#!/usr/bin/env python3
"""
Aria Health Server - minimaler JSON-Endpoint auf Port 9090.
GET /health       -> {"status": "ok", "services": {...}, ...}   (cached, fast)
GET /health/full  -> identisch, aber cache wird gebrochen        (slow)

KAR-56 (11.05.2026): Cache (30s) und ThreadingHTTPServer. Vorher curl --max-time 3
timeoutet weil collect() ca. 5s braucht (Anthropic + Telegram Network-Calls).
"""
import json, os, subprocess, sqlite3, threading, time, urllib.request, urllib.error
from datetime import datetime, timezone
from http.server import ThreadingHTTPServer, BaseHTTPRequestHandler

PORT = 9090
DB_PATH = os.path.expanduser("~/.aria-chat.db")
ENV_FILE = os.path.expanduser("~/.env")
CACHE_TTL_SEC = 30

_cache_lock = threading.Lock()
_cache = {"ts": 0.0, "data": None}


def svc_active(name: str) -> bool:
    try:
        r = subprocess.run(["systemctl", "is-active", name],
                           capture_output=True, text=True, timeout=3)
        return r.stdout.strip() == "active"
    except Exception:
        return False


def telegram_ping() -> bool:
    token = None
    tg_env = os.path.expanduser("~/.claude/channels/telegram/.env")
    if os.path.exists(tg_env):
        for line in open(tg_env):
            if line.startswith("TELEGRAM_BOT_TOKEN="):
                token = line.split("=", 1)[1].strip()
                break
    if not token:
        return False
    try:
        req = urllib.request.Request(f"https://api.telegram.org/bot{token}/getMe")
        with urllib.request.urlopen(req, timeout=5) as r:
            return json.loads(r.read()).get("ok", False)
    except Exception:
        return False


def last_chat_ts():
    if not os.path.exists(DB_PATH):
        return None
    try:
        conn = sqlite3.connect(DB_PATH, timeout=3)
        row = conn.execute(
            "SELECT created_at FROM aria_chat_log ORDER BY created_at DESC LIMIT 1"
        ).fetchone()
        conn.close()
        return row[0] if row else None
    except Exception:
        return None


def anthropic_valid() -> bool:
    key = None
    if os.path.exists(ENV_FILE):
        for line in open(ENV_FILE):
            if line.startswith("ANTHROPIC_API_KEY="):
                key = line.split("=", 1)[1].strip()
                break
    if not key:
        # Max/Pro Plan — nicht pruefbar via API
        return None
    try:
        req = urllib.request.Request(
            "https://api.anthropic.com/v1/messages",
            data=json.dumps({
                "model": "claude-haiku-4-5-20251001",
                "max_tokens": 1,
                "messages": [{"role": "user", "content": "hi"}],
            }).encode(),
            headers={"x-api-key": key, "anthropic-version": "2023-06-01",
                     "content-type": "application/json"},
            method="POST",
        )
        with urllib.request.urlopen(req, timeout=8) as r:
            return r.status == 200
    except urllib.error.HTTPError as e:
        return e.code not in (401, 403)
    except Exception:
        return False


def brain_last_change():
    brain = os.path.expanduser("~/aria/brain")
    if not os.path.isdir(brain):
        return None
    try:
        r = subprocess.run(["git", "-C", brain, "log", "-1", "--format=%ci"],
                           capture_output=True, text=True, timeout=3)
        return r.stdout.strip() or None
    except Exception:
        return None


def collect():
    tg = telegram_ping()
    anth = anthropic_valid()
    services = {
        "aria": svc_active("aria.service"),
        "aria-chat-logger": svc_active("aria-chat-logger.service"),
        "aria-health": svc_active("aria-health.service"),
    }
    all_ok = all(services.values()) and tg and anth is not False
    return {
        "status": "ok" if all_ok else "degraded",
        "timestamp": datetime.now(timezone.utc).isoformat(),
        "services": services,
        "telegram_reachable": tg,
        "anthropic_key_valid": anth,
        "last_chat": last_chat_ts(),
        "brain_last_change": brain_last_change(),
    }


def collect_cached(force_refresh: bool = False) -> dict:
    """collect() macht 3+ Network-Calls (5-8s gesamt). Bei /health cachen wir
    das Ergebnis fuer CACHE_TTL_SEC, /health/full erzwingt Refresh."""
    now = time.time()
    with _cache_lock:
        if not force_refresh and _cache["data"] and (now - _cache["ts"]) < CACHE_TTL_SEC:
            data = dict(_cache["data"])
            data["cache_age_s"] = round(now - _cache["ts"], 2)
            return data
    fresh = collect()
    fresh["cache_age_s"] = 0
    with _cache_lock:
        _cache["ts"] = now
        _cache["data"] = fresh
    return fresh


class H(BaseHTTPRequestHandler):
    def do_GET(self):
        if self.path in ("/health", "/"):
            data = collect_cached(force_refresh=False)
        elif self.path == "/health/full":
            data = collect_cached(force_refresh=True)
        else:
            self.send_response(404); self.end_headers(); return
        body = json.dumps(data, indent=2).encode()
        try:
            self.send_response(200)
            self.send_header("content-type", "application/json")
            self.send_header("content-length", str(len(body)))
            self.end_headers()
            self.wfile.write(body)
        except BrokenPipeError:
            # Client gab schon auf — kein Stack-Trace ins Journal werfen.
            return

    def log_message(self, fmt, *args):
        return


if __name__ == "__main__":
    ThreadingHTTPServer(("127.0.0.1", PORT), H).serve_forever()
