"""Systemd service status checks for heartbeat monitoring."""

from __future__ import annotations

import logging
import subprocess
import time
from pathlib import Path

logger = logging.getLogger("health-heartbeat")


def check_oom_kills(service: str, window_minutes: int = 30) -> int:
    """Count OOM kills for a service in the last N minutes via journalctl."""
    try:
        r = subprocess.run(
            [
                "journalctl",
                "--user",
                "-u",
                f"opendeviationbar-{service}",
                "--since",
                f"{window_minutes} min ago",
                "--no-pager",
                "-q",
                "--grep",
                "oom-kill|out-of-memory|killed process",
            ],
            capture_output=True,
            text=True,
            timeout=10,
            check=False,
        )
        if r.returncode == 0 and r.stdout.strip():
            return len(r.stdout.strip().split("\n"))
    except (FileNotFoundError, subprocess.TimeoutExpired, OSError):
        pass
    return 0


def check_systemd_overrides() -> list[str]:
    """Detect active systemd override files for opendeviationbar services."""
    overrides = []
    override_base = Path.home() / ".config" / "systemd" / "user"
    if not override_base.exists():
        return overrides
    for service_dir in override_base.glob("opendeviationbar-*.service.d"):
        confs = list(service_dir.glob("*.conf"))
        if confs:
            svc_name = service_dir.name.replace(".service.d", "")
            overrides.append(svc_name)
    return overrides


def get_kintsugi_daemon_pid() -> int | None:
    """Get kintsugi daemon MainPID from systemd (None if unavailable).

    Checks both normal and catch-up service (only one runs at a time).
    """
    for unit in ("opendeviationbar-kintsugi-catchup", "opendeviationbar-kintsugi"):
        try:
            r = subprocess.run(
                ["systemctl", "--user", "show", unit, "--property=MainPID"],
                capture_output=True,
                text=True,
                timeout=5,
                check=False,
            )
            for line in r.stdout.strip().split("\n"):
                if line.startswith("MainPID="):
                    pid = int(line.split("=", 1)[1])
                    if pid > 0:
                        return pid
        except (FileNotFoundError, subprocess.TimeoutExpired, OSError, ValueError):
            continue
    return None


def is_kintsugi_catchup_active() -> bool:
    """Check if kintsugi-catchup service is active (Issue #158 Phase 9)."""
    try:
        r = subprocess.run(
            ["systemctl", "--user", "is-active", "opendeviationbar-kintsugi-catchup"],
            capture_output=True,
            text=True,
            timeout=5,
            check=False,
        )
        return r.returncode == 0
    except (FileNotFoundError, subprocess.TimeoutExpired, OSError):
        return False


def collect_service_stats(results: dict[str, bool | str]) -> None:
    """Collect uptime and memory for daemon services."""
    for svc in ("sidecar", "kintsugi"):
        # For kintsugi, check catch-up service if normal is not active
        name = f"opendeviationbar-{svc}"
        if svc == "kintsugi" and results.get("kintsugi_mode") == "catch-up":
            name = "opendeviationbar-kintsugi-catchup"

        # MON-05: Query NRestarts alongside existing properties
        props_to_query = "MemoryCurrent,ExecMainStartTimestamp"
        if svc == "sidecar":
            props_to_query += ",NRestarts"
        try:
            r = subprocess.run(
                [
                    "systemctl",
                    "--user",
                    "show",
                    name,
                    f"--property={props_to_query}",
                ],
                capture_output=True,
                text=True,
                timeout=5,
                check=False,
            )
            props = {}
            for line in r.stdout.strip().split("\n"):
                if "=" in line:
                    k, v = line.split("=", 1)
                    props[k] = v

            # Memory (MB)
            mem_bytes = int(props.get("MemoryCurrent", 0))
            if mem_bytes > 0:
                results[f"{svc}_mem"] = f"{mem_bytes / 1024 / 1024:.0f}"

            # Uptime from ExecMainStartTimestamp
            ts_str = props.get("ExecMainStartTimestamp", "")
            uptime_min: float | None = None
            if ts_str and ts_str != "n/a":
                # Format: "Mon 2026-03-03 11:39:11 PST"
                # Parse with subprocess date for timezone handling
                try:
                    r2 = subprocess.run(
                        ["date", "-d", ts_str, "+%s"],
                        capture_output=True,
                        text=True,
                        timeout=2,
                        check=False,
                    )
                    if r2.returncode == 0 and r2.stdout.strip():
                        start_epoch = int(r2.stdout.strip())
                        uptime_h = (time.time() - start_epoch) / 3600
                        uptime_min = uptime_h * 60
                        if uptime_h < 1:
                            results[f"{svc}_uptime"] = f"{uptime_min:.0f}m"
                        elif uptime_h < 24:
                            results[f"{svc}_uptime"] = f"{uptime_h:.1f}h"
                        else:
                            results[f"{svc}_uptime"] = f"{uptime_h / 24:.1f}d"
                except (ValueError, OSError):
                    pass

            # MON-05: Sidecar PID age and restart count telemetry
            if svc == "sidecar":
                n_restarts_str = props.get("NRestarts", "")
                if n_restarts_str:
                    results["sidecar_restarts_total"] = n_restarts_str
                if uptime_min is not None:
                    results["sidecar_pid_age_min"] = f"{uptime_min:.0f}"
                    if uptime_min < 15 and int(n_restarts_str or "0") > 0:
                        results["sidecar_restart_freq"] = "frequent"
        except (FileNotFoundError, subprocess.TimeoutExpired, OSError, ValueError):
            pass
