"""Theming: Fuji-Akzente + Light/Dark — über CSS-Recoloring.

libadwaita ignoriert klassische GTK-Themes bewusst; Theming läuft daher über
das Überschreiben der benannten Adwaita-Farben (`@define-color accent_bg_color …`)
per CSS-Provider auf USER-Priorität. Die Akzent-Hues kommen 1:1 aus
`taninux.core.theme`, damit GTK-App und TUI dieselbe Palette teilen.
"""
from __future__ import annotations

import os
import subprocess
from pathlib import Path

import gi

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

# Akzent-Daten leben GTK-frei in gui.accents (geteilt mit config + eww-Consumer).
from taninux.core import theme as T  # noqa: F401  (CSS nutzt @window_bg_color etc.)
from taninux.gui.accents import (  # noqa: F401  (re-export für settings.py)
    DEFAULT_ACCENT,
    FUJI_ACCENTS,
    Accent,
    by_key as accent,
)

# Mapping Schema-Key → Adwaita ColorScheme
_SCHEMES = {
    "system": Adw.ColorScheme.DEFAULT,
    "light": Adw.ColorScheme.FORCE_LIGHT,
    "dark": Adw.ColorScheme.FORCE_DARK,
}

_provider: Gtk.CssProvider | None = None


def _contrast_fg(hex_color: str) -> str:
    """Lesbarer Vordergrund (dunkel/weiß) für Text auf der Akzentfläche."""
    h = hex_color.lstrip("#")
    r, g, b = (int(h[i:i + 2], 16) / 255 for i in (0, 2, 4))
    lum = 0.2126 * r + 0.7152 * g + 0.0588 * b
    return T.YORU if lum > 0.6 else "#ffffff"


def _build_css(acc: Accent) -> bytes:
    fg = _contrast_fg(acc.hex)
    # Akzent-Override + Swatch-Styling (Swatches sind statisch, aber billig
    # mitzubauen). Swatch = runder Farbknopf, aktiver bekommt einen Ring.
    swatches = "\n".join(
        f".swatch-{a.key} {{ background-color: {a.hex}; }}"
        for a in FUJI_ACCENTS
    )
    return f"""
@define-color accent_bg_color {acc.hex};
@define-color accent_fg_color {fg};
@define-color accent_color {acc.hex};

/* pill controls — all buttons & dropdowns are stadium pills */
button, menubutton > button, dropdown, dropdown > button,
combobox button, splitbutton > button, entry, spinbutton,
.pill {{ border-radius: 999px; }}

.fuji-swatch {{
  min-width: 26px;
  min-height: 26px;
  padding: 0;
  border-radius: 50%;
  box-shadow: inset 0 0 0 1px alpha(currentColor, 0.15);
}}
.fuji-swatch:checked {{
  box-shadow: inset 0 0 0 2px @window_bg_color, 0 0 0 2px @accent_bg_color;
}}
{swatches}
""".encode()


def apply(color_scheme: str, accent_key: str) -> None:
    """Setzt Color-Scheme (StyleManager) + Akzent (CSS-Provider)."""
    global _provider

    mgr = Adw.StyleManager.get_default()
    mgr.set_color_scheme(_SCHEMES.get(color_scheme, Adw.ColorScheme.DEFAULT))

    if _provider is None:
        _provider = Gtk.CssProvider()
        display = Gdk.Display.get_default()
        if display is not None:
            Gtk.StyleContext.add_provider_for_display(
                display, _provider, Gtk.STYLE_PROVIDER_PRIORITY_USER
            )
    _provider.load_from_data(_build_css(accent(accent_key)))


def apply_persisted() -> None:
    """Beim Start aufrufen — lädt die gespeicherte Präferenz."""
    from taninux.gui import config

    cfg = config.load()
    apply(cfg["color_scheme"], cfg["accent"])


