"""Printers — CUPS-Druckerverwaltung (libadwaita).

Read kommt aus core.printers (lpstat). Schreib-Aktionen (Default setzen,
enable/disable, entfernen) liefern dort nur argv und laufen hier über einen
gemeinsamen ProcessRunner — privilegiert via Helper (lpadmin/cupsenable/
cupsdisable) bzw. unprivilegiert (cancel -a für die Queue).

Drucker HINZUFÜGEN (Treiberauswahl) ist NICHT enthalten — dafür ein
dediziertes System-Tool nutzen.
"""
from __future__ import annotations

import gi

gi.require_version("Gtk", "4.0")
gi.require_version("Adw", "1")
from gi.repository import Adw, Gtk  # noqa: E402

from taninux.core import printers
from taninux.gui import confirm as confirm_mod
from taninux.gui.console import LogConsole, RunnerCard, log_expander
from taninux.gui.process import ProcessRunner


def build() -> Gtk.Widget:
    page = Adw.PreferencesPage()

    if not printers.available():
        page.add(_unavailable_group())
        return page

    # Gemeinsame Konsole + Runner für alle Aktionen dieser Seite.
    console = LogConsole()
    runner = ProcessRunner()
    runner.connect("line", lambda _r, line: console.append_line(line))

    # Druckergruppe wird nach jeder Aktion neu befüllt (live).
    printers_group = Adw.PreferencesGroup(
        title="Printers",
        description="Adding a printer (driver selection) isn't here — use a "
        "dedicated tool for that.",
    )
    queue_group = Adw.PreferencesGroup(
        title="Print queue",
        description="Pending jobs across all printers.",
    )

    def run(argv: list[str], *, privileged: bool) -> None:
        console.clear()
        runner.run(argv, privileged=privileged)

    def refresh() -> None:
        _fill_printers(printers_group, run)
        _fill_queue(queue_group, run)

    runner.connect("done", lambda _r, code: _on_done(console, code, refresh))

    refresh()
    page.add(printers_group)
    page.add(queue_group)
    page.add(log_expander(console, title="Output"))
    return page


def _on_done(console: LogConsole, code: int, refresh) -> None:
    console.append_line("")
    console.append_line(
        f"✔ done (exit {code})" if code == 0 else f"✘ exit {code}"
    )
    refresh()


def _clear_group(group: Adw.PreferencesGroup) -> None:
    """Entfernt alle bisher per _track() hinzugefügten Rows der Gruppe."""
    rows = getattr(group, "_tani_rows", None)
    if not rows:
        return
    for row in list(rows):
        group.remove(row)
    rows.clear()


def _track(group: Adw.PreferencesGroup, row: Gtk.Widget) -> None:
    rows = getattr(group, "_tani_rows", None)
    if rows is None:
        rows = []
        group._tani_rows = rows
    group.add(row)
    rows.append(row)


def _fill_printers(group: Adw.PreferencesGroup, run) -> None:
    _clear_group(group)
    plist = printers.printers()
    if not plist:
        _track(group, Adw.ActionRow(
            title="No printers configured",
            subtitle="Add one with a system printer tool.",
        ))
        return

    for p in plist:
        subtitle = p.state
        if p.is_default:
            subtitle += " · default"
        if p.info:
            subtitle += f" · {p.info}"
        row = Adw.ActionRow(title=p.name, subtitle=subtitle)

        if not p.is_default:
            row.add_suffix(_btn(
                "Set default",
                lambda _b, n=p.name: run(printers.set_default_argv(n),
                                         privileged=True),
            ))

        if p.enabled:
            row.add_suffix(_btn(
                "Disable",
                lambda _b, n=p.name: run(printers.disable_argv(n),
                                         privileged=True),
            ))
        else:
            row.add_suffix(_btn(
                "Enable",
                lambda _b, n=p.name: run(printers.enable_argv(n),
                                         privileged=True),
                suggested=True,
            ))

        remove = _btn(
            "Remove",
            lambda _b, n=p.name: confirm_mod.confirm(
                _b, "Remove printer?",
                f"Permanently remove the printer “{n}” from CUPS.",
                lambda n=n: run(printers.remove_argv(n), privileged=True),
            ),
            destructive=True,
        )
        row.add_suffix(remove)
        _track(group, row)


def _fill_queue(group: Adw.PreferencesGroup, run) -> None:
    _clear_group(group)
    jobs = printers.queue()
    if not jobs:
        _track(group, Adw.ActionRow(
            title="Queue empty", subtitle="No pending print jobs."
        ))
        return

    for job in jobs:
        _track(group, Adw.ActionRow(title=job))

    clear_row = Adw.ActionRow(title="Clear queue",
                              subtitle="Cancel all pending jobs.")
    clear_row.add_suffix(_btn(
        "Clear queue",
        lambda _b: run(printers.cancel_all_argv(), privileged=False),
        destructive=True,
    ))
    _track(group, clear_row)


def _btn(label: str, on_click, *, suggested: bool = False,
         destructive: bool = False) -> Gtk.Button:
    btn = Gtk.Button(label=label)
    btn.set_valign(Gtk.Align.CENTER)
    if suggested:
        btn.add_css_class("suggested-action")
    if destructive:
        btn.add_css_class("destructive-action")
    btn.connect("clicked", on_click)
    return btn


def _unavailable_group() -> Adw.PreferencesGroup:
    group = Adw.PreferencesGroup(
        title="Printing",
        description="CUPS is not installed. Printer management is unavailable.",
    )
    group.add(Adw.ActionRow(
        title="CUPS not available",
        subtitle="Install cups to manage printers.",
    ))
    box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=12)
    box.set_margin_top(6)
    box.append(RunnerCard(
        "Install CUPS",
        ["pacman", "-S", "--needed", "--noconfirm", "cups"],
        privileged=True,
    ))
    group.add(box)
    return group
