from collections.abc import Awaitable
from pathlib import Path
from typing import Any, Self, cast

from gi.repository import Adw, Gio, GLib, GObject, Gtk

from morphosis import APP_ID, PREFIX, tasks
from morphosis.document import Document, Format


@Gtk.Template(resource_path=f"{PREFIX}/window.ui")
class Window(Adw.ApplicationWindow):
    """The main application window."""

    __gtype_name__ = "Window"

    document: Document = Gtk.Template.Child()

    toast_overlay: Adw.ToastOverlay = Gtk.Template.Child()
    navigation_view: Adw.NavigationView = Gtk.Template.Child()

    format_row: Adw.ComboRow = Gtk.Template.Child()
    font_style_group: Adw.ToggleGroup = Gtk.Template.Child()  # type: ignore[name-defined]

    app_icon = GObject.Property(type=str, default=APP_ID)
    selected_format = GObject.Property(type=Format)
    selected_font_style = GObject.Property(type=str)

    def __init__(self, **kwargs: Any) -> None:
        super().__init__(**kwargs)

        # https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/3933
        schema = Gio.Settings.new(APP_ID)
        schema.bind(
            "export-format", self.format_row, "selected", Gio.SettingsBindFlags.DEFAULT
        )
        schema.bind(
            "font-style", self.font_style_group, "active", Gio.SettingsBindFlags.DEFAULT
        )

    @tasks.callback
    async def _open_document(self, select_dialog: Gtk.FileDialog) -> None:
        try:
            file = await cast(Awaitable[Gio.File], select_dialog.open(self))
        except GLib.Error:
            return

        await self.document.set_from_file(file)
        self.navigation_view.push_by_tag("document")

    @tasks.callback
    async def _save_document(self, save_dialog: Gtk.FileDialog) -> None:
        try:
            output_file = await cast(Awaitable[Gio.File], save_dialog.save(self))
        except GLib.Error:
            return

        if not output_file.get_path():
            return

        self.navigation_view.push_by_tag("converting")
        await self.document.convert(
            output_file=output_file,
            document_format=self.selected_format,
            font_style=self.selected_font_style,
        )

    @Gtk.Template.Callback()
    def _on_conversion_finished(self, toast: Adw.Toast) -> None:
        self.navigation_view.pop_to_tag("start")
        self.toast_overlay.dismiss_all()  # type: ignore[attr-defined]
        self.toast_overlay.add_toast(toast)

    @Gtk.Template.Callback()
    def _launch_launcher(self, launcher: Gtk.FileLauncher | Gtk.UriLauncher) -> None:
        launcher.launch()

    @Gtk.Template.Callback()
    def _output_file_name(self, _win: Self, doc_name: str, doc_format: Format) -> str:
        return f"{Path(doc_name).stem}.{doc_format.extension}"
