#!/usr/bin/env python3
"""
Model service health watchdog — runs via Hermes cron (no_agent=True) every 5 min.
Key behaviors:
  - Silent when healthy (no output → nothing delivered)
  - Deliver pending .model-switch-notify files FIRST (from switches/restarts/rollbacks)
  - On dead service: restart it via sudo systemctl, output notification message

LIVE PATH: ~/.hermes/scripts/model-health-watchdog.py (cron references this path)
Requires shared models.py in the same directory.
"""
import subprocess
import os
import sys
from datetime import datetime

_script_dir = os.path.dirname(os.path.abspath(__file__))
if _script_dir not in sys.path:
    sys.path.insert(0, _script_dir)
from models import MODELS

CONFIG = os.path.expanduser("~/.hermes/config.yaml")
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")

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") as f:
        f.write(f"{ts} {msg}\n")


def get_config_model() -> str | None:
    if not os.path.exists(CONFIG):
        return None
    with open(CONFIG) as f:
        for line in f:
            stripped = line.strip()
            if stripped.startswith("default:") and ".gguf" in stripped:
                return stripped.split("default:")[-1].strip().strip("'\"")
    return None


def get_active_service_name() -> str | None:
    for m in MODELS:
        r = subprocess.run(
            ["systemctl", "is-active", m["service"]],
            capture_output=True, text=True, timeout=10,
        )
        if r.stdout.strip() == "active":
            return m["name"]
    return None


def main():
    # ── Deliver any pending notification first ────────────────────
    # Model switches, restarts, and rollbacks leave a notification file.
    # Check before health check so switches deliver on next tick.
    if os.path.exists(NOTIFY_FILE):
        with open(NOTIFY_FILE) as f:
            content = f.read().strip()
        os.remove(NOTIFY_FILE)
        if content:
            print(content)
            sys.exit(0)

    config_model = get_config_model()
    if not config_model:
        sys.exit(0)

    target = next((m for m in MODELS if m["model_name"] == config_model), None)
    if not target:
        sys.exit(0)  # cloud model

    active = get_active_service_name()
    if active == target["name"]:
        sys.exit(0)  # healthy → silent

    # Dead or mismatched — restart
    log(f"DEAD: {target['name']} — active={active}, restarting...")

    if active:
        other = next((m for m in MODELS if m["name"] == active), None)
        if other:
            subprocess.run(
                ["sudo", "systemctl", "stop", other["service"]],
                capture_output=True, timeout=15,
            )

    r = subprocess.run(
        ["sudo", "systemctl", "start", target["service"]],
        capture_output=True, text=True, timeout=30,
    )

    if r.returncode == 0:
        log(f"RESTARTED: {target['name']} successfully")
        print(f"🔄 **{target['name']}** was down — auto-restarted at "
              f"{datetime.now().strftime('%I:%M %p')} PDT")
    else:
        log(f"FAILED: restart {target['name']}: {r.stderr.strip()[:200]}")
        print(f"❌ **{target['name']}** restart failed: {r.stderr.strip()[:200]}")
        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)
