"use client";

import { useEffect, useMemo, useState } from "react";
import { useRouter } from "next/navigation";
import { StatusPill } from "../../components/admin/admin-page.jsx";
import {
  STATUS_TONES,
  STATUS_LABELS,
  EXEC_STATUS_TONES,
  TERMINAL_CASE_STATES,
} from "../../../lib/process/status-tokens.js";

function fmtTime(iso) {
  if (!iso) return '—';
  return new Date(iso).toLocaleString();
}

function executionsByStage(executions) {
  const map = new Map();
  for (const e of executions) {
    const list = map.get(e.stage_slug) || [];
    list.push(e);
    map.set(e.stage_slug, list);
  }
  return map;
}

// Artifact bodies come from `/api/artifacts/[id]/raw` so the polling JSON
// payload stays metadata-only. The iframe fetches once per artifact id and
// the browser caches it for the document lifetime.
function ArtifactCard({ artifact }) {
  if (!artifact) return null;
  const isHtml = artifact.kind === 'html';
  return (
    <li className="case-artifact-card">
      <div className="case-artifact-card-meta">
        <span className="case-artifact-title">{artifact.title || artifact.path}</span>
        <span className="muted"> · {artifact.kind}</span>
      </div>
      {isHtml ? (
        <iframe
          title={artifact.title || artifact.id}
          src={`/api/artifacts/${artifact.id}/raw`}
          sandbox="allow-scripts"
          loading="lazy"
        />
      ) : null}
    </li>
  );
}

function IntakeArtifactFrame({ title, label, artifact, helpText }) {
  const isHtml = artifact?.kind === 'html';
  return (
    <div className="intake-artifact-card">
      <header>
        <h4>{label}</h4>
        <span className="muted">{artifact?.title || ''}</span>
      </header>
      {isHtml ? (
        <iframe
          title={title}
          src={`/api/artifacts/${artifact.id}/raw`}
          sandbox="allow-scripts"
          loading="lazy"
        />
      ) : (
        <p className="muted">Artifact content unavailable.</p>
      )}
      {helpText ? <small className="muted">{helpText}</small> : null}
    </div>
  );
}

function IntakeStagePanel({ caseRow, artifacts, latestExec }) {
  const intakeFormArtifactId = caseRow?.context?.intake_form_artifact_id;
  const execArtifactIds = latestExec?.artifact_ids || [];
  // Form artifact = the artifact-style intake webpage created at case start.
  const formArtifact = artifacts.find((a) => a.id === intakeFormArtifactId);
  // Submission artifact = receipt of the submitted payload (PII redacted).
  const submissionArtifact = artifacts.find(
    (a) => execArtifactIds.includes(a.id) && a.id !== intakeFormArtifactId,
  );

  return (
    <>
      {formArtifact ? (
        <IntakeArtifactFrame
          title="Intake form artifact"
          label="Intake form artifact"
          artifact={formArtifact}
          helpText="Artifact-first intake page · canonical presentation record for this case."
        />
      ) : null}

      {!caseRow.intake_payload ? (
        <p>
          Intake form not submitted yet. Submit via{' '}
          <a href={`/workflows/new/${caseRow.id}`}>the intake page</a>{' '}
          for this case.
        </p>
      ) : null}

      {submissionArtifact ? (
        <IntakeArtifactFrame
          title="Intake submission"
          label="Intake submission"
          artifact={submissionArtifact}
          helpText="Sensitive identifiers (passport / national IDs) are redacted in this artifact."
        />
      ) : null}

      {caseRow.intake_payload ? (
        <details className="payload-card">
          <summary>Raw intake payload (engine state)</summary>
          <pre>{JSON.stringify(caseRow.intake_payload, null, 2)}</pre>
        </details>
      ) : null}
    </>
  );
}

function CaseArtifactGallery({ artifacts }) {
  if (!artifacts || artifacts.length === 0) return null;
  return (
    <section className="case-artifacts-gallery">
      <h3>Case artifacts</h3>
      <p className="muted">
        Every workflow touchpoint is rendered as an HTML artifact. These artifacts
        are also visible in the project library.
      </p>
      <ul className="case-artifact-list">
        {artifacts.map((a) => <ArtifactCard key={a.id} artifact={a} />)}
      </ul>
    </section>
  );
}

