"""Bootloader-Detection + Default-Entry Management.

Unterstützt:
- systemd-boot (via /boot/loader/entries/ + bootctl)
- GRUB (info-only — grub-set-default ist fragil, command zeigen)
"""
from __future__ import annotations

import re
import subprocess
from dataclasses import dataclass
from pathlib import Path


@dataclass
class BootloaderInfo:
    kind: str                       # "systemd-boot" / "grub" / "unknown"
    config_path: Path | None
    default_entry: str | None       # bei systemd-boot der entry-name (z.B. "arch.conf")
    entries: list[Path]             # alle .conf entries (nur systemd-boot)


def detect() -> BootloaderInfo:
    # systemd-boot
    loader_conf = Path("/boot/loader/loader.conf")
    entries_dir = Path("/boot/loader/entries")
    if loader_conf.exists() and entries_dir.is_dir():
        default = None
        try:
            for line in loader_conf.read_text().splitlines():
                line = line.strip()
                if line.startswith("default"):
                    parts = line.split(maxsplit=1)
                    if len(parts) == 2:
                        default = parts[1].strip()
                    break
        except OSError:
            pass
        # bootctl status liefert oft den effektiven default (falls "default" in loader.conf einen pattern hat)
        if not default or "*" in default:
            try:
                r = subprocess.run(
                    ["bootctl", "list", "--json=short"],
                    capture_output=True, text=True, check=False, timeout=5,
                )
                if r.returncode == 0:
                    import json
                    for entry in json.loads(r.stdout):
                        if entry.get("isDefault"):
                            default = entry.get("id", default)
                            break
            except (FileNotFoundError, subprocess.TimeoutExpired, ValueError):
                pass
        return BootloaderInfo(
            kind="systemd-boot",
            config_path=loader_conf,
            default_entry=default,
            entries=sorted(entries_dir.glob("*.conf")),
        )

    # GRUB
    grub_cfg = Path("/boot/grub/grub.cfg")
    if grub_cfg.exists():
        default = None
        try:
            etcdefault = Path("/etc/default/grub").read_text()
            m = re.search(r'^GRUB_DEFAULT\s*=\s*"?([^"\n]+)"?', etcdefault, re.MULTILINE)
            if m:
                default = m.group(1).strip()
        except OSError:
            pass
        return BootloaderInfo(
            kind="grub",
            config_path=grub_cfg,
            default_entry=default,
            entries=[],
        )

    return BootloaderInfo(kind="unknown", config_path=None,
                          default_entry=None, entries=[])


def entry_for_kernel(bl: BootloaderInfo, kernel_pkg: str) -> Path | None:
    """Findet das systemd-boot .conf entry für ein gegebenes Kernel-Paket.

    Match-Strategie: entry enthält `linux /vmlinuz-<suffix>` wo suffix mit
    `kernel_pkg` korrespondiert. `linux` → `/vmlinuz-linux`,
    `linux-zen` → `/vmlinuz-linux-zen`."""
    if bl.kind != "systemd-boot":
        return None
    target = f"vmlinuz-{kernel_pkg}"
    for entry in bl.entries:
        try:
            content = entry.read_text()
        except OSError:
            continue
        # Match exakt: vmlinuz-linux-zen, NICHT vmlinuz-linux wenn pkg=linux-zen
        for line in content.splitlines():
            line = line.strip()
            if line.startswith("linux"):
                # Format: "linux /vmlinuz-linux-zen"
                parts = line.split()
                if len(parts) >= 2:
                    path = parts[1].rstrip("/").split("/")[-1]
                    if path == target:
                        return entry
    return None


def is_default(bl: BootloaderInfo, entry: Path) -> bool:
    if bl.default_entry is None:
        return False
    return bl.default_entry == entry.name or bl.default_entry == entry.stem


def set_default_argv(bl: BootloaderInfo, entry) -> list[str] | None:
    """ARGV zum Setzen des Default-Boot-Entry.

    core eskaliert NICHT selbst — gibt nur die Befehlsliste zurück, die der
    (GTK-)Aufruferprivilegiert (pkexec) ausführt. Passt zum Muster „command zeigen".

    - systemd-boot: `bootctl set-default <entry-id>` (entry-id = .conf-Dateiname).
      `entry` darf ein str, eine Path oder None sein.
    - GRUB: None — `grub-set-default` ist fragil (Index vs. Menüpfad, danach
      `grub-mkconfig` nötig); bewusst nicht automatisiert.
    """
    if bl.kind != "systemd-boot" or entry is None:
        return None
    # entry-id für bootctl ist der Dateiname des .conf-Eintrags
    entry_id = entry.name if isinstance(entry, Path) else str(entry)
    return ["bootctl", "set-default", entry_id]


def prune_argv(keep: int) -> list[str]:
    """ARGV zum Aufräumen alter zwischengespeicherter Pakete via `paccache`.

    Meint den pacman-Cache (/var/cache/pacman/pkg) — darin liegen alte Versionen
    aller Pakete, inkl. alter Kernel. `paccache -rk <keep>` entfernt alle bis auf
    die `keep` jüngsten Versionen pro Paket; idiomatischer Arch-Weg.
    core eskaliert nicht selbst — der Aufrufer führt das privilegiert aus.
    """
    return ["paccache", "-rk", str(max(0, int(keep)))]
