"""
Clock-out Time Calculator
퇴근시간 계산 프로그램 - 메인 실행 파일
"""
import sys
import os

# PyQt5 임포트
from PyQt5.QtWidgets import QApplication, QMessageBox
from PyQt5.QtGui import QFont
from PyQt5.QtCore import QLockFile, QDir
from PyQt5.QtNetwork import QLocalServer, QLocalSocket

# 프로젝트 루트를 경로에 추가
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))

from ui.main_window import MainWindow
from core.database import Database


def _ensure_updater_extracted():
    """main.exe에 내장된 updater.exe를 같은 폴더에 추출.

    main.exe만 단독 배포해도 자동 업데이트가 동작하도록, 시작 시 한 번
    내장본을 같은 폴더로 복사. 이미 같은 사이즈로 있으면 건너뜀.
    개발 환경(.py 실행)에서는 별도 빌드된 updater.exe를 사용해야 하므로 no-op.
    """
    if not getattr(sys, 'frozen', False):
        return

    import shutil
    from pathlib import Path

    main_dir = Path(sys.executable).parent
    target = main_dir / 'updater.exe'
    bundled = Path(getattr(sys, '_MEIPASS', '')) / 'updater.exe'

    if not bundled.exists():
        return  # 빌드 시 포함 안 됨

    needs_extract = (not target.exists()
                     or target.stat().st_size != bundled.stat().st_size)
    if needs_extract:
        try:
            shutil.copy2(str(bundled), str(target))
        except OSError:
            pass  # 권한 부족 등은 silent — 자동 업데이트만 안 됨


def check_requirements():
    """필수 요구사항 확인"""
    try:
        import win32evtlog
        return True
    except ImportError:
        return False


def main():
    """메인 함수"""
    # PyInstaller frozen exe에 내장된 updater.exe를 옆 폴더에 자동 추출
    _ensure_updater_extracted()

    app = QApplication(sys.argv)

    # 애플리케이션 정보
    app.setApplicationName("Clock-out Time Calculator")
    app.setOrganizationName("DevUtil")
    app.setApplicationVersion("1.0.0")

    # 중복 실행 방지 - 로컬 서버로 체크
    server_name = "ClockOutCalculatorInstance"

    # 이미 실행 중인지 확인
    socket = QLocalSocket()
    socket.connectToServer(server_name)

    if socket.waitForConnected(500):
        # 이미 실행 중 - 기존 인스턴스에 "show" 신호 전송
        socket.write(b"show")
        socket.flush()
        socket.waitForBytesWritten(1000)
        socket.disconnectFromServer()
        return 0

    # 새로운 인스턴스 - 서버 시작
    server = QLocalServer()
    # 기존 서버가 남아있을 수 있으므로 제거
    QLocalServer.removeServer(server_name)

    if not server.listen(server_name):
        QMessageBox.warning(
            None,
            "서버 오류",
            "프로그램 인스턴스 서버를 시작할 수 없습니다."
        )
        return 1

    # 폰트 설정 — 번들 NanumSquare 등록 + 전역 적용 (미설치 시 Malgun Gothic 폴백)
    from utils.font_loader import apply_app_font
    apply_app_font(app, 9)

    # 필수 패키지 확인
    if not check_requirements():
        QMessageBox.critical(
            None,
            "요구사항 오류",
            "필수 패키지가 설치되지 않았습니다.\n\n"
            "다음 명령어를 실행하세요:\n"
            "pip install -r requirements.txt"
        )
        return 1

    # 데이터베이스 초기화 — db_path_override 설정 시 그 경로 사용 (클라우드 폴더 등)
    # 부트스트랩: 기본 DB로 한 번 열어 override 키 확인
    from core.settings_keys import DB_PATH_OVERRIDE
    bootstrap = Database()
    override_path = bootstrap.get_setting(DB_PATH_OVERRIDE, '') or ''
    if override_path and os.path.exists(os.path.dirname(override_path) or '.'):
        db = Database(override_path)
    else:
        db = bootstrap

    # 1일 1회 자동 백업 (조용히 실패 — 백업 실패가 앱 실행을 막으면 안 됨)
    try:
        from utils.backup import backup_db_if_needed
        backup_db_if_needed(db)
    except Exception as e:
        from utils.debug_log import dlog
        dlog(f"backup failed: {e}")

    # 전역 예외 후킹 (crash report)
    try:
        from utils.crash_handler import install_global_handler
        from core.version import __version__
        install_global_handler(db, app_version=__version__)
    except Exception as e:
        from utils.debug_log import dlog
        dlog(f"crash handler install failed: {e}")

    # 첫 실행 온보딩 (강제) — ONBOARDING_COMPLETED=true 가 아니면 표시
    try:
        from ui.onboarding_view import maybe_show_onboarding
        maybe_show_onboarding(db)
    except Exception as e:
        from utils.debug_log import dlog
        dlog(f"onboarding skipped: {e}")

    # 메인 윈도우 생성 및 표시 (위에서 만든 db 재사용 — 이중 부트스트랩 방지)
    try:
        window = MainWindow(db=db)

        # 서버 연결 처리 - 다른 인스턴스에서 show 신호를 받으면 창을 보여줌
        def on_new_connection():
            client_socket = server.nextPendingConnection()
            if client_socket:
                client_socket.waitForReadyRead(1000)
                data = client_socket.readAll().data()
                if data == b"show":
                    # 창 표시
                    window.show()
                    window.raise_()
                    window.activateWindow()
                client_socket.disconnectFromServer()

        server.newConnection.connect(on_new_connection)

        window.show()

        result = app.exec_()

        # 서버 종료
        server.close()

        return result

    except Exception as e:
        QMessageBox.critical(
            None,
            "오류",
            f"프로그램 실행 중 오류가 발생했습니다:\n\n{str(e)}"
        )
        server.close()
        return 1


if __name__ == "__main__":
    sys.exit(main())
