#!/usr/bin/env python3
"""
llama-swap health watchdog — runs periodically via Hermes cron (no_agent).
- Silent when healthy (no stdout → nothing delivered)
- On unhealthy proxy: restarts llama-swap, outputs notification message
- Also delivers any pending legacy model-switch notification file once
"""

import os
import subprocess
import sys
import time
import urllib.request
from datetime import datetime

NOTIFY_FILE = os.path.expanduser("~/.hermes/.model-switch-notify")
LOG_DIR = os.path.expanduser("~/.hermes/logs")
LOG_FILE = os.path.join(LOG_DIR, "model-health.log")
LLAMA_SWAP_SERVICE = "llama-swap"
LLAMA_SWAP_MODELS_URL = "http://127.0.0.1:9292/v1/models"

os.makedirs(LOG_DIR, exist_ok=True)


def log(msg: str):
    ts = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    with open(LOG_FILE, "a", encoding="utf-8") as f:
        f.write(f"{ts} {msg}\n")


def deliver_legacy_notification() -> bool:
    if not os.path.exists(NOTIFY_FILE):
        return False
    with open(NOTIFY_FILE, encoding="utf-8") as f:
        content = f.read().strip()
    os.remove(NOTIFY_FILE)
    if content:
        print(content)
        return True
    return False


def service_active() -> bool:
    r = subprocess.run(
        ["systemctl", "is-active", LLAMA_SWAP_SERVICE],
        capture_output=True,
        text=True,
        timeout=10,
    )
    return r.stdout.strip() == "active"


def proxy_healthy(timeout: int = 5) -> bool:
    try:
        with urllib.request.urlopen(LLAMA_SWAP_MODELS_URL, timeout=timeout) as resp:
            if resp.status != 200:
                return False
            body = resp.read(4096).decode("utf-8", errors="replace")
            return '"data"' in body and '"object":"list"' in body.replace(" ", "")
    except Exception:
        return False


def restart_service() -> tuple[bool, str]:
    r = subprocess.run(
        ["sudo", "systemctl", "restart", LLAMA_SWAP_SERVICE],
        capture_output=True,
        text=True,
        timeout=60,
    )
    if r.returncode != 0:
        return False, (r.stderr or r.stdout or "restart failed").strip()[:240]

    deadline = time.time() + 30
    while time.time() < deadline:
        if service_active() and proxy_healthy(timeout=5):
            return True, "healthy after restart"
        time.sleep(2)
    return False, "service restarted but /v1/models never became healthy within 30s"


def main():
    if deliver_legacy_notification():
        sys.exit(0)

    active = service_active()
    healthy = proxy_healthy(timeout=5) if active else False
    if active and healthy:
        sys.exit(0)

    log(f"UNHEALTHY: service_active={active} proxy_healthy={healthy} — restarting {LLAMA_SWAP_SERVICE}")
    ok, detail = restart_service()
    now = datetime.now().strftime('%I:%M %p')
    if ok:
        log(f"RESTARTED: {LLAMA_SWAP_SERVICE} {detail}")
        print(f"🔄 **llama-swap** was unhealthy — restarted at {now} PDT")
        sys.exit(0)

    log(f"FAILED: {LLAMA_SWAP_SERVICE} {detail}")
    print(f"❌ **llama-swap** restart failed: {detail}")
    sys.exit(1)


if __name__ == "__main__":
    try:
        main()
    except Exception as e:
        log(f"UNHANDLED: {e}")
        print(f"❌ Health watchdog error: {e}")
        sys.exit(1)
