from __future__ import annotations

from fastapi import APIRouter, Request
from fastapi.responses import HTMLResponse, RedirectResponse

from grantflow.api.security import api_key_configured, _api_key_claims  # noqa: WPS450

ui_router = APIRouter(tags=["ui"])

_LOGIN_HTML = """<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>GrantFlow — Sign in</title>
<style>
  *{box-sizing:border-box;margin:0;padding:0}
  body{font-family:system-ui,sans-serif;background:#f4f5f7;display:flex;
       align-items:center;justify-content:center;min-height:100vh}
  .card{background:#fff;border-radius:10px;box-shadow:0 1px 4px rgba(0,0,0,.12);
        padding:32px 28px;width:340px}
  h1{font-size:1.1rem;font-weight:700;color:#0d47a1;margin-bottom:20px}
  label{display:block;font-size:.85rem;font-weight:600;color:#444;margin-bottom:6px}
  input{width:100%;padding:8px 10px;border:1px solid #ccc;border-radius:6px;
        font-size:.9rem;font-family:monospace}
  button{margin-top:16px;width:100%;padding:10px;background:#0d47a1;color:#fff;
         border:none;border-radius:6px;font-size:.9rem;font-weight:600;cursor:pointer}
  button:hover{background:#0b3d91}
  .err{margin-top:12px;color:#842029;font-size:.82rem;display:none}
</style>
</head>
<body>
<div class="card">
  <h1>GrantFlow HITL Review</h1>
  <form method="get" action="/ui/hitl">
    <label for="k">API Key</label>
    <input id="k" name="api_key" type="password" placeholder="grantflow-..." autocomplete="current-password" required>
    <button type="submit">Sign in</button>
  </form>
  {error_block}
</div>
</body>
</html>"""

_ERROR_BLOCK = '<p class="err" style="display:block">{msg}</p>'


def _ui_credential(request: Request) -> str | None:
    qp = request.query_params.get("api_key", "").strip()
    if qp:
        return qp
    cookie = request.cookies.get("gf_api_key", "").strip()
    return cookie or None


def _ui_auth_check(request: Request) -> str | None:
    """Return error message if auth fails, None if OK."""
    expected = api_key_configured()
    if not expected:
        return None
    provided = _ui_credential(request)
    if not provided or _api_key_claims(provided, expected) is None:
        return "Invalid or missing API key."
    return None


