# Copyright (c) 2026 동일비전(Dongil Vision Korea). All Rights Reserved.
"""
╔══════════════════════════════════════════════════════════════════════════════╗
║  ALASKA v2.0 - Qt Application Runner                                         ║
║  PySide6/PyQt 애플리케이션 원라인 시작                                       ║
╠══════════════════════════════════════════════════════════════════════════════╣
║  Version : 2.0.1                                                             ║
║  Date    : 2026-02-10                                                        ║
╠══════════════════════════════════════════════════════════════════════════════╣
║  Summary:                                                                    ║
║    Qt + Alaska 통합 앱 러너                                                  ║
║    - 7줄 코드를 1줄로 축소                                                   ║
║    - 자동 초기화/정리                                                        ║
║    - 어디서든 client 접근 가능                                               ║
╚══════════════════════════════════════════════════════════════════════════════╝

Usage:
    from py_alaska.qt import AlaskaApp

    if __name__ == "__main__":
        AlaskaApp.run("config.json", MainWindow)
"""

from __future__ import annotations
import sys
import atexit
from typing import Type, Optional, TYPE_CHECKING

if TYPE_CHECKING:
    from .. import TaskManager, RmiClient


class AlaskaApp:
    """PySide6/PyQt + Alaska 통합 앱 러너

    Qt 애플리케이션과 Alaska TaskManager를 통합하여
    초기화, 실행, 정리를 자동으로 처리합니다.

    Example:
        # Before (7줄)
        app = QApplication(sys.argv)
        gconfig.load("config.json")
        manager = TaskManager(gconfig)
        manager.start_all()
        window = MainWindow()
        window.show()
        try:
            sys.exit(app.exec())
        finally:
            manager.stop_all()

        # After (1줄)
        AlaskaApp.run("config.json", MainWindow)
    """

    manager: Optional['TaskManager'] = None
    _app = None
    _window = None
    _cleanup_registered = False

    @classmethod
    def run(cls, config_path: str, main_window_class: Type = None, *, main_task: str = None, **window_kwargs):
        """Qt 앱 시작 (자동 정리 포함)

        Args:
            config_path: 설정 파일 경로 (JSON)
            main_window_class: QWidget/QMainWindow 서브클래스 (main_task와 함께 사용 시 생략 가능)
            main_task: 메인 윈도우로 사용할 task ID (QWidget 기반 task)
            **window_kwargs: 메인 윈도우 생성자에 전달할 키워드 인수

        Examples:
            # 기존 방식 - MainWindow 클래스 사용
            AlaskaApp.run("config.json", MainWindow)

            # 새 방식 - task를 직접 메인 윈도우로 사용
            AlaskaApp.run("config.json", main_task="viewer")
        """
        # Qt 앱 생성
        try:
            from PySide6.QtWidgets import QApplication, QMainWindow
        except ImportError:
            try:
                from PyQt6.QtWidgets import QApplication, QMainWindow
            except ImportError:
                from PyQt5.QtWidgets import QApplication, QMainWindow

        cls._app = QApplication(sys.argv)

        # @ui_thread 데코레이터 초기화 (UI 스레드에서)
        from .decorators import _ensure_ui_invoker_initialized
        _ensure_ui_invoker_initialized()

        # Alaska 초기화
        from .. import gconfig
        from .. import TaskManager

        gconfig.load(config_path)
        cls.manager = TaskManager(gconfig)
        cls.manager.start_all()

        # 종료 시 자동 정리
        if not cls._cleanup_registered:
            atexit.register(cls._cleanup)
            cls._cleanup_registered = True
        cls._app.aboutToQuit.connect(cls._cleanup)

        # 메인 윈도우 생성
        if main_task:
            # task를 메인 윈도우로 사용
            task_widget = cls.get_task(main_task)
            if task_widget is None:
                raise ValueError(f"Task '{main_task}' not found or not a QWidget")
            # QMainWindow로 래핑
            cls._window = QMainWindow()
            cls._window.setCentralWidget(task_widget)
            title = window_kwargs.get('title', main_task)
            cls._window.setWindowTitle(title)
            cls._window.resize(800, 600)
        elif main_window_class:
            cls._window = main_window_class(**window_kwargs)
        else:
            raise ValueError("Either main_window_class or main_task must be provided")

        cls._window.show()

        sys.exit(cls._app.exec())

    @classmethod
    def _cleanup(cls):
        """리소스 정리"""
        if cls.manager:
            try:
                cls.manager.stop_all()
            except Exception:
                pass
            cls.manager = None

    @classmethod
    def get_client(cls, task_id: str) -> 'RmiClient':
        """어디서든 RmiClient 접근

        Args:
            task_id: Task ID

        Returns:
            RmiClient: RMI 클라이언트

        Raises:
            RuntimeError: AlaskaApp.run() 호출 전 사용 시
            ValueError: 존재하지 않는 task_id 요청 시
        """
        if cls.manager is None:
            raise RuntimeError("AlaskaApp.run() must be called first")
        return cls.manager.get_client(task_id)

    @classmethod
    def get_task(cls, task_id: str):
        """어디서든 Task 인스턴스 접근 (thread 모드 전용)

        Args:
            task_id: Task ID

        Returns:
            Task 인스턴스 (thread 모드) 또는 None

        Raises:
            RuntimeError: AlaskaApp.run() 호출 전 사용 시
        """
        if cls.manager is None:
            raise RuntimeError("AlaskaApp.run() must be called first")
        return cls.manager.get_task(task_id)

    @classmethod
    def get_signal_client(cls, client_id: str = "_external"):
        """어디서든 SignalClient 접근

        Args:
            client_id: 클라이언트 ID (기본값: "_external")

        Returns:
            SignalClient: Signal 수신 클라이언트

        Raises:
            RuntimeError: AlaskaApp.run() 호출 전 사용 시
        """
        if cls.manager is None:
            raise RuntimeError("AlaskaApp.run() must be called first")
        return cls.manager.get_signal_client(client_id)

    @classmethod
    def get_smblock(cls, name: str):
        """어디서든 SmBlock 접근

        Args:
            name: SmBlock 이름

        Returns:
            SmBlock: 공유 메모리 블록

        Raises:
            RuntimeError: AlaskaApp.run() 호출 전 사용 시
            ValueError: 존재하지 않는 SmBlock 이름 요청 시
        """
        if cls.manager is None:
            raise RuntimeError("AlaskaApp.run() must be called first")
        return cls.manager.get_smblock(name)
