from __future__ import annotations

import shutil
import subprocess
from dataclasses import dataclass
from pathlib import Path

from .system_info import SystemInfo


@dataclass(frozen=True)
class StatusItem:
    category: str
    label: str
    ok: bool
    detail: str


def _command_exists(command: str) -> bool:
    return shutil.which(command) is not None


def _run(command: list[str]) -> subprocess.CompletedProcess[str]:
    return subprocess.run(command, text=True, capture_output=True, check=False)


def _service_active(service: str) -> bool:
    if not _command_exists("systemctl"):
        return False
    return _run(["systemctl", "is-active", service]).returncode == 0


def _binary_status(category: str, label: str, command: str) -> StatusItem:
    exists = _command_exists(command)
    return StatusItem(category=category, label=label, ok=exists, detail="installé" if exists else "absent")


def collect_status(system: SystemInfo) -> list[StatusItem]:
    maintenance: list[StatusItem] = []
    security: list[StatusItem] = []
    services: list[StatusItem] = []
    performance: list[StatusItem] = []
    poste: list[StatusItem] = []

    p10k_path = system.target_home / ".p10k.zsh"
    poste.append(StatusItem("Poste", "Config p10k", p10k_path.exists(), str(p10k_path if p10k_path.exists() else "absente")))

    unattended_ok = False
    unattended_detail = "non configuré"
    if system.package_manager == "apt-get":
        unattended_ok = _service_active("unattended-upgrades.service") and Path("/etc/apt/apt.conf.d/20auto-upgrades").exists()
        unattended_detail = "service actif" if unattended_ok else "service inactif"
    elif system.package_manager in {"dnf", "yum"}:
        unattended_ok = _service_active("dnf-automatic.timer")
        unattended_detail = "timer actif" if unattended_ok else "timer inactif"
    maintenance.append(StatusItem("Maintenance", "MAJ auto", unattended_ok, unattended_detail))

    logrotate_ok = Path("/etc/logrotate.d/securecheck").exists()
    maintenance.append(StatusItem("Maintenance", "Rotation logs", logrotate_ok, "config présente" if logrotate_ok else "config absente"))

    zram_ok = _service_active("securecheck-zram.service") or ("zram" in _run(["swapon", "--show"]).stdout if _command_exists("swapon") else False)
    performance.append(StatusItem("Performance", "zram", zram_ok, "actif" if zram_ok else "inactif"))

    if _command_exists("ufw"):
        ufw_result = _run(["ufw", "status"])
        firewall_ok = "Status: active" in ufw_result.stdout
        firewall_detail = "ufw actif" if firewall_ok else "ufw inactif"
    elif _command_exists("firewall-cmd"):
        firewall_ok = _service_active("firewalld.service")
        firewall_detail = "firewalld actif" if firewall_ok else "firewalld inactif"
    else:
        firewall_ok = False
        firewall_detail = "pare-feu absent"
    security.append(StatusItem("Sécurité", "Firewall", firewall_ok, firewall_detail))
    apparmor_active = _service_active("apparmor") or _command_exists("apparmor_status")
    security.append(StatusItem("Sécurité", "AppArmor", apparmor_active, "activé" if apparmor_active else "inactif"))

    clamav_active = _service_active("clamav-daemon") or _service_active("clamav-freshclam")
    security.append(StatusItem("Sécurité", "ClamAV", clamav_active, "actif" if clamav_active else "inactif"))
    wazuh_active = _service_active("wazuh-agent")
    security.append(StatusItem("Sécurité", "Wazuh agent", wazuh_active, "actif" if wazuh_active else "inactif"))
    aide_timer_active = _service_active("aidecheck.timer")
    aide_db_exists = Path("/var/lib/aide/aide.db").exists()
    aide_ok = aide_timer_active or aide_db_exists
    detail = "timer actif" if aide_timer_active else "db présent" if aide_db_exists else "inactif"
    security.append(StatusItem("Sécurité", "AIDE", aide_ok, detail))

    security.append(_binary_status("Sécurité", "Lynis", "lynis"))
    security.append(_binary_status("Sécurité", "rkhunter", "rkhunter"))
    security.append(_binary_status("Sécurité", "chkrootkit", "chkrootkit"))

    docker_active = _command_exists("docker") and _service_active("docker.service")
    fail2ban_active = _command_exists("fail2ban-client") and _service_active("fail2ban.service")
    services.append(StatusItem("Services", "Service Docker", docker_active, "actif" if docker_active else "inactif"))
    services.append(StatusItem("Services", "Service fail2ban", fail2ban_active, "actif" if fail2ban_active else "inactif"))
    avahi_running = _command_exists("avahi-daemon") and _service_active("avahi-daemon")
    services.append(StatusItem("Services", "Avahi", not avahi_running, "désactivé" if not avahi_running else "actif"))
    services.append(_binary_status("Services", "Docker", "docker"))
    services.append(_binary_status("Services", "fail2ban", "fail2ban-client"))

    poste.extend([
        _binary_status("Poste", "zsh", "zsh"),
        _binary_status("Poste", "git", "git"),
        _binary_status("Poste", "curl", "curl"),
        _binary_status("Poste", "ncdu", "ncdu"),
        _binary_status("Poste", "needrestart", "needrestart"),
        _binary_status("Poste", "htop", "htop"),
        _binary_status("Poste", "nmon", "nmon"),
        _binary_status("Poste", "duf", "duf"),
        _binary_status("Poste", "net-tools", "ifconfig"),
    ])

    ordered = maintenance + security + performance + services + poste
    return ordered