_HITL_HTML = """<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>GrantFlow — HITL Review</title>
<style>
  *{box-sizing:border-box;margin:0;padding:0}
  body{font-family:system-ui,sans-serif;background:#f4f5f7;color:#1a1a2e;padding:24px}
  h1{font-size:1.3rem;font-weight:700;margin-bottom:20px;color:#0d47a1}
  .badge{display:inline-block;padding:2px 8px;border-radius:10px;font-size:.75rem;font-weight:600}
  .badge-pending{background:#fff3cd;color:#856404}
  .badge-approved{background:#d1e7dd;color:#0a5132}
  .badge-rejected{background:#f8d7da;color:#842029}
  .card{background:#fff;border-radius:10px;box-shadow:0 1px 4px rgba(0,0,0,.1);padding:20px;margin-bottom:16px}
  .card-header{display:flex;justify-content:space-between;align-items:flex-start;gap:12px;margin-bottom:12px}
  .card-title{font-weight:700;font-size:1rem}
  .meta{font-size:.8rem;color:#666;margin-top:4px}
  .meta span{margin-right:12px}
  .field{margin-bottom:8px;font-size:.85rem}
  .field label{display:block;font-weight:600;color:#444;margin-bottom:2px}
  .field code{background:#f0f0f0;padding:2px 6px;border-radius:4px;font-size:.8rem;word-break:break-all}
  textarea{width:100%;padding:8px;border:1px solid #ccc;border-radius:6px;font-size:.85rem;
           resize:vertical;min-height:60px;margin-top:8px;font-family:inherit}
  .actions{display:flex;gap:10px;margin-top:12px;flex-wrap:wrap}
  button{padding:8px 18px;border:none;border-radius:6px;font-size:.85rem;font-weight:600;cursor:pointer;transition:.15s}
  .btn-approve{background:#198754;color:#fff}
  .btn-approve:hover{background:#157347}
  .btn-reject{background:#dc3545;color:#fff}
  .btn-reject:hover{background:#bb2d3b}
  .btn-resume{background:#0d6efd;color:#fff}
  .btn-resume:hover{background:#0b5ed7}
  .btn-refresh{background:#6c757d;color:#fff;margin-bottom:16px}
  .btn-refresh:hover{background:#5c636a}
  button:disabled{opacity:.5;cursor:not-allowed}
  .msg{padding:8px 12px;border-radius:6px;font-size:.85rem;margin-top:10px}
  .msg-ok{background:#d1e7dd;color:#0a5132}
  .msg-err{background:#f8d7da;color:#842029}
  .empty{color:#888;font-size:.9rem;padding:20px 0}
  .spinner{display:inline-block;width:16px;height:16px;border:2px solid #ccc;
           border-top-color:#0d47a1;border-radius:50%;animation:spin .6s linear infinite;vertical-align:middle}
  @keyframes spin{to{transform:rotate(360deg)}}
</style>
</head>
<body>
<h1>GrantFlow — HITL Review Queue</h1>
<button class="btn-refresh" onclick="load()">&#8635; Refresh</button>
<div id="root"><span class="spinner"></span></div>

<script>
const API = '';

async function load() {
  const root = document.getElementById('root');
  root.innerHTML = '<span class="spinner"></span>';
  try {
    const key = document.cookie.match(/gf_api_key=([^;]+)/)?.[1] || '';
    const headers = key ? {'X-API-Key': key} : {};
    const res = await fetch(API + '/hitl/pending', {headers});
    const data = await res.json();
    const cps = data.checkpoints || [];
    if (!cps.length) {
      root.innerHTML = '<p class="empty">No pending checkpoints. All caught up.</p>';
      return;
    }
    root.innerHTML = cps.map(cp => cardHTML(cp)).join('');
  } catch(e) {
    root.innerHTML = '<p class="msg msg-err">Failed to load: ' + e.message + '</p>';
  }
}

function cardHTML(cp) {
  const id = cp.checkpoint_id || cp.id || '?';
  const jobId = cp.job_id || '—';
  const stage = cp.stage || '—';
  const donor = cp.donor_id || '—';
  const created = cp.created_at ? new Date(cp.created_at).toLocaleString() : '—';
  const prompt = cp.prompt || '';
  return `<div class="card" id="card-${id}">
    <div class="card-header">
      <div>
        <div class="card-title">${stage} <span class="badge badge-pending">pending</span></div>
        <div class="meta">
          <span>Job: <code>${jobId}</code></span>
          <span>Donor: ${donor}</span>
          <span>${created}</span>
        </div>
      </div>
    </div>
    ${prompt ? `<div class="field"><label>Checkpoint prompt</label><div style="margin-top:4px;font-size:.85rem;white-space:pre-wrap">${esc(prompt)}</div></div>` : ''}
    <div class="field"><label>Checkpoint ID</label><code>${id}</code></div>
    <div class="field"><label>Feedback (optional)</label>
      <textarea id="fb-${id}" placeholder="Add notes for the agent..."></textarea>
    </div>
    <div class="actions">
      <button class="btn-approve" onclick="decide('${id}','${jobId}',true)">Approve</button>
      <button class="btn-reject" onclick="decide('${id}','${jobId}',false)">Reject</button>
    </div>
    <div id="msg-${id}"></div>
  </div>`;
}

function esc(s) {
  return s.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
}

async function decide(checkpointId, jobId, approved) {
  const fb = document.getElementById('fb-' + checkpointId)?.value || '';
  const msgEl = document.getElementById('msg-' + checkpointId);
  const card = document.getElementById('card-' + checkpointId);
  card.querySelectorAll('button').forEach(b => b.disabled = true);
  msgEl.innerHTML = '<span class="spinner"></span> Sending...';

  const key = document.cookie.match(/gf_api_key=([^;]+)/)?.[1] || '';
  const headers = {'Content-Type': 'application/json'};
  if (key) headers['X-API-Key'] = key;

  try {
    const res = await fetch(API + '/hitl/approve', {
      method: 'POST',
      headers,
      body: JSON.stringify({checkpoint_id: checkpointId, approved, feedback: fb || null}),
    });
    const data = await res.json();
    if (!res.ok) {
      const detail = data?.detail?.message || data?.detail || JSON.stringify(data);
      msgEl.innerHTML = '<p class="msg msg-err">Error: ' + detail + '</p>';
      card.querySelectorAll('button').forEach(b => b.disabled = false);
      return;
    }
    const label = approved ? 'approved' : 'rejected';
    msgEl.innerHTML = `<p class="msg msg-ok">Checkpoint ${label}.</p>`;
    card.querySelector('.badge').className = 'badge badge-' + label;
    card.querySelector('.badge').textContent = label;

    if (approved && jobId && jobId !== '—') {
      const resumeBtn = document.createElement('button');
      resumeBtn.className = 'btn-resume';
      resumeBtn.textContent = 'Resume job';
      resumeBtn.onclick = () => resumeJob(jobId, resumeBtn, msgEl);
      card.querySelector('.actions').appendChild(resumeBtn);
    }
  } catch(e) {
    msgEl.innerHTML = '<p class="msg msg-err">Network error: ' + e.message + '</p>';
    card.querySelectorAll('button').forEach(b => b.disabled = false);
  }
}

async function resumeJob(jobId, btn, msgEl) {
  btn.disabled = true;
  const key = document.cookie.match(/gf_api_key=([^;]+)/)?.[1] || '';
  const headers = {'Content-Type': 'application/json'};
  if (key) headers['X-API-Key'] = key;
  try {
    const res = await fetch(API + '/resume/' + jobId, {method: 'POST', headers, body: '{}'});
    const data = await res.json();
    if (!res.ok) {
      const detail = data?.detail?.message || data?.detail || JSON.stringify(data);
      msgEl.innerHTML += '<p class="msg msg-err">Resume failed: ' + detail + '</p>';
      btn.disabled = false;
      return;
    }
    msgEl.innerHTML += '<p class="msg msg-ok">Job resumed. Poll GET /status/' + jobId + ' for progress.</p>';
  } catch(e) {
    msgEl.innerHTML += '<p class="msg msg-err">Network error: ' + e.message + '</p>';
    btn.disabled = false;
  }
}

load();
</script>
</body>
</html>"""


@ui_router.get("/ui/hitl", response_class=HTMLResponse, include_in_schema=False, response_model=None)
def hitl_review_ui(request: Request):
    error = _ui_auth_check(request)
    if error:
        expected = api_key_configured()
        if expected and request.query_params.get("api_key", "").strip():
            body = _LOGIN_HTML.replace("{error_block}", _ERROR_BLOCK.format(msg=error))
        else:
            body = _LOGIN_HTML.replace("{error_block}", "")
        return HTMLResponse(content=body, status_code=401)

    qp_key = request.query_params.get("api_key", "").strip()
    if qp_key:
        response = RedirectResponse(url="/ui/hitl", status_code=302)
        response.set_cookie("gf_api_key", qp_key, httponly=False, samesite="strict")
        return response

    return HTMLResponse(content=_HITL_HTML)
