from __future__ import annotations

import tkinter as tk
from pathlib import Path
from tkinter import filedialog, messagebox

from ccma import __version__
from ccma.config import load_config
from ccma.domain.dates import setup_system_locale
from ccma.storage.repository import MemberRepository
from ccma.ui.main_window import MainWindow
from ccma.ui.monitors import (
    centered_geometry,
    ensure_visible_geometry,
    monitor_for_geometry,
    preferred_monitor,
)
from ccma.ui.splash import SplashScreen, StartupResult
from ccma.ui.theme import load_theme
from ccma.ui.window_state import is_maximized, maximize


class CCMAApp(tk.Tk):
    def __init__(self):
        super().__init__()
        setup_system_locale()
        self.config_obj = load_config()
        self.title(f"CCMA · v{__version__}")
        self.minsize(1050, 650)
        load_theme(self, self.config_obj.theme_mode)
        self.startup_monitor = preferred_monitor(self, self.config_obj.monitor_bounds)
        initial_geometry = self.config_obj.window_geometry or centered_geometry(
            1500, 860, self.startup_monitor
        )
        self.geometry(ensure_visible_geometry(initial_geometry, self.startup_monitor))
        self._last_normal_geometry = self.geometry()
        self._geometry_capture_job: str | None = None
        self.bind("<Configure>", self._remember_window_geometry)
        self.protocol("WM_DELETE_WINDOW", self.close)
        self.withdraw()
        self.after_idle(self._start)

    def _start(self) -> None:
        store_path = self._resolve_store()
        if not store_path:
            self.destroy()
            return
        repository = MemberRepository(store_path)
        try:
            SplashScreen(
                self,
                repository,
                self._startup_complete,
                self._startup_failed,
                run_housekeeper=self.config_obj.run_housekeeper_on_startup,
                monitor=self.startup_monitor,
                housekeeper_settings=self.config_obj.housekeeper_settings(),
                minimum_display_seconds=self.config_obj.splash_minimum_seconds,
            )
        except Exception as exc:
            self._startup_failed(exc)

    def _resolve_store(self) -> Path | None:
        configured = self.config_obj.store_path.strip()
        if configured:
            return Path(configured).expanduser()
        selected = filedialog.askdirectory(
            parent=self,
            title="Zentrales CCMA-Mitgliederverzeichnis auswählen oder anlegen",
            initialdir=str(Path.home()),
            mustexist=False,
        )
        if not selected:
            return None
        self.config_obj.store_path = selected
        self.config_obj.save()
        return Path(selected)

    def _startup_complete(self, result: StartupResult) -> None:
        self.deiconify()
        main = MainWindow(
            self,
            result.repository,
            self.config_obj,
            result.findings,
            result.validation_errors,
        )
        main.pack(fill="both", expand=True)
        if self.config_obj.window_state in {"maximized", "zoomed"}:
            self.after_idle(lambda: maximize(self))

    def _startup_failed(self, error: Exception) -> None:
        self.deiconify()
        messagebox.showerror("CCMA konnte nicht gestartet werden", str(error), parent=self)
        self.destroy()

    def _remember_window_geometry(self, _event: tk.Event | None = None) -> None:
        if self._geometry_capture_job:
            try:
                self.after_cancel(self._geometry_capture_job)
            except tk.TclError:
                pass
        self._geometry_capture_job = self.after(150, self._capture_normal_geometry)

    def _capture_normal_geometry(self) -> None:
        self._geometry_capture_job = None
        try:
            if self.state() == "normal" and not is_maximized(self) and self.winfo_viewable():
                self._last_normal_geometry = self.winfo_geometry()
        except tk.TclError:
            return

    def close(self) -> None:
        try:
            maximized = is_maximized(self)
            current_geometry = self.winfo_geometry()
            if not maximized:
                self._last_normal_geometry = current_geometry
            self.config_obj.window_geometry = self._last_normal_geometry
            self.config_obj.window_state = "maximized" if maximized else "normal"
            monitor = monitor_for_geometry(self, current_geometry)
            self.config_obj.monitor_bounds = monitor.as_tuple()
            self.config_obj.save()
        except (OSError, tk.TclError):
            pass
        self.destroy()


def main() -> None:
    app = CCMAApp()
    app.mainloop()


if __name__ == "__main__":
    main()
