# -*- coding: utf-8 -*-
# dispatch/window.py

"""Главное окно независимого приложения Dispatch.

Назначение модуля:
    Минимальный графический каркас, выполняющий единственную обязанность —
    разместить корневой виджет модуля `hub.ticket.TicketPlugin` в окне
    верхнего уровня. Управление содержимым модуля Ticket остаётся
    полностью внутри самого модуля.

Архитектурные ограничения:
    - Окно не содержит предметной логики и не обращается к внутренним
      полям модуля Ticket: взаимодействие выполняется только через его
      публичный API (`TicketPlugin`).
    - Стилевое оформление берётся из внешнего реестра `APP_STYLES`;
      локальные QSS-литералы запрещены (правило 6.3).
    - Отказ модуля Ticket изолирован: при ошибке инициализации окно
      продолжает существовать, ошибка фиксируется в журнале.
"""

from PySide6.QtCore import Qt, QEvent, QTimer
from PySide6.QtWidgets import QMainWindow

from error_logger import log_exception
from gui.containers.percent_sized_widget import PercentSizedWidget
from gui.styles import APP_STYLES
from gui.theme_bus import theme_bus as _default_theme_bus
from application import TaskApplicationService
from ticket_plugin import TicketPlugin

from null_hardware_gateway import NullHardwareGateway


class DispatchMainWindow(QMainWindow):
    """Главное окно приложения Dispatch с единственным модулем Ticket."""

    def __init__(self, theme_bus=None):
        super().__init__()
        self._theme_bus = theme_bus or _default_theme_bus
        self._ticket_plugin: TicketPlugin | None = None
        self._setup_window()
        self._setup_ui()
        self._connect_signals()

    def _setup_window(self) -> None:
        """Настроить параметры окна верхнего уровня."""
        self.setWindowTitle("Dispatch — Ticket")
        self.setMinimumSize(1200, 800)
        self.setStyleSheet(APP_STYLES.get("MAIN_WINDOW_DARK", ""))
        self.showMaximized()

    def _setup_ui(self) -> None:
        """Разместить корневой виджет модуля Ticket в качестве центрального.

        В составе Dispatch модуль работы с COM-портом отключён: приложение
        собирает application-сервис Ticket с null-шлюзом и передаёт его
        в `TicketPlugin`, который владеет жизненным циклом сервиса.
        """
        try:
            null_gateway = NullHardwareGateway(parent=self)
            application_service = TaskApplicationService(
                hardware_gateway=null_gateway,
                parent=self,
            )
            self._ticket_plugin = TicketPlugin(application_service=application_service)
            self.setCentralWidget(self._ticket_plugin)
        except Exception as exc:
            log_exception(__name__, "DispatchMainWindow._setup_ui", exc)
            raise

    def _connect_signals(self) -> None:
        """Подключить шину тем для согласованного оформления окна."""
        self._theme_bus.theme_changed.connect(self._on_theme_changed)

    def _on_theme_changed(self, theme: str) -> None:
        """Применить тему окна по ключам из внешнего реестра стилей."""
        is_light = str(theme or "").strip().lower() == "light"
        key = "MAIN_WINDOW_LIGHT" if is_light else "MAIN_WINDOW_DARK"
        self.setStyleSheet(APP_STYLES.get(key, ""))

    def changeEvent(self, event):
        """Пересчитать процентную разметку при восстановлении окна."""
        if event.type() == QEvent.Type.WindowStateChange:
            if not (self.windowState() & Qt.WindowState.WindowMinimized):
                QTimer.singleShot(0, self._refresh_percent_layout)
        return super().changeEvent(event)

    def _refresh_percent_layout(self) -> None:
        """Принудительно пересчитать процентные размеры дочерних виджетов."""
        for widget in self.findChildren(PercentSizedWidget):
            try:
                widget.schedule_percent_update()
            except Exception as exc:
                log_exception(__name__, "DispatchMainWindow._refresh_percent_layout", exc)

    def closeEvent(self, event) -> None:
        """Гарантировать корректную остановку модуля Ticket при закрытии."""
        if self._ticket_plugin is not None:
            try:
                self._ticket_plugin.cleanup()
            except Exception as exc:
                log_exception(__name__, "DispatchMainWindow.closeEvent", exc)
        super().closeEvent(event)
