import logging
import sys
from importlib.metadata import PackageNotFoundError, version
from pathlib import Path

from PySide6.QtQml import QQmlApplicationEngine
from PySide6.QtQuickControls2 import QQuickStyle
from PySide6.QtWidgets import QApplication

from pygui.backend.controllers.batch_export_controller import BatchExportController
from pygui.backend.controllers.device_controller import DeviceController
from pygui.backend.controllers.session_controller import SessionController
from pygui.backend.data.constants import default_data_dir
from pygui.backend.data.file_browser import FileBrowser
from pygui.backend.data.local_settings import LocalSettings
from pygui.backend.data.local_settings_model import LocalSettingsModel
from pygui.backend.license.license_model import LicenseModel

# Importing wafer_map_item + trend_chart_item registers @QmlElement types (QML: import ISC.Wafer).
from pygui.backend.visualization import (
    graph_quick_item as graph_quick_item,  # noqa: F401
)
from pygui.backend.visualization import (
    trend_chart_item as trend_chart_item,  # noqa: F401
)
from pygui.backend.visualization import (
    wafer_map_item as wafer_map_item,  # noqa: F401
)


# ===== Application Entry Point =====
def main() -> int:
    logging.basicConfig(
        level=logging.INFO,
        format="%(asctime)s [%(levelname)s] %(name)s: %(message)s"
    )
    # ===== UI Style Setup =====
    # Use a non-native controls style so our custom QML button backgrounds are supported.
    QQuickStyle.setStyle("Basic")

    # ===== Qt Bootstrap =====
    # Minimal Qt bootstrap: load the ISC QML module and exit if it fails.
    app = QApplication(sys.argv)
    engine = QQmlApplicationEngine()

    # ===== Shared Settings =====
    # One LocalSettings instance, one disk read. LocalSettingsModel and
    # DeviceController both hold this same object, so a save from the
    # Settings tab is visible to the device layer immediately — no reload,
    # no second copy to go stale.
    data_dir = str(default_data_dir())
    # settings.json only exists once something has saved — absence means this
    # machine has never run the app before (first-launch wizard trigger).
    is_first_launch = not (Path(data_dir) / "settings.json").exists()
    raw_settings = LocalSettings.read_settings(data_dir)

    settings_model = LocalSettingsModel(raw_settings, data_dir)
    select_file_dialog_model = FileBrowser()
    settings_model.loadSettings()
    engine.rootContext().setContextProperty("settingsModel", settings_model)
    engine.rootContext().setContextProperty("file_browser", select_file_dialog_model)
    engine.rootContext().setContextProperty("isFirstLaunch", is_first_launch)

    # App version from package metadata so the About dialog can't drift
    # from pyproject.toml.
    try:
        app_version = version("pygui")
    except PackageNotFoundError:
        app_version = "dev"
    engine.rootContext().setContextProperty("appVersion", app_version)

    # ===== License Model (About dialog grid, replay trial) =====
    license_model = LicenseModel(data_dir)
    engine.rootContext().setContextProperty("licenseModel", license_model)

    # ===== Device Controller (serial comm) =====
    device_controller = DeviceController(
        raw_settings, data_dir, license_lookup=license_model.levelForWafer
    )
    engine.rootContext().setContextProperty("deviceController", device_controller)

    # Source panel browses the same folder recordings/reads are saved to.
    select_file_dialog_model.setCurrentDirectory(str(device_controller.saveDataDir))

    # ===== Session Controller (live/review wafer dashboard) =====
    stream_controller = SessionController()
    engine.rootContext().setContextProperty("streamController", stream_controller)

    # ===== Batch Export Controller (SourcePanel batch PNG export) =====
    batch_export_controller = BatchExportController()
    engine.rootContext().setContextProperty("batchExportController", batch_export_controller)

    # ===== QML Startup =====
    # The "ISC" QML module lives alongside this file (src/pygui/ISC), so the
    # package directory is the import path the engine searches for qmldir.
    engine.addImportPath(Path(__file__).parent)
    engine.loadFromModule("ISC", "Main")

    # ===== Exit Handling =====
    if not engine.rootObjects():
        return -1

    return app.exec()


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