"""EDA Agent FastAPI Application Entry Point."""
from contextlib import asynccontextmanager

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import HTMLResponse

from eda_agent.api.agent import router as eda_agent_router
from eda_agent.api.deps_auth import RequireInternalToken
from eda_agent.config import settings
from eda_agent.db.connection import close_db, init_db


@asynccontextmanager
async def lifespan(app: FastAPI):
    """Application lifespan events."""
    await init_db()
    yield
    await close_db()


app = FastAPI(
    title="AIF EDA Agent API",
    description="EDA Agent Runtime Service",
    version="0.1.0",
    lifespan=lifespan,
)

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

app.include_router(eda_agent_router, prefix="/api/v1", dependencies=[RequireInternalToken])


@app.get("/")
async def root():
    return {"name": "AIF EDA Agent", "version": "0.1.0", "status": "running"}


@app.get("/health")
async def health():
    return {"status": "healthy", "database": "connected"}


@app.get("/dashboard", response_class=HTMLResponse)
async def dashboard():
    return HTMLResponse(
        content="""<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>AIF EDA Dashboard</title>
  <style>
    body { font-family: Arial, sans-serif; margin: 20px; background: #f7f7f7; color: #222; }
    .grid { display: grid; grid-template-columns: 320px 1fr; gap: 16px; }
    .card { background: white; border-radius: 10px; padding: 14px; box-shadow: 0 1px 4px rgba(0,0,0,.08); margin-bottom: 12px; }
    h2, h3, h4 { margin-top: 0; }
    ul { padding-left: 16px; margin: 0; }
    li { margin: 6px 0; cursor: pointer; }
    li:hover { text-decoration: underline; }
    .muted { color: #666; font-size: 13px; }
    pre { background: #111; color: #f1f1f1; padding: 10px; border-radius: 8px; overflow: auto; max-height: 280px; }
    .row { display: flex; gap: 8px; align-items: center; margin-bottom: 8px; }
    button { padding: 6px 10px; border-radius: 6px; border: 1px solid #ccc; cursor: pointer; background: #fff; }
    .ok { color: #0a7; font-weight: bold; }
    .fail { color: #d33; font-weight: bold; }
    .kpis { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; margin-bottom: 12px; }
    .kpi { border: 1px solid #eee; border-radius: 8px; padding: 10px; background: #fafafa; }
    .kpi .label { font-size: 12px; color: #555; }
    .kpi .value { font-size: 20px; font-weight: bold; margin-top: 6px; }
    .stage-list { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 8px; }
    .stage-pill { background: #eef3ff; border: 1px solid #d8e3ff; border-radius: 999px; padding: 4px 8px; font-size: 12px; }
    .timeline { margin-top: 8px; border-left: 2px solid #e3e3e3; padding-left: 10px; }
    .timeline-item { margin: 8px 0; padding: 6px 8px; background: #fcfcfc; border: 1px solid #eee; border-radius: 6px; }
    .timeline-item .head { font-size: 13px; font-weight: bold; display: flex; justify-content: space-between; }
    .timeline-item .meta { font-size: 12px; color: #666; margin-top: 2px; }
    details { margin-top: 10px; }
    summary { cursor: pointer; color: #333; }
  </style>
</head>
<body>
  <h2>AIF EDA Runtime Dashboard</h2>
  <p class="muted">Business view first, raw JSON second.</p>
  <div class="row">
    <button onclick="loadAgents()">Refresh</button>
    <span id="status" class="muted"></span>
  </div>
  <div class="grid">
    <div class="card">
      <h3>Agents</h3>
      <ul id="agents"></ul>
    </div>
    <div class="card">
      <h3 id="title">Agent Overview</h3>
      <div id="summary" class="muted">Select an agent.</div>
      <div class="kpis">
        <div class="kpi">
          <div class="label">Beliefs</div>
          <div class="value" id="kpi-beliefs">-</div>
        </div>
        <div class="kpi">
          <div class="label">Norm Bindings</div>
          <div class="value" id="kpi-bindings">-</div>
        </div>
        <div class="kpi">
          <div class="label">Last Execute</div>
          <div class="value" id="kpi-execute">-</div>
        </div>
        <div class="kpi">
          <div class="label">Recent Failure</div>
          <div class="value" id="kpi-failure">-</div>
        </div>
      </div>

      <div class="card" style="box-shadow:none;border:1px solid #eee;">
        <h4>Compliance Snapshot</h4>
        <div id="compliance" class="muted">No execution data yet.</div>
        <div id="stages" class="stage-list"></div>
      </div>

      <div class="card" style="box-shadow:none;border:1px solid #eee;">
        <h4>Recent Timeline</h4>
        <div id="timeline" class="timeline muted">No trace timeline yet.</div>
      </div>

      <details open>
        <summary>Raw State JSON</summary>
        <pre id="state"></pre>
      </details>
      <details open>
        <summary>Recent Traces JSON</summary>
        <pre id="traces"></pre>
      </details>
    </div>
  </div>
  <script>
    let selected = null;
    function setText(id, value) {
      document.getElementById(id).textContent = value;
    }
    function setHtml(id, value) {
      document.getElementById(id).innerHTML = value;
    }

    function getLastTraceByStage(traces, stagePrefix) {
      if (!Array.isArray(traces)) return null;
      return traces.find(t => (t.stage || "").startsWith(stagePrefix)) || null;
    }

    function renderStagePills(traces) {
      const stages = (traces || []).map(t => t.stage);
      const uniq = [...new Set(stages)];
      const box = document.getElementById("stages");
      box.innerHTML = "";
      uniq.forEach(s => {
        const el = document.createElement("span");
        el.className = "stage-pill";
        el.textContent = s;
        box.appendChild(el);
      });
    }

    function renderBusinessView(state, traces) {
      const beliefsCount = Object.keys(state.beliefs || {}).length;
      const bindingCount = (state.norm_bindings || []).length;
      setText("kpi-beliefs", String(beliefsCount));
      setText("kpi-bindings", String(bindingCount));

      const exec = getLastTraceByStage(traces, "execute");
      if (exec && exec.result_payload) {
        const success = exec.result_payload.success === true;
        setHtml("kpi-execute", success ? '<span class="ok">PASS</span>' : '<span class="fail">FAIL</span>');
        const c = exec.result_payload.compliance || {};
        const hard = (c.hard_boundary_violations || []).length;
        const soft = (c.soft_boundary_violations || []).length;
        const flex = (c.flexible_boundary_violations || []).length;
        setText("compliance", `approved=${!!c.approved} | hard=${hard} | soft=${soft} | flexible=${flex}`);
      } else {
        setText("kpi-execute", "-");
        setText("compliance", "No execution data yet.");
      }

      const failed = getLastTraceByStage(traces, "bind_norms_failed");
      if (failed) {
        const reason = (failed.result_payload && failed.result_payload.error) || "unknown";
        setHtml("kpi-failure", '<span class="fail">YES</span>');
        const brief = reason.length > 80 ? reason.slice(0, 80) + "..." : reason;
        setText("summary", `Recent upstream failure: ${brief}`);
      } else {
        setHtml("kpi-failure", '<span class="ok">NO</span>');
        setText("summary", `role=${state.agent_role} | trust=${state.trust_score} | active_fields=${(state.active_fields || []).length}`);
      }

      renderStagePills(traces);
      renderTimeline(traces);
    }

    function renderTimeline(traces) {
      const box = document.getElementById("timeline");
      if (!Array.isArray(traces) || traces.length === 0) {
        box.className = "timeline muted";
        box.textContent = "No trace timeline yet.";
        return;
      }
      const ordered = [...traces].reverse();
      box.className = "timeline";
      box.innerHTML = ordered.map(t => {
        const stage = t.stage || "unknown";
        const ms = t.latency_ms == null ? "-" : `${t.latency_ms}ms`;
        const at = t.created_at ? new Date(t.created_at).toLocaleString() : "-";
        const rp = t.result_payload || {};
        const result =
          rp.success === true ? "PASS" :
          rp.success === false ? "FAIL" :
          (rp.selected ? "SELECTED" : "DONE");
        return `
          <div class="timeline-item">
            <div class="head"><span>${stage}</span><span>${result}</span></div>
            <div class="meta">latency=${ms} | at=${at}</div>
          </div>
        `;
      }).join("");
    }

    async function loadAgents() {
      const status = document.getElementById('status');
      status.textContent = 'Loading agents...';
      try {
        const res = await fetch('/api/v1/agents');
        const data = await res.json();
        const ul = document.getElementById('agents');
        ul.innerHTML = '';
        if (!Array.isArray(data) || data.length === 0) {
          ul.innerHTML = '<li class="muted">No agents found.</li>';
          status.innerHTML = '<span class="fail">No agent data</span>';
          return;
        }
        data.forEach(agent => {
          const li = document.createElement('li');
          li.textContent = `${agent.agent_id} (${agent.agent_role})`;
          li.onclick = () => loadAgentDetail(agent.agent_id);
          ul.appendChild(li);
        });
        status.innerHTML = '<span class="ok">Loaded</span>';
        if (!selected) loadAgentDetail(data[0].agent_id);
      } catch (e) {
        status.innerHTML = '<span class="fail">Failed to load agents</span>';
      }
    }
    async function loadAgentDetail(agentId) {
      selected = agentId;
      document.getElementById('title').textContent = `Agent Overview: ${agentId}`;
      try {
        const [stateRes, traceRes] = await Promise.all([
          fetch(`/api/v1/agents/${agentId}`),
          fetch(`/api/v1/agents/${agentId}/traces?limit=20`)
        ]);
        const state = await stateRes.json();
        const traces = await traceRes.json();
        renderBusinessView(state, traces);
        document.getElementById('state').textContent = JSON.stringify(state, null, 2);
        document.getElementById('traces').textContent = JSON.stringify(traces, null, 2);
      } catch (e) {
        document.getElementById('summary').textContent = 'Failed to load agent detail.';
      }
    }
    loadAgents();
    setInterval(() => { if (selected) loadAgentDetail(selected); }, 10000);
  </script>
</body>
</html>"""
    )


if __name__ == "__main__":
    import uvicorn

    uvicorn.run(
        "eda_agent.main:app",
        host=settings.eda_api_host,
        port=settings.eda_api_port,
        reload=settings.eda_api_debug,
    )

