"""Daily maintenance checks for IT Ops tab."""
from __future__ import annotations

import json
import subprocess
from datetime import datetime, timezone
from typing import Any

from app.db import execute, fetch_all, fetch_one
from app.connectors.proxmox import PROXMOX_HOST, VM_106_IP, _port_health, _run_ssh, check_docker_services

SEVERITY_ORDER = {"critical": 0, "warning": 1, "info": 2}


def _iso_now() -> str:
    return datetime.now(timezone.utc).isoformat()


def _table_exists(name: str) -> bool:
    row = fetch_one(
        """
        SELECT EXISTS(
            SELECT 1 FROM information_schema.tables
            WHERE table_schema = 'public' AND table_name = %s
        ) AS ok
        """,
        (name,),
    )
    return bool(row and row.get("ok"))


def list_notes(limit: int = 20, unresolved_only: bool = True) -> list[dict[str, Any]]:
    if not _table_exists("ops_maintenance_notes"):
        return []
    clauses = ["resolved = false"] if unresolved_only else []
    where = (" WHERE " + " AND ".join(clauses)) if clauses else ""
    rows = fetch_all(
        f"SELECT * FROM ops_maintenance_notes{where} ORDER BY created_at DESC LIMIT %s",
        (max(1, min(limit, 100)),),
    )
    out = []
    for r in rows:
        item = dict(r)
        if hasattr(item.get("created_at"), "isoformat"):
            item["created_at"] = item["created_at"].isoformat()
        out.append(item)
    return out


def add_note(title: str, body: str = "", severity: str = "info", source: str = "sysops") -> dict[str, Any] | None:
    if not _table_exists("ops_maintenance_notes"):
        return None
    row = fetch_one(
        """
        INSERT INTO ops_maintenance_notes (severity, title, body, source)
        VALUES (%s, %s, %s, %s)
        RETURNING *
        """,
        (severity, title[:255], body, source),
    )
    if not row:
        return None
    item = dict(row)
    if hasattr(item.get("created_at"), "isoformat"):
        item["created_at"] = item["created_at"].isoformat()
    return item


def run_maintenance_scan() -> dict[str, Any]:
    findings: list[dict[str, Any]] = []

    proxmox_up = _port_health(PROXMOX_HOST, 8006)
    if not proxmox_up:
        findings.append({
            "severity": "critical",
            "title": "Proxmox Web UI niet bereikbaar",
            "body": f"Poort 8006 op {PROXMOX_HOST} reageert niet. Controleer Dell R340 / Proxmox VE.",
        })

    docker = check_docker_services()
    if not docker.get("ok"):
        findings.append({
            "severity": "warning",
            "title": "Docker status onbekend",
            "body": docker.get("error") or "Kon docker ps niet uitvoeren op VM106.",
        })
    else:
        containers = docker.get("containers") or []
        unhealthy = [
            c for c in containers
            if "unhealthy" in str(c.get("Status") or c.get("State") or "").lower()
        ]
        if unhealthy:
            names = ", ".join(str(c.get("Names") or c.get("Name") or "?")[:40] for c in unhealthy[:5])
            findings.append({
                "severity": "warning",
                "title": f"{len(unhealthy)} container(s) unhealthy",
                "body": names,
            })

    apt = _run_ssh(VM_106_IP, "apt list --upgradable 2>/dev/null | grep -v Listing | wc -l")
    if apt.get("ok"):
        try:
            count = int((apt.get("stdout") or "0").strip())
        except ValueError:
            count = 0
        if count > 0:
            findings.append({
                "severity": "info" if count < 10 else "warning",
                "title": f"{count} package updates beschikbaar op VM106",
                "body": "Voer maintenance uit wanneer gepland: apt update && apt upgrade",
            })

    disk = _run_ssh(VM_106_IP, "df -h / | tail -1 | awk '{print $5}'")
    if disk.get("ok"):
        pct = (disk.get("stdout") or "").replace("%", "").strip()
        try:
            used = int(pct)
            if used >= 90:
                findings.append({
                    "severity": "critical",
                    "title": f"Schijf VM106 {used}% vol",
                    "body": "Ruimte vrijmaken op root volume.",
                })
            elif used >= 80:
                findings.append({
                    "severity": "warning",
                    "title": f"Schijf VM106 {used}% vol",
                    "body": "Plan opschoning binnenkort.",
                })
        except ValueError:
            pass

    saved: list[dict[str, Any]] = []
    for f in findings:
        note = add_note(f["title"], f.get("body", ""), f.get("severity", "info"))
        if note:
            saved.append(note)

    if not findings:
        note = add_note(
            "Geen openstaande maintenance — alles OK",
            f"Scan {_iso_now()}: Proxmox, Docker en schijf binnen normen.",
            "info",
        )
        if note:
            saved.append(note)

    saved.sort(key=lambda n: SEVERITY_ORDER.get(str(n.get("severity")), 9))

    try:
        from app.connectors.gitea_repo_sync import _record_activity
        from app.middleware import log_agent_event

        summary = f"{len(findings)} bevinding(en) — scan {_iso_now()[:19]}"
        _record_activity(
            "maintenance_scan",
            f"Maintenance scan: {len(findings)} bevinding(en)",
            summary + "\n" + "\n".join(f"- {f['title']}" for f in findings[:8]),
            metadata={"findings_count": len(findings), "for_herman": True},
        )
        log_agent_event(
            agent_name="sysops",
            agent_type="sysops",
            event_type="maintenance_scan",
            title=f"Maintenance scan voltooid — {len(findings)} bevinding(en)",
            body=summary,
            metadata={"findings": [f.get("title") for f in findings[:10]], "for_herman": True},
            channel="sysops",
        )
    except Exception:
        pass

    return {
        "ok": True,
        "scanned_at": _iso_now(),
        "findings_count": len(findings),
        "notes": saved,
    }