# --------------------------------------------------------------------------
#  Global theme (system-wide GTK4 + GTK3) — full dynamic Fuji recolour.
# --------------------------------------------------------------------------
# Writes the picked Fuji accent + monochrome light/dark SURFACES to the global
# GTK4 (libadwaita) and GTK3 user CSS, and sets gsettings so EVERY app follows
# (not just this one). Dark base = #0f0f0f, light base = #f0f0f0; the accent is
# the chosen Fuji hue. All buttons & dropdowns are pills. GTK4 rides on the
# existing `@import "libadwaita.css"`; GTK3 rides on adw-gtk3.

# Monochrome surfaces derived from the two base values (#0f0f0f / #f0f0f0).
_DARK_SURF = dict(bg="#0f0f0f", bg_alt="#191919", bg_hi="#262626", view="#141414",
                  card="#191919", headerbar="#0f0f0f", fg="#f0f0f0",
                  border="rgba(240,240,240,0.10)")
_LIGHT_SURF = dict(bg="#f0f0f0", bg_alt="#e4e4e4", bg_hi="#d6d6d6", view="#fafafa",
                   card="#ffffff", headerbar="#e8e8e8", fg="#0f0f0f",
                   border="rgba(15,15,15,0.12)")

_PILLS_GTK4 = (
    "button, menubutton > button, dropdown, dropdown > button, combobox button,\n"
    "splitbutton > button, entry, spinbutton, .pill { border-radius: 999px; }\n"
    ".card, popover > contents, .osd { border-radius: 14px; }\n"
)
_PILLS_GTK3 = (
    "button, combobox button, combobox, entry, spinbutton,\n"
    "notebook > header > tabs > tab { border-radius: 999px; }\n"
)


def _config_base() -> Path:
    return Path(os.environ.get("XDG_CONFIG_HOME") or str(Path.home() / ".config"))


def _gtk4_config_dir() -> Path:
    return _config_base() / "gtk-4.0"


def _resolve_dark(color_scheme: str) -> bool:
    """True if the global theme should be dark. 'system' → read gsettings."""
    if color_scheme == "dark":
        return True
    if color_scheme == "light":
        return False
    try:
        out = subprocess.run(
            ["gsettings", "get", "org.gnome.desktop.interface", "color-scheme"],
            capture_output=True, text=True, timeout=5, check=False,
        ).stdout
    except (FileNotFoundError, subprocess.TimeoutExpired):
        return True
    return "prefer-light" not in out


def _gtk4_full(acc: Accent, dark: bool) -> str:
    p = _DARK_SURF if dark else _LIGHT_SURF
    fg = _contrast_fg(acc.hex)
    return f"""/* TANINUX-managed — global GTK4/libadwaita Fuji theme. Do not edit by hand.
   {'dark' if dark else 'light'} · accent {acc.label} ({acc.hex}) */
@define-color accent_color {acc.hex};
@define-color accent_bg_color {acc.hex};
@define-color accent_fg_color {fg};
@define-color window_bg_color {p['bg']};
@define-color window_fg_color {p['fg']};
@define-color view_bg_color {p['view']};
@define-color view_fg_color {p['fg']};
@define-color headerbar_bg_color {p['headerbar']};
@define-color headerbar_fg_color {p['fg']};
@define-color headerbar_backdrop_color {p['bg']};
@define-color headerbar_border_color {p['fg']};
@define-color card_bg_color {p['card']};
@define-color card_fg_color {p['fg']};
@define-color dialog_bg_color {p['view']};
@define-color dialog_fg_color {p['fg']};
@define-color popover_bg_color {p['bg_alt']};
@define-color popover_fg_color {p['fg']};
@define-color sidebar_bg_color {p['bg_alt']};
@define-color sidebar_fg_color {p['fg']};
{_PILLS_GTK4}"""


