"""Power — Akku-Info (falls vorhanden) + Idle-Timeouts (Bildschirm aus / Suspend).

Akku/AC sind reiner Read aus core.power. Die Idle-Timeouts laufen niri-only
über swayidle (eigener taninux-swayidle.service, DPMS via niri-Action). Der
Service läuft als User-Service (kein root); die niri-Config wird nicht
angefasst. Fehlt swayidle, gibt's einen Install-Block (pacman via Helper).
"""
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 power
from taninux.gui.console import RunnerCard
from taninux.gui.process import ProcessRunner


def build() -> Gtk.Widget:
    page = Adw.PreferencesPage()
    page.add(_power_source_group())
    if power.brightness_available():
        page.add(_brightness_group())
    page.add(_energy_mode_group())
    page.add(_idle_group())
    if not power.idle_daemon_installed():
        page.add(_install_group())
    return page


def _card_box(card: Gtk.Widget) -> Gtk.Box:
    box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=12)
    box.set_margin_top(6)
    box.append(card)
    return box


def _energy_mode_group() -> Adw.PreferencesGroup:
    group = Adw.PreferencesGroup(
        title="Energy mode",
        description="Most effective on laptops.",
    )

    if not power.ppd_installed():
        group.add(Adw.ActionRow(title="Install to enable energy modes"))
        group.add(_card_box(RunnerCard(
            "Install",
            ["pacman", "-S", "--needed", "--noconfirm", "power-profiles-daemon"],
            privileged=True,
        )))
        return group

    profs = power.power_profiles()
    if not profs:
        group.add(Adw.ActionRow(title="Enable to use energy modes"))
        group.add(_card_box(RunnerCard(
            "Enable",
            ["systemctl", "enable", "--now", "power-profiles-daemon"],
            privileged=True,
        )))
        return group

    cur = power.current_profile()
    combo = Adw.ComboRow(title="Power profile")
    combo.set_model(Gtk.StringList.new(profs))
    if cur in profs:
        combo.set_selected(profs.index(cur))

    def on_sel(c: Adw.ComboRow, _p) -> None:
        i = c.get_selected()
        if 0 <= i < len(profs):
            power.set_profile(profs[i])

    combo.connect("notify::selected", on_sel)
    group.add(combo)
    return group


def _power_source_group() -> Adw.PreferencesGroup:
    group = Adw.PreferencesGroup(title="Power source")
    bats = power.batteries()
    if bats:
        for b in bats:
            row = Adw.ActionRow(title=b.name.upper(), subtitle=b.status)
            cap = f"{b.capacity}%" if b.capacity >= 0 else "—"
            if b.capacity >= 0:
                level = Gtk.LevelBar.new_for_interval(0, 100)
                level.set_value(b.capacity)
                level.set_size_request(120, -1)
                level.set_valign(Gtk.Align.CENTER)
                row.add_suffix(level)
            lbl = Gtk.Label(label=cap)
            lbl.add_css_class("dim-label")
            lbl.add_css_class("numeric")
            row.add_suffix(lbl)
            group.add(row)
    else:
        ac = power.ac_online()
        sub = (
            "On AC power" if ac is True
            else "No battery detected — desktop system"
        )
        group.add(Adw.ActionRow(title="Battery", subtitle=sub))
    return group


def _brightness_group() -> Adw.PreferencesGroup:
    group = Adw.PreferencesGroup(title="Display brightness")
    row = Adw.ActionRow(title="Brightness")

    scale = Gtk.Scale.new_with_range(Gtk.Orientation.HORIZONTAL, 1, 100, 1)
    scale.set_hexpand(True)
    scale.set_size_request(220, -1)
    scale.set_draw_value(False)
    scale.set_valign(Gtk.Align.CENTER)

    pct_lbl = Gtk.Label()
    pct_lbl.add_css_class("dim-label")
    pct_lbl.add_css_class("numeric")

    # Startwert VOR connect setzen, sonst feuert es beim Aufbau ein set.
    cur = power.brightness_percent()
    scale.set_value(max(1, min(100, cur)))
    pct_lbl.set_label(f"{cur}%")

    runner = ProcessRunner()
    # Runner am Widget verankern, damit er nicht weg-gc't wird.
    row._brightness_runner = runner  # noqa: SLF001

    def on_changed(s: Gtk.Scale) -> None:
        val = int(s.get_value())
        pct_lbl.set_label(f"{val}%")
        if not runner.running:
            runner.run(power.set_brightness_argv(val), privileged=False)

    scale.connect("value-changed", on_changed)

    row.add_suffix(scale)
    row.add_suffix(pct_lbl)
    group.add(row)
    return group


def _idle_group() -> Adw.PreferencesGroup:
    t = power.read_idle_timeouts()
    daemon = power.idle_daemon_name()
    group = Adw.PreferencesGroup(
        title="Idle · sleep",
        description="Turn the screen off or suspend after inactivity. 0 = never.",
    )

    so_adj = Gtk.Adjustment(value=t["screen_off"] // 60, lower=0, upper=240,
                            step_increment=1, page_increment=5)
    so = Adw.SpinRow(title="Screen off after", adjustment=so_adj)
    so.set_subtitle("minutes (0 = never)")
    group.add(so)

    su_adj = Gtk.Adjustment(value=t["suspend"] // 60, lower=0, upper=480,
                            step_increment=1, page_increment=5)
    su = Adw.SpinRow(title="Suspend after", adjustment=su_adj)
    su.set_subtitle("minutes (0 = never)")
    group.add(su)

    btn = Gtk.Button(label="Apply idle settings")
    btn.add_css_class("suggested-action")
    btn.add_css_class("pill")
    btn.set_halign(Gtk.Align.START)
    status = Gtk.Label(xalign=0.0)
    status.add_css_class("dim-label")
    status.set_wrap(True)

    def on_apply(_b: Gtk.Button) -> None:
        so_sec = int(so_adj.get_value()) * 60
        su_sec = int(su_adj.get_value()) * 60
        p = power.write_idle_config(so_sec, su_sec)
        if power.idle_daemon_installed():
            ok = power.apply_idle()
            status.set_label(
                f"Saved → {p}. {daemon} "
                + ("restarted." if ok else "service could not start.")
            )
        else:
            status.set_label(
                f"Saved → {p}. Install {daemon} below to activate."
            )

    btn.connect("clicked", on_apply)

    box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=8)
    box.set_margin_top(6)
    box.append(btn)
    box.append(status)
    group.add(box)
    return group


def _install_group() -> Adw.PreferencesGroup:
    pkg = power.idle_pkg()
    group = Adw.PreferencesGroup(
        title="Idle timers",
        description="Install to enable the timers above.",
    )
    card = RunnerCard(
        "Install", ["pacman", "-S", "--needed", "--noconfirm", pkg],
        privileged=True,
    )
    box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=12)
    box.set_margin_top(6)
    box.append(card)
    group.add(box)
    return group
