"""Backups-Seite — Time-Machine-artige Snapshots über Timeshift.

ALLE Timeshift-Aufrufe (auch --list) brauchen root → laufen privilegiert via
pkexec durch den taninux-helper. Restore ist sehr destruktiv (stellt das System
wieder her, ggf. Reboot) → mit Bestätigungsdialog.
"""
from __future__ import annotations

import gi

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

from taninux.core import backup
from taninux.gui import confirm
from taninux.gui.console import LogConsole, log_expander
from taninux.gui.process import ProcessRunner


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

    if not backup.available():
        _build_install(page)
        return page

    # Gemeinsame Konsole + Action-Runner (create/delete/restore). Nach jeder
    # Aktion wird die Snapshot-Liste neu geladen.
    console = LogConsole()
    action_runner = ProcessRunner()
    action_runner.connect("line", lambda _r, line: console.append_line(line))

    # Snapshots-Gruppe (wird in-place neu befüllt nach jeder Aktion).
    g_snaps = Adw.PreferencesGroup(
        title="Snapshots",
        description="Restore reverts the system and may require a reboot.",
    )
    rows: list[Gtk.Widget] = []

    def reload_snapshots() -> None:
        _load_snapshots(g_snaps, rows, console, action_runner, reload_snapshots)

    def on_action_done(_r: ProcessRunner, code: int) -> None:
        console.append_line("")
        console.append_line("✔ done (exit 0)" if code == 0 else f"✘ exit {code}")
        reload_snapshots()

    action_runner.connect("done", on_action_done)

    # -- Create-Gruppe ------------------------------------------------
    page.add(_create_group(console, action_runner))

    # -- Snapshots-Gruppe (initial laden) -----------------------------
    page.add(g_snaps)
    reload_snapshots()

    # -- Log-Gruppe ---------------------------------------------------
    page.add(log_expander(console))

    return page


def _build_install(page: Adw.PreferencesPage) -> None:
    """Fallback-UI, wenn timeshift nicht installiert ist."""
    from taninux.gui.console import RunnerCard

    group = Adw.PreferencesGroup(
        title="Timeshift not installed",
        description="Backups use Timeshift for system snapshots.",
    )
    card = RunnerCard(
        "Install timeshift",
        ["pacman", "-S", "--needed", "--noconfirm", "timeshift"],
        privileged=True,
    )
    box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=12)
    box.set_margin_top(6)
    box.append(card)
    group.add(box)
    page.add(group)


def _create_group(console: LogConsole, runner: ProcessRunner) -> Adw.PreferencesGroup:
    """EntryRow für Kommentar + Button zum Erstellen eines Snapshots."""
    group = Adw.PreferencesGroup(title="Create snapshot")

    entry = Adw.EntryRow(title="Comment")
    group.add(entry)

    button = Gtk.Button(label="Create snapshot")
    button.add_css_class("suggested-action")
    button.add_css_class("pill")
    button.set_halign(Gtk.Align.START)

    def on_click(_b: Gtk.Button) -> None:
        if runner.running:
            return
        console.clear()
        runner.run(backup.create_argv(entry.get_text()), privileged=True)

    button.connect("clicked", on_click)

    box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=12)
    box.set_margin_top(6)
    box.append(button)
    group.add(box)
    return group


def _load_snapshots(
    group: Adw.PreferencesGroup,
    rows: list[Gtk.Widget],
    console: LogConsole,
    action_runner: ProcessRunner,
    reload: "callable",
) -> None:
    """Lädt `timeshift --list` privilegiert über einen EIGENEN Runner, sammelt
    die Ausgabe in einem Buffer und baut bei `done` die Zeilen neu auf."""
    # bestehende Zeilen entfernen
    for row in rows:
        group.remove(row)
    rows.clear()

    spinner_row = Adw.ActionRow(title="Loading snapshots…")
    spinner = Gtk.Spinner()
    spinner.start()
    spinner_row.add_prefix(spinner)
    group.add(spinner_row)
    rows.append(spinner_row)

    buffer: list[str] = []
    list_runner = ProcessRunner()
    list_runner.connect("line", lambda _r, line: buffer.append(line))

    def on_done(_r: ProcessRunner, code: int) -> None:
        spinner.stop()
        group.remove(spinner_row)
        rows.remove(spinner_row)

        if code != 0:
            err_row = Adw.ActionRow(title="Could not load snapshots")
            group.add(err_row)
            rows.append(err_row)
            return

        snapshots = backup.parse_list("\n".join(buffer))
        if not snapshots:
            empty_row = Adw.ActionRow(title="No snapshots yet")
            group.add(empty_row)
            rows.append(empty_row)
            return

        for snap in snapshots:
            subtitle = " ".join(p for p in (snap.tags, snap.description) if p)
            row = Adw.ActionRow(title=snap.name, subtitle=subtitle or None)
            row.add_suffix(_restore_button(snap.name, console, action_runner, reload))
            row.add_suffix(_delete_button(snap.name, console, action_runner, reload))
            group.add(row)
            rows.append(row)

    list_runner.connect("done", on_done)
    list_runner.run(backup.list_argv(), privileged=True)


def _restore_button(
    name: str,
    console: LogConsole,
    runner: ProcessRunner,
    reload: "callable",
) -> Gtk.Button:
    button = Gtk.Button(label="Restore")
    button.add_css_class("destructive-action")
    button.set_valign(Gtk.Align.CENTER)

    def do_run() -> None:
        if runner.running:
            return
        console.clear()
        runner.run(backup.restore_argv(name), privileged=True)

    def on_click(_b: Gtk.Button) -> None:
        confirm.confirm(
            button,
            "Restore this snapshot?",
            f"This reverts the entire system to {name}. All changes since then "
            "will be lost and a reboot may be required. Runs as root via pkexec.",
            do_run,
        )

    button.connect("clicked", on_click)
    return button


def _delete_button(
    name: str,
    console: LogConsole,
    runner: ProcessRunner,
    reload: "callable",
) -> Gtk.Button:
    button = Gtk.Button(label="Delete")
    button.add_css_class("destructive-action")
    button.set_valign(Gtk.Align.CENTER)

    def do_run() -> None:
        if runner.running:
            return
        console.clear()
        runner.run(backup.delete_argv(name), privileged=True)

    def on_click(_b: Gtk.Button) -> None:
        confirm.confirm(
            button,
            "Delete this snapshot?",
            f"Snapshot {name} will be permanently removed. Runs as root via pkexec.",
            do_run,
        )

    button.connect("clicked", on_click)
    return button