def _gtk3_full(acc: Accent, dark: bool) -> str:
    p = _DARK_SURF if dark else _LIGHT_SURF
    fg = _contrast_fg(acc.hex)
    return f"""/* TANINUX-managed — global GTK3 Fuji theme (rides adw-gtk3). Do not edit. */
@define-color accent_color {acc.hex};
@define-color accent_bg_color {acc.hex};
@define-color accent_fg_color {fg};
@define-color window_bg_color {p['bg']};
@define-color window_fg_color {p['fg']};
@define-color view_bg_color {p['view']};
@define-color headerbar_bg_color {p['headerbar']};
@define-color card_bg_color {p['card']};
@define-color popover_bg_color {p['bg_alt']};
@define-color theme_bg_color {p['bg']};
@define-color theme_fg_color {p['fg']};
@define-color theme_base_color {p['view']};
@define-color theme_text_color {p['fg']};
@define-color theme_selected_bg_color {acc.hex};
@define-color theme_selected_fg_color {fg};
@define-color borders {p['border']};
{_PILLS_GTK3}/* The per-widget accent (sliders, tab underline, switches) is driven by the
   GNOME accent-color gsetting (adw-gtk3 honours it and wins on specificity);
   write_global_theme maps the Fuji hue to the nearest preset. */
"""


# Fuji accent → nearest GNOME accent-color preset (for GTK3/adw-gtk3, which
# follows the gsetting; GTK4/libadwaita uses the exact Fuji hex from our css).
_ACCENT_PRESET = {
    "ume": "purple", "shinkai": "blue", "take": "green",
    "chikyu": "yellow", "beni": "red",
}


def _set_gsettings(dark: bool, system: bool, accent_key: str) -> None:
    pairs = [
        ("color-scheme", "default" if system else ("prefer-dark" if dark else "prefer-light")),
        ("gtk-theme", "adw-gtk3-dark" if dark else "adw-gtk3"),
        ("accent-color", _ACCENT_PRESET.get(accent_key, "purple")),
    ]
    for key, val in pairs:
        try:
            subprocess.run(
                ["gsettings", "set", "org.gnome.desktop.interface", key, val],
                check=False, timeout=5,
            )
        except (FileNotFoundError, subprocess.TimeoutExpired):
            pass


def write_global_theme(color_scheme: str, accent_key: str) -> None:
    """Write the full Fuji theme (GTK4 + GTK3) globally + sync gsettings.

    Drives EVERY app: surfaces follow light/dark (#f0f0f0 / #0f0f0f), the accent
    is the chosen Fuji hue, all buttons & dropdowns are pills.
    """
    acc = accent(accent_key)
    dark = _resolve_dark(color_scheme)

    # GTK4 → ~/.config/gtk-4.0/libadwaita.css (imported by the adw-gtk3 gtk.css).
    try:
        g4 = _gtk4_config_dir()
        g4.mkdir(parents=True, exist_ok=True)
        (g4 / "libadwaita.css").write_text(_gtk4_full(acc, dark))
        tweaks = g4 / "libadwaita-tweaks.css"
        if not tweaks.exists():           # silence the adw-gtk3 @import for it
            tweaks.write_text("/* TANINUX (intentionally empty) */\n")
    except OSError:
        pass

    # GTK3 → ~/.config/gtk-3.0/gtk.css (overrides on top of adw-gtk3).
    try:
        g3 = _config_base() / "gtk-3.0"
        g3.mkdir(parents=True, exist_ok=True)
        dst = g3 / "gtk.css"
        backup = g3 / "gtk.css.pre-tanin"
        if dst.exists() and not dst.is_symlink() and not backup.exists():
            backup.write_text(dst.read_text())   # keep a real pre-existing file once
        dst.write_text(_gtk3_full(acc, dark))
    except OSError:
        pass

    _set_gsettings(dark, color_scheme == "system", accent_key)


def write_global_accent(accent_key: str) -> None:
    """Back-compat shim — now writes the full theme for the saved scheme."""
    from taninux.gui import config
    write_global_theme(config.load()["color_scheme"], accent_key)