export default function CaseDetailClient({ caseRow: initialCase, definition, stages, executions: initialExecutions, approvals: initialApprovals, artifacts: initialArtifacts }) {
  const router = useRouter();
  const [caseRow, setCaseRow] = useState(initialCase);
  const [executions, setExecutions] = useState(initialExecutions);
  const [approvals, setApprovals] = useState(initialApprovals);
  const [artifacts, setArtifacts] = useState(initialArtifacts);
  const [activeStageSlug, setActiveStageSlug] = useState(caseRow.current_stage_slug || stages[0]?.slug);
  const [busy, setBusy] = useState(false);
  const [error, setError] = useState(null);

  // Light polling — 4s — when case is in an active state. Stops once terminal.
  useEffect(() => {
    if (TERMINAL_CASE_STATES.has(caseRow.status)) return;
    let cancelled = false;
    const tick = async () => {
      try {
        const res = await fetch(`/api/processes/${caseRow.id}`);
        if (!res.ok) return;
        const data = await res.json();
        if (cancelled) return;
        setCaseRow(data.case);
        setExecutions(data.executions || []);
        setApprovals(data.approvals || []);
        setArtifacts(data.artifacts || []);
        if (data.case?.current_stage_slug) setActiveStageSlug(data.case.current_stage_slug);
      } catch { /* observation only */ }
    };
    const id = setInterval(tick, 4000);
    return () => { cancelled = true; clearInterval(id); };
  }, [caseRow.id, caseRow.status]);

  const execByStage = useMemo(() => executionsByStage(executions), [executions]);
  const activeStage = useMemo(
    () => stages.find((s) => s.slug === activeStageSlug) || stages[0],
    [stages, activeStageSlug],
  );

  async function approve(approvalId) {
    setBusy(true);
    setError(null);
    try {
      const res = await fetch(`/api/approvals/${approvalId}`, {
        method: 'PATCH',
        headers: { 'content-type': 'application/json' },
        body: JSON.stringify({ decision: 'approved' }),
      });
      if (!res.ok) {
        const j = await res.json().catch(() => ({}));
        throw new Error(j?.error || 'approve failed');
      }
    } catch (err) {
      setError(err?.message || String(err));
    } finally {
      setBusy(false);
    }
  }

  async function deny(approvalId) {
    setBusy(true);
    setError(null);
    try {
      const res = await fetch(`/api/approvals/${approvalId}`, {
        method: 'PATCH',
        headers: { 'content-type': 'application/json' },
        body: JSON.stringify({ decision: 'denied' }),
      });
      if (!res.ok) {
        const j = await res.json().catch(() => ({}));
        throw new Error(j?.error || 'deny failed');
      }
    } catch (err) {
      setError(err?.message || String(err));
    } finally {
      setBusy(false);
    }
  }

  async function retryStage(stageId) {
    setBusy(true);
    setError(null);
    try {
      const res = await fetch(`/api/processes/${caseRow.id}/stages/${stageId}/retry`, { method: 'POST' });
      if (!res.ok) {
        const j = await res.json().catch(() => ({}));
        throw new Error(j?.error || 'retry failed');
      }
    } catch (err) {
      setError(err?.message || String(err));
    } finally {
      setBusy(false);
    }
  }

  async function cancelCase() {
    if (!confirm('Cancel this case?')) return;
    setBusy(true);
    try {
      const res = await fetch(`/api/processes/${caseRow.id}`, {
        method: 'PATCH',
        headers: { 'content-type': 'application/json' },
        body: JSON.stringify({ status: 'cancelled' }),
      });
      if (!res.ok) {
        const j = await res.json().catch(() => ({}));
        throw new Error(j?.error || 'cancel failed');
      }
      router.refresh();
    } catch (err) {
      setError(err?.message || String(err));
    } finally {
      setBusy(false);
    }
  }

  const activeExecs = execByStage.get(activeStage?.slug) || [];
  const latestExec = activeExecs[activeExecs.length - 1];
  const pendingApproval = approvals.find(
    (a) => a.status === 'pending' && a.payload?.stage_slug === activeStage?.slug
  );

  return (
    <div className="case-detail" data-page="case">
      <header className="case-header">
        <StatusPill tone={STATUS_TONES[caseRow.status] || 'neutral'}>
          {STATUS_LABELS[caseRow.status] || caseRow.status}
        </StatusPill>
        <div className="case-header-meta">
          <span className="muted">Project: {caseRow.project_id}</span>
          <span className="muted">Updated: {fmtTime(caseRow.updated_at)}</span>
        </div>
        {!TERMINAL_CASE_STATES.has(caseRow.status) ? (
          <button className="btn-tertiary" onClick={cancelCase} disabled={busy}>Cancel case</button>
        ) : null}
      </header>

      {error ? <p className="form-error" role="alert">{error}</p> : null}

      <div className="case-grid">
        <aside className="case-timeline">
          <h3>Stages</h3>
          <ol>
            {stages.map((stage) => {
              const execs = execByStage.get(stage.slug) || [];
              const last = execs[execs.length - 1];
              const isActive = stage.slug === activeStage?.slug;
              const isCurrent = stage.slug === caseRow.current_stage_slug;
              const status = last?.status || (isCurrent ? 'running' : 'pending');
              return (
                <li
                  key={stage.id}
                  className={`stage-node ${isActive ? 'active' : ''} ${isCurrent ? 'current' : ''}`}
                  data-status={status}
                >
                  <button type="button" onClick={() => setActiveStageSlug(stage.slug)}>
                    <span className="stage-name">{stage.name}</span>
                    <span className="stage-kind muted">{stage.kind.replace('_', ' ')}</span>
                    <StatusPill tone={EXEC_STATUS_TONES[status] || 'neutral'}>{status}</StatusPill>
                  </button>
                </li>
              );
            })}
          </ol>
        </aside>

        <section className="case-stage-panel">
          {activeStage ? (
            <>
              <header>
                <h3>{activeStage.name}</h3>
                <span className="muted">{activeStage.kind}</span>
              </header>

              {activeStage.kind === 'intake_form' ? (
                <IntakeStagePanel
                  caseRow={caseRow}
                  artifacts={artifacts}
                  latestExec={latestExec}
                />
              ) : null}

              {activeStage.kind === 'human_approval' && pendingApproval ? (
                <div className="approval-card">
                  <p><strong>Approval requested:</strong> {pendingApproval.summary}</p>
                  <div className="approval-actions">
                    <button className="btn-primary" onClick={() => approve(pendingApproval.id)} disabled={busy}>
                      Approve
                    </button>
                    <button className="btn-danger" onClick={() => deny(pendingApproval.id)} disabled={busy}>
                      Deny
                    </button>
                  </div>
                  <small className="muted">
                    Risk: {pendingApproval.risk} · created {fmtTime(pendingApproval.created_at)}
                  </small>
                </div>
              ) : null}

              {latestExec ? (
                <div className="exec-card">
                  <header>
                    <h4>Latest execution</h4>
                    <StatusPill tone={EXEC_STATUS_TONES[latestExec.status] || 'neutral'}>
                      {latestExec.status}
                    </StatusPill>
                    {latestExec.attempt > 1 ? <span className="muted">Attempt {latestExec.attempt}</span> : null}
                  </header>
                  {latestExec.output ? (
                    <details open>
                      <summary>Structured output</summary>
                      <pre>{JSON.stringify(latestExec.output, null, 2)}</pre>
                    </details>
                  ) : null}
                  {latestExec.error ? <p className="form-error">Error: {latestExec.error}</p> : null}
                  {latestExec.status === 'fail' ? (
                    <button className="btn-secondary" onClick={() => retryStage(activeStage.id)} disabled={busy}>
                      Retry stage
                    </button>
                  ) : null}
                </div>
              ) : (
                <p className="muted">No execution recorded yet.</p>
              )}

              {artifacts.length && (latestExec?.artifact_ids?.length || activeStage.kind === 'package') ? (
                <div className="artifacts-card">
                  <h4>Stage artifacts</h4>
                  <ul>
                    {artifacts
                      .filter((a) => (latestExec?.artifact_ids || []).includes(a.id))
                      .map((a) => (
                        <li key={a.id}>
                          <span className="case-artifact-title">{a.title || a.path}</span>
                          <span className="muted"> · {a.kind}</span>
                        </li>
                      ))}
                  </ul>
                </div>
              ) : null}
            </>
          ) : (
            <p>Pick a stage from the timeline.</p>
          )}
        </section>
      </div>

      <CaseArtifactGallery artifacts={artifacts} />
    </div>
  );
}
