"""Agent orchestration — Spec 029."""
from __future__ import annotations
import os
from pathlib import Path
from app.agents import checks, llm_client, notify, registry, store
from app.agents import messages as agent_messages
from app.agents.catalog import SCENARIO_AGENT_MAP

SPECS = Path(os.getenv("AGENTIC_SPECS_ROOT", "/opt/ligbox-ops-platform/specs"))
OPS_API = os.getenv("OPS_API_URL", "http://api:8080")
TOKEN = os.getenv("OPS_INTERNAL_TOKEN", "")

def sync_registry(conn):
    for sc in registry.load_registry():
        store.upsert_scenario(conn, sc)
    return len(registry.load_registry())

def index_specs_kb(conn):
    if not SPECS.exists(): return 0
    n = 0
    for p in sorted(SPECS.glob("**/*.md")):
        try:
            txt = p.read_text(encoding="utf-8", errors="ignore")
            if len(txt) > 100:
                store.index_kb_file(conn, str(p.relative_to(SPECS)), txt)
                n += 1
        except OSError:
            pass
    return n

def run_scenario(conn, scenario_id, *, trigger="cron"):
    sc = store.get_scenario(conn, scenario_id)
    if not sc:
        return {"ok": False, "error": "not found"}
    agent_id = SCENARIO_AGENT_MAP.get(scenario_id) or (sc.get("config") or {}).get("agent_id") or "sentinel"
    fn = checks.SCENARIO_RUNNERS.get(scenario_id)
    if not fn:
        return {"ok": False, "error": "no runner"}
    run_id = store.create_run(conn, scenario_id, trigger)
    store.log_event(conn, event_type="run.start", message=scenario_id, run_id=run_id, agent_id=agent_id)
    raw = fn(conn, ops_api_url=OPS_API, internal_token=TOKEN)
    fids = []
    for f in raw:
        kb = store.search_kb(conn, f.get("title", ""))
        human = f.get("human_action") or ""
        if f.get("severity") in ("high", "critical", "warn"):
            advice, model = llm_client.advise_human_action(
                finding_title=f.get("title",""), finding_detail=f.get("detail_md",""),
                kb_snippets=[k["snippet"] for k in kb],
            )
            if advice and not human: human = advice
        fid = store.add_finding(conn, run_id, severity=f.get("severity", sc.get("severity_default","warn")),
            category=f.get("category","api"), title=f.get("title","Finding"), detail_md=f.get("detail_md",""),
            evidence=f.get("evidence"), human_action=human, kb_refs=[k["source"] for k in kb])
        fids.append(fid)
        if f.get("severity") in ("warn", "high", "critical"):
            inc, notify_ops = store.upsert_incident(
                conn,
                scenario_id=scenario_id,
                finding_id=fid,
                title=f.get("title", "Finding"),
                severity=f.get("severity", "warn"),
                primary_agent=agent_id,
                suggested_human_action=human,
            )
            if notify_ops:
                agent_messages.notify_finding_to_operators(
                    conn,
                    finding_id=fid,
                    scenario_id=scenario_id,
                    title=f.get("title", "Finding"),
                    severity=f.get("severity", "warn"),
                    human_action=human,
                    agent_id=agent_id,
                    thread_id=inc.get("thread_id"),
                )
        if f.get("severity") in ("high", "critical"):
            notify.notify_finding({**f, "suggested_human_action": human})
        store.log_event(conn, event_type="finding.created", message=f.get("title",""), run_id=run_id, payload={"id": fid}, agent_id=agent_id)
    status = "ok" if not raw else "degraded"
    store.finish_run(conn, run_id, status=status, summary=f"{len(raw)} finding(s)" if raw else "healthy")
    store.log_event(conn, event_type="run.finish", message=status, run_id=run_id, agent_id=agent_id)
    if not raw:
        store.resolve_incidents_for_scenario(conn, scenario_id)
    conn.commit()
    return {"ok": True, "run_id": run_id, "scenario_id": scenario_id, "status": status, "findings_count": len(raw), "finding_ids": fids}

def run_all_enabled(conn, trigger="cron"):
    sync_registry(conn)
    return {"runs": [run_scenario(conn, s["id"], trigger=trigger) for s in store.list_scenarios(conn)],
            "total": len(store.list_scenarios(conn))}
