// Task detail modal — opens when any task card is clicked.
// Tabs: "Details" (description, objective, files, subtasks, acceptance) and
// "History" (every event in the task's progression — assignments, submissions,
// rejections, approvals — with iteration numbers and snapshots of the work
// state at each point).

const { useEffect: useEffectModal, useState: useStateModal, useMemo: useMemoModal } = React;

// SourceChip is defined in task-card.jsx and exported on window.
const SourceChip = window.SourceChip;
const StationFlow = window.StationFlow;

const BigCheck = ({ done, onToggle, actor = "agent", disabled = false, label }) => {
  const ringColor = actor === "validator"
    ? "border-amber-300 group-hover:border-amber-500"
    : "border-indigo-300 group-hover:border-indigo-500";
  return (
    <button
      type="button"
      onClick={disabled ? undefined : onToggle}
      aria-pressed={done}
      aria-label={label}
      className={`group shrink-0 w-9 h-9 rounded-full flex items-center justify-center transition-all border-[3px] ${
        done
          ? "bg-emerald-500 border-emerald-500 text-white shadow-md shadow-emerald-500/20"
          : `bg-white ${ringColor} ${disabled ? "opacity-60 cursor-not-allowed" : "hover:scale-105"}`
      }`}
    >
      {done && <CheckCircle size={20} strokeWidth={3} />}
    </button>
  );
};

const StatusPill = ({ status }) => {
  const map = {
    queue:         { label: "Queue",         cls: "bg-neutral-100 text-neutral-700 border-neutral-300" },
    working:       { label: "Working",       cls: "bg-indigo-100 text-indigo-700 border-indigo-300" },
    validating:    { label: "Validating",    cls: "bg-amber-100 text-amber-700 border-amber-300" },
    "human-review":{ label: "Human Review",  cls: "bg-orange-100 text-orange-800 border-orange-300" },
    rejected:      { label: "Rejected",      cls: "bg-red-100 text-red-700 border-red-300" },
    shipped:       { label: "Shipped",       cls: "bg-emerald-100 text-emerald-700 border-emerald-300" },
  };
  const meta = map[status] || map.queue;
  return (
    <span className={`inline-flex items-center text-[11px] font-bold uppercase tracking-[0.18em] px-3 py-1.5 rounded-full border-2 ${meta.cls}`}>
      {meta.label}
    </span>
  );
};

// Phase metadata — color, icon, verb. Drives the timeline dot + label.
const PHASE_META = {
  created:      { label: "Created",      color: "neutral", dot: "bg-neutral-400" },
  assigned:     { label: "Assigned",     color: "indigo",  dot: "bg-indigo-500" },
  working:      { label: "Working",      color: "indigo",  dot: "bg-indigo-500" },
  submitted:    { label: "Submitted",    color: "amber",   dot: "bg-amber-500" },
  rejected:     { label: "Rejected",     color: "red",     dot: "bg-red-500" },
  approved:     { label: "Approved",     color: "emerald", dot: "bg-emerald-500" },
  shipped:      { label: "Shipped",      color: "emerald", dot: "bg-emerald-500" },
  'routed-back':{ label: "Routed Back", color: "amber",   dot: "bg-amber-600" },
};

const phaseRing = (color) => ({
  neutral: "border-neutral-200 bg-neutral-50",
  indigo: "border-indigo-200 bg-indigo-50/40",
  amber: "border-amber-200 bg-amber-50/40",
  red: "border-red-200 bg-red-50/40",
  emerald: "border-emerald-200 bg-emerald-50/40",
}[color] || "border-neutral-200 bg-neutral-50");

const phaseText = (color) => ({
  neutral: "text-neutral-700",
  indigo: "text-indigo-700",
  amber: "text-amber-700",
  red: "text-red-700",
  emerald: "text-emerald-700",
}[color] || "text-neutral-700");

// Group events by iteration so the user can clearly see "iteration 1 was
// rejected, iteration 2 is current".
const groupByIteration = (events) => {
  const groups = new Map();
  for (const ev of events) {
    const it = ev.iteration || 1;
    if (!groups.has(it)) groups.set(it, []);
    groups.get(it).push(ev);
  }
  return [...groups.entries()].map(([iteration, evs]) => ({ iteration, events: evs }));
};

const TimelineEvent = ({ ev, isLast }) => {
  const meta = PHASE_META[ev.phase] || PHASE_META.created;
  return (
    <li className="relative pl-12 pb-6">
      {!isLast && <span className="absolute left-[19px] top-7 bottom-0 w-0.5 bg-neutral-200" />}
      <span className={`absolute left-[0.65rem] top-[0.1rem] w-5 h-5 rounded-full ${meta.dot} ring-4 ring-white shadow-sm`} />
      <div className={`border-2 rounded-xl p-4 ${phaseRing(meta.color)}`}>
        <div className="flex items-center justify-between gap-3 flex-wrap mb-1">
          <div className="flex items-center gap-2 flex-wrap">
            <span className={`text-[10px] font-bold uppercase tracking-[0.18em] ${phaseText(meta.color)}`}>{meta.label}</span>
            {ev.station && <span className="text-[10px] font-bold uppercase tracking-widest text-neutral-400">· {ev.station}</span>}
          </div>
          <span className="text-[11px] font-medium text-neutral-400">{ev.when}</span>
        </div>
        {ev.actor && (
          <div className="flex items-center gap-2 mb-1.5">
            <div className={`w-6 h-6 rounded-full text-white text-[10px] font-bold flex items-center justify-center ${
              meta.color === "amber" ? "bg-amber-500" :
              meta.color === "red" ? "bg-red-500" :
              meta.color === "emerald" ? "bg-emerald-500" :
              "bg-indigo-500"
            }`}>{ev.actor.name.charAt(0)}</div>
            <span className="text-sm font-bold text-neutral-900">{ev.actor.name}</span>
            {ev.actor.role && ev.actor.role !== ev.actor.name && (
              <span className="text-xs text-neutral-500 font-medium">· {ev.actor.role}</span>
            )}
          </div>
        )}
        <p className="text-sm text-neutral-800 leading-snug">{ev.message}</p>
        {ev.feedback && (
          <div className="mt-3 p-3 rounded-lg bg-red-50 border border-red-200">
            <div className="text-[10px] font-bold uppercase tracking-widest text-red-700 mb-1">Validator feedback</div>
            <p className="text-sm text-red-900 leading-snug">{ev.feedback}</p>
          </div>
        )}
        {ev.snapshot && (ev.snapshot.subtasks || ev.snapshot.acceptance) && (
          <details className="mt-3">
            <summary className="text-[11px] font-bold uppercase tracking-widest text-neutral-500 cursor-pointer hover:text-neutral-800 select-none">
              Work snapshot at this point
            </summary>
            <div className="mt-2 grid grid-cols-1 sm:grid-cols-2 gap-3">
              {ev.snapshot.subtasks && (
                <div className="bg-white rounded-lg border border-neutral-200 p-3">
                  <div className="text-[10px] font-bold uppercase tracking-widest text-indigo-700 mb-1.5">SubTasks</div>
                  <ul className="flex flex-col gap-1">
                    {ev.snapshot.subtasks.map((s) => (
                      <li key={s.id} className="flex items-center gap-2 text-xs">
                        <span className={`w-3.5 h-3.5 rounded-full border-2 shrink-0 ${s.done ? "bg-emerald-500 border-emerald-500" : "bg-white border-neutral-300"}`} />
                        <span className={s.done ? "text-neutral-500 line-through" : "text-neutral-800"}>{s.text}</span>
                      </li>
                    ))}
                  </ul>
                </div>
              )}
              {ev.snapshot.acceptance && (
                <div className="bg-white rounded-lg border border-neutral-200 p-3">
                  <div className="text-[10px] font-bold uppercase tracking-widest text-amber-700 mb-1.5">Acceptance</div>
                  <ul className="flex flex-col gap-1">
                    {ev.snapshot.acceptance.map((a) => (
                      <li key={a.id} className="flex items-center gap-2 text-xs">
                        <span className={`w-3.5 h-3.5 rounded-full border-2 shrink-0 ${a.done ? "bg-emerald-500 border-emerald-500" : "bg-white border-neutral-300"}`} />
                        <span className={a.done ? "text-neutral-500 line-through" : "text-neutral-800"}>{a.text}</span>
                      </li>
                    ))}
                  </ul>
                </div>
              )}
            </div>
          </details>
        )}
      </div>
    </li>
  );
};

const HistoryView = ({ task }) => {
  const events = task.events || [];
  const groups = useMemoModal(() => groupByIteration(events), [events]);
  const currentIter = task.iteration || (groups.length ? groups[groups.length - 1].iteration : 1);

  if (events.length === 0) {
    return <p className="text-neutral-400 text-sm italic">No history yet.</p>;
  }
  return (
    <div className="flex flex-col gap-8">
      {groups.map((g) => {
        const isCurrent = g.iteration === currentIter;
        const wasRejected = g.events.some((e) => e.phase === "rejected");
        return (
          <div key={g.iteration} className={`rounded-2xl border-2 p-5 ${isCurrent ? "border-indigo-200 bg-white" : wasRejected ? "border-red-100 bg-red-50/30" : "border-neutral-200 bg-white"}`}>
            <div className="flex items-center justify-between gap-3 mb-4 flex-wrap">
              <div className="flex items-center gap-2">
                <RefreshCw size={16} className={isCurrent ? "text-indigo-600" : wasRejected ? "text-red-500" : "text-neutral-400"} />
                <span className={`text-sm font-black uppercase tracking-[0.18em] ${isCurrent ? "text-indigo-700" : wasRejected ? "text-red-700" : "text-neutral-700"}`}>Iteration {g.iteration}</span>
                {isCurrent && <span className="text-[10px] font-bold uppercase tracking-widest bg-indigo-100 text-indigo-700 px-2 py-0.5 rounded-full border border-indigo-200">Current</span>}
                {!isCurrent && wasRejected && <span className="text-[10px] font-bold uppercase tracking-widest bg-red-100 text-red-700 px-2 py-0.5 rounded-full border border-red-200">Rejected</span>}
              </div>
              <span className="text-xs text-neutral-400 font-medium">{g.events.length} event{g.events.length === 1 ? "" : "s"}</span>
            </div>
            <ul className="relative">
              {g.events.map((ev, idx) => (
                <TimelineEvent key={ev.id} ev={ev} isLast={idx === g.events.length - 1} />
              ))}
            </ul>
          </div>
        );
      })}
    </div>
  );
};

// --- Agent log: developer-tools-style transcript of the agent's run ---
// Three entry kinds:
//   - "thinking"  → italic gray bubble of internal reasoning
//   - "tool"      → labeled chip: tool name + (path | query). For `write`, an
//                   expandable code block with the full new file contents.
//   - "message"   → plain text the agent surfaced (rare; mainly for status pings)
const ToolBadge = ({ tool }) => {
  const map = {
    read:   { bg: "bg-sky-100",    text: "text-sky-700",    border: "border-sky-200" },
    write:  { bg: "bg-emerald-100",text: "text-emerald-700",border: "border-emerald-200" },
    grep:   { bg: "bg-violet-100", text: "text-violet-700", border: "border-violet-200" },
    run:    { bg: "bg-amber-100",  text: "text-amber-700",  border: "border-amber-200" },
  };
  const m = map[tool] || { bg: "bg-neutral-100", text: "text-neutral-700", border: "border-neutral-200" };
  return (
    <span className={`text-[10px] font-bold uppercase tracking-[0.18em] px-2 py-1 rounded-md border ${m.bg} ${m.text} ${m.border}`}>
      {tool}
    </span>
  );
};

const AgentLogEntry = ({ entry }) => {
  const [open, setOpen] = useStateModal(false);

  if (entry.kind === "thinking") {
    return (
      <div className="flex gap-3">
        <div className="shrink-0 w-7 h-7 rounded-full bg-neutral-100 border border-neutral-200 flex items-center justify-center text-neutral-500" aria-hidden>
          <span className="text-[11px] font-bold">✱</span>
        </div>
        <div className="flex-1 min-w-0">
          <div className="text-[10px] font-bold uppercase tracking-[0.18em] text-neutral-400 mb-1">Thinking</div>
          <p className="text-[15px] leading-relaxed text-neutral-700 italic">{entry.text}</p>
        </div>
      </div>
    );
  }

  if (entry.kind === "tool") {
    const isWrite = entry.tool === "write";
    return (
      <div className="flex gap-3">
        <div className="shrink-0 w-7 h-7 rounded-md bg-neutral-900 text-white flex items-center justify-center" aria-hidden>
          <Hammer size={14} />
        </div>
        <div className="flex-1 min-w-0">
          <div className="flex items-center gap-2 mb-1.5 flex-wrap">
            <ToolBadge tool={entry.tool} />
            {entry.path && (
              <code className="text-[13px] font-mono bg-neutral-100 border border-neutral-200 text-neutral-800 px-2 py-0.5 rounded break-all">{entry.path}</code>
            )}
            {entry.query && (
              <span className="text-[13px] font-mono text-neutral-700">
                pattern <code className="bg-neutral-100 border border-neutral-200 px-1.5 py-0.5 rounded">{entry.query}</code>
                {entry.path && <> in <code className="bg-neutral-100 border border-neutral-200 px-1.5 py-0.5 rounded break-all">{entry.path}</code></>}
              </span>
            )}
          </div>
          {isWrite && entry.content && (
            <>
              <button
                onClick={() => setOpen(!open)}
                className="text-[11px] font-bold uppercase tracking-widest text-emerald-700 hover:text-emerald-900 inline-flex items-center gap-1"
              >
                {open ? <ChevronDown size={12} /> : <ChevronRight size={12} />}
                {open ? "Hide contents" : `Show contents (${entry.content.split("\n").length} lines)`}
              </button>
              {open && (
                <pre className="mt-2 bg-neutral-950 text-neutral-100 text-[12.5px] font-mono leading-relaxed rounded-lg p-4 overflow-x-auto border border-neutral-800 whitespace-pre">
{entry.content}
                </pre>
              )}
            </>
          )}
        </div>
      </div>
    );
  }

  // message / fallback
  return (
    <div className="flex gap-3">
      <div className="shrink-0 w-7 h-7 rounded-full bg-indigo-100 border border-indigo-200 text-indigo-700 flex items-center justify-center" aria-hidden>
        <Send size={12} />
      </div>
      <div className="flex-1 min-w-0">
        <p className="text-[15px] leading-relaxed text-neutral-800">{entry.text}</p>
      </div>
    </div>
  );
};

const RunStatusPill = ({ status }) => {
  const map = {
    active:    { label: "Active",     cls: "bg-indigo-100 text-indigo-700 border-indigo-300" },
    approved:  { label: "Approved",   cls: "bg-emerald-100 text-emerald-700 border-emerald-300" },
    submitted: { label: "Submitted",  cls: "bg-amber-100 text-amber-700 border-amber-300" },
    rejected:  { label: "Rejected",   cls: "bg-red-100 text-red-700 border-red-300" },
    completed: { label: "Completed",  cls: "bg-neutral-100 text-neutral-700 border-neutral-300" },
  };
  const m = map[status] || map.completed;
  return (
    <span className={`inline-flex items-center text-[9px] font-bold uppercase tracking-[0.16em] px-1.5 py-0.5 rounded border ${m.cls}`}>
      {m.label}
    </span>
  );
};

const RunPickerItem = ({ run, isSelected, onSelect, index, total }) => {
  const isActive = run.status === "active";
  const initial = run.agent?.name?.charAt(0) || "?";
  const accent =
    run.status === "rejected" ? "red" :
    run.status === "approved" ? "emerald" :
    run.status === "submitted" ? "amber" :
    isActive ? "indigo" : "neutral";
  const avatarBg = {
    red: "bg-red-500",
    emerald: "bg-emerald-500",
    amber: "bg-amber-500",
    indigo: "bg-indigo-500",
    neutral: "bg-neutral-400",
  }[accent];
  return (
    <button
      type="button"
      onClick={onSelect}
      className={`w-full text-left p-3 rounded-xl border-2 transition-all flex gap-3 items-start ${
        isSelected ? "bg-white border-neutral-900 shadow-md" : "bg-white border-neutral-200 hover:border-neutral-300 hover:bg-neutral-50"
      }`}
    >
      <div className={`relative shrink-0 w-9 h-9 rounded-full text-white text-sm font-bold flex items-center justify-center ring-2 ring-white shadow-sm ${avatarBg}`}>
        {initial}
        {isActive && (
          <span className="absolute -bottom-0.5 -right-0.5 w-3 h-3 rounded-full bg-emerald-500 ring-2 ring-white" aria-label="Active run" />
        )}
      </div>
      <div className="min-w-0 flex-1">
        <div className="flex items-center gap-1.5 mb-0.5 flex-wrap">
          <span className="text-sm font-bold text-neutral-900 leading-tight">{run.agent?.name}</span>
          <RunStatusPill status={run.status} />
        </div>
        <div className="text-[11px] font-medium text-neutral-500 leading-tight truncate">
          {run.station}{run.iteration > 1 ? ` · iter ${run.iteration}` : ""}
        </div>
        <div className="text-[10px] text-neutral-400 mt-0.5">
          {run.entries.length} entr{run.entries.length === 1 ? "y" : "ies"} · {run.startedAt}
        </div>
      </div>
    </button>
  );
};

const AgentLogView = ({ runs, initialRunId }) => {
  // Default to the active run if any, else the most recent (last in array).
  const defaultRunId = useMemoModal(() => {
    if (initialRunId && runs.find((r) => r.id === initialRunId)) return initialRunId;
    const active = runs.find((r) => r.status === "active");
    if (active) return active.id;
    return runs[runs.length - 1]?.id;
  }, [runs, initialRunId]);

  const [selectedId, setSelectedId] = useStateModal(defaultRunId);
  // If runs change (e.g. modal reopened on a different task), reset.
  useEffectModal(() => { setSelectedId(defaultRunId); }, [defaultRunId]);

  const selected = runs.find((r) => r.id === selectedId) || runs[0];

  if (!runs || runs.length === 0) {
    return <p className="text-neutral-400 text-sm italic">No agent activity yet.</p>;
  }

  return (
    <div className="grid grid-cols-1 lg:grid-cols-[260px_1fr] gap-6">
      {/* Run picker (left) */}
      <aside className="flex flex-col gap-2">
        <div className="text-[10px] font-bold uppercase tracking-[0.22em] text-neutral-400 mb-1 px-1">
          Agent runs ({runs.length})
        </div>
        {runs.map((run, idx) => (
          <RunPickerItem
            key={run.id}
            run={run}
            index={idx}
            total={runs.length}
            isSelected={run.id === selected?.id}
            onSelect={() => setSelectedId(run.id)}
          />
        ))}
      </aside>

      {/* Transcript (right) */}
      <div className="bg-white border-2 border-neutral-200 rounded-2xl overflow-hidden">
        {selected && (
          <>
            <header className="px-6 py-5 border-b border-neutral-200 bg-gradient-to-b from-white to-neutral-50/60 flex items-center justify-between gap-4 flex-wrap">
              <div className="flex items-center gap-3 min-w-0">
                <div className={`shrink-0 w-10 h-10 rounded-full text-white text-base font-bold flex items-center justify-center ring-2 ring-white shadow-sm ${
                  selected.status === "rejected" ? "bg-red-500" :
                  selected.status === "approved" ? "bg-emerald-500" :
                  selected.status === "submitted" ? "bg-amber-500" :
                  selected.status === "active" ? "bg-indigo-500" : "bg-neutral-400"
                }`}>{selected.agent?.name?.charAt(0)}</div>
                <div className="min-w-0">
                  <div className="flex items-center gap-2 flex-wrap">
                    <span className="text-base font-bold text-neutral-900 leading-tight">{selected.agent?.name}</span>
                    {selected.agent?.role && selected.agent.role !== selected.agent.name && (
                      <span className="text-xs text-neutral-500 font-medium">· {selected.agent?.role}</span>
                    )}
                    <RunStatusPill status={selected.status} />
                  </div>
                  <div className="text-[11px] font-bold uppercase tracking-[0.18em] text-neutral-500 mt-0.5">
                    {selected.station}{selected.iteration > 1 ? ` · iteration ${selected.iteration}` : ""}
                  </div>
                </div>
              </div>
              <div className="text-right text-[11px] font-medium text-neutral-400 shrink-0">
                {selected.startedAt}{selected.endedAt ? ` → ${selected.endedAt}` : " → now"}
              </div>
            </header>
            <ol className="flex flex-col gap-5 p-6">
              {selected.entries.map((entry, idx) => (
                <li key={idx} className="border-b border-neutral-100 pb-5 last:border-b-0 last:pb-0">
                  <AgentLogEntry entry={entry} />
                </li>
              ))}
              {selected.status === "active" && (
                <li className="flex items-center gap-2 text-[11px] font-bold uppercase tracking-[0.18em] text-indigo-600">
                  <span className="relative flex w-2 h-2">
                    <span className="absolute inline-flex h-full w-full rounded-full bg-indigo-400 opacity-75 animate-ping" />
                    <span className="relative inline-flex rounded-full h-2 w-2 bg-indigo-500" />
                  </span>
                  Streaming…
                </li>
              )}
            </ol>
          </>
        )}
      </div>
    </div>
  );
};

// VariantPickerPanel — shows N design variants side-by-side, lets the human pick one.
// Accepts:
//   humanPicker: { status, variants: [{ id, agentName, output, iqDecision, fitDecision }], pickedVariantId }
//   onPickVariant: (variantId) => void  (null when already picked)
const ValidatorBadge = ({ label, decision }) => {
  const cls =
    decision === 'accept' ? 'bg-emerald-50 text-emerald-700 border-emerald-200' :
    decision === 'reject' ? 'bg-red-50 text-red-700 border-red-200' :
    'bg-neutral-100 text-neutral-600 border-neutral-200';
  return (
    <span className={`inline-flex items-center text-[9px] font-bold uppercase tracking-widest px-2 py-0.5 rounded-full border ${cls}`}>
      {label}: {decision ?? '—'}
    </span>
  );
};

const VariantCard = ({ variant, isPicked, canPick, onPick }) => {
  const [showPreview, setShowPreview] = useStateModal(false);
  const hasHtml = typeof variant.output?.html === 'string' && variant.output.html.trim().length > 0;
  const stance = variant.output?.variant_stance || variant.output?.design_notes || '(no stance recorded)';
  const notes = variant.output?.design_notes || '';

  return (
    <div className={`flex flex-col border-2 rounded-2xl overflow-hidden transition-all ${
      isPicked ? 'border-indigo-400 shadow-lg shadow-indigo-100' :
      canPick ? 'border-neutral-200 hover:border-neutral-300' :
      'border-neutral-200'
    }`}>
      {/* Header */}
      <div className={`px-5 py-4 flex items-center justify-between gap-3 ${isPicked ? 'bg-indigo-50' : 'bg-white'}`}>
        <div className="flex items-center gap-3 min-w-0">
          <div className={`w-9 h-9 rounded-full flex items-center justify-center text-sm font-bold ring-2 ring-white ${isPicked ? 'bg-indigo-500 text-white' : 'bg-neutral-200 text-neutral-700'}`}>
            {variant.agentName?.charAt(0) ?? variant.id.toUpperCase()}
          </div>
          <div className="min-w-0">
            <div className="font-bold text-neutral-900 text-sm leading-tight">{variant.agentName}</div>
            <div className="text-[11px] text-neutral-500 font-medium truncate max-w-[220px]">{stance}</div>
          </div>
        </div>
        {isPicked && (
          <span className="text-[10px] font-bold uppercase tracking-widest px-2.5 py-1 rounded-full bg-indigo-500 text-white shrink-0">Picked</span>
        )}
      </div>

      {/* Validator badges */}
      <div className="px-5 py-2.5 bg-neutral-50/60 border-y border-neutral-100 flex items-center gap-2 flex-wrap">
        <ValidatorBadge label="IQ" decision={variant.iqDecision?.decision} />
        <ValidatorBadge label="Fit" decision={variant.fitDecision?.decision} />
        {variant.iqDecision?.summary && (
          <span className="text-[11px] text-neutral-500 truncate max-w-[200px]">{variant.iqDecision.summary}</span>
        )}
      </div>

      {/* Preview toggle */}
      {hasHtml && (
        <div className="px-5 py-2 border-b border-neutral-100">
          <button
            type="button"
            onClick={() => setShowPreview((v) => !v)}
            className="text-[11px] font-bold uppercase tracking-widest text-indigo-600 hover:text-indigo-800"
          >
            {showPreview ? '▼ Hide preview' : '▶ Show HTML preview'}
          </button>
        </div>
      )}
      {showPreview && hasHtml && (
        <div className="bg-white border-b border-neutral-100" style={{ height: 360 }}>
          <iframe
            title={`Preview — ${variant.agentName}`}
            srcDoc={variant.output.html}
            sandbox="allow-scripts"
            className="w-full h-full"
            style={{ border: 'none' }}
          />
        </div>
      )}

      {/* Design notes */}
      {notes && (
        <div className="px-5 py-4 bg-white flex-1">
          <div className="text-[10px] font-bold uppercase tracking-widest text-neutral-500 mb-1.5">Design notes</div>
          <p className="text-sm text-neutral-700 leading-relaxed">{notes}</p>
        </div>
      )}

      {/* Pick button */}
      {canPick && !isPicked && (
        <div className="px-5 py-4 bg-neutral-50 border-t border-neutral-100">
          <button
            type="button"
            onClick={onPick}
            className="w-full px-4 py-2.5 rounded-xl bg-indigo-600 text-white font-bold text-sm hover:bg-indigo-700 transition-colors"
          >
            Pick this variant
          </button>
        </div>
      )}
    </div>
  );
};

const VariantPickerPanel = ({ humanPicker, onPickVariant }) => {
  const { status, variants, pickedVariantId } = humanPicker;
  const canPick = status === 'pending' && typeof onPickVariant === 'function';

  return (
    <div className="flex flex-col gap-6">
      <div>
        <div className="text-[11px] font-bold uppercase tracking-[0.22em] text-neutral-500 mb-1 flex items-center gap-1.5">
          <UserCircle size={12} /> Design variants — picker review
        </div>
        <p className="text-sm text-neutral-600 max-w-2xl leading-relaxed">
          {status === 'pending'
            ? `${variants.length} variant${variants.length === 1 ? '' : 's'} produced. Review each one, then pick the design to carry forward to the next station.`
            : `Variant ${pickedVariantId?.toUpperCase() ?? '—'} was picked. This design flows to the next station.`}
        </p>
      </div>

      <div className={`grid gap-6 ${variants.length >= 2 ? 'grid-cols-1 xl:grid-cols-2' : 'grid-cols-1'}`}>
        {variants.map((v) => (
          <VariantCard
            key={v.id}
            variant={v}
            isPicked={v.id === pickedVariantId}
            canPick={canPick}
            onPick={() => onPickVariant && onPickVariant(v.id)}
          />
        ))}
      </div>
    </div>
  );
};

const TaskModal = ({ task, station, onClose, onToggleSubtask, onToggleAcceptance, onToggleValidator, onApprove, onReject, onAddHumanReviewComment, onPickVariant, nextStationTitle, initialTab = "details" }) => {
  const [tab, setTab] = useStateModal(initialTab);

  // When the modal is reopened with a different `initialTab` (e.g. user clicked
  // the agent pill on a different card), respect that hint.
  useEffectModal(() => { setTab(initialTab); }, [initialTab, task?.id]);

  useEffectModal(() => {
    const onKey = (e) => { if (e.key === "Escape") onClose(); };
    document.addEventListener("keydown", onKey);
    const prev = document.body.style.overflow;
    document.body.style.overflow = "hidden";
    return () => {
      document.removeEventListener("keydown", onKey);
      document.body.style.overflow = prev;
    };
  }, [onClose]);

  if (!task) return null;

  const isShipped = task.area === "done";
  const displayStatus = isShipped ? "shipped" : task.status;
  const assignedAgent = station?.agents.find((a) => a.id === task.assigneeId);
  const stationTitle = isShipped ? "Shipped Product" : station?.title;
  const subtasks = task.subtasks || [];
  const acceptance = task.acceptance || [];
  const subtasksDone = subtasks.filter((s) => s.done).length;
  const acceptanceDone = acceptance.filter((a) => a.done).length;
  // Read-only viewer (snapshot mode): every checkbox/toggle is inert.
  const subtasksEditable = !task.readOnly && (task.status === "working" || task.status === "rejected");
  const acceptanceEditable = !task.readOnly && task.status === "validating";
  const eventCount = (task.events || []).length;
  const iterationCount = task.iteration || 1;

  const TabBtn = ({ id, children, badge }) => {
    const active = tab === id;
    return (
      <button
        onClick={() => setTab(id)}
        className={`relative px-4 py-2 text-sm font-bold rounded-lg transition-colors ${
          active ? "bg-neutral-900 text-white shadow-sm" : "text-neutral-600 hover:text-neutral-900 hover:bg-neutral-100"
        }`}
      >
        {children}
        {badge != null && (
          <span className={`ml-2 inline-flex items-center justify-center text-[10px] font-bold rounded-full px-1.5 min-w-[18px] h-[18px] ${active ? "bg-white/20 text-white" : "bg-neutral-200 text-neutral-700"}`}>{badge}</span>
        )}
      </button>
    );
  };

  return (
    <div className="fixed inset-0 z-[100] flex items-center justify-center p-4 sm:p-8" role="dialog" aria-modal="true">
      <div className="absolute inset-0 bg-neutral-900/60 backdrop-blur-sm motion-enter" onClick={onClose} />

      <div className="relative bg-white rounded-3xl shadow-2xl border border-neutral-200 w-full max-w-5xl max-h-[92vh] flex flex-col overflow-hidden motion-enter">
        {/* Header */}
        <div className="px-8 py-6 border-b border-neutral-200 bg-gradient-to-b from-white to-neutral-50/60 flex items-start justify-between gap-6">
          <div className="min-w-0 flex-1">
            <div className="flex items-center gap-2 mb-3 flex-wrap">
              <span className="text-xs font-mono font-semibold text-neutral-500 bg-neutral-100 border border-neutral-200 px-2 py-1 rounded-md leading-none">{task.id}</span>
              {task.source && <SourceChip source={task.source} size="lg" />}
              {stationTitle && (
                <span className="inline-flex items-center text-[11px] font-bold uppercase tracking-[0.18em] text-neutral-700 bg-white border border-neutral-300 px-2 py-1 rounded-md leading-none">
                  {stationTitle}
                </span>
              )}
              <StatusPill status={displayStatus} />
              {iterationCount > 1 && (
                <span className="inline-flex items-center gap-1 text-[11px] font-bold uppercase tracking-[0.18em] text-neutral-600 bg-neutral-50 border border-neutral-300 px-2 py-1 rounded-full">
                  <RefreshCw size={11} /> Iteration {iterationCount}
                </span>
              )}
            </div>
            <h2 className="text-3xl font-black tracking-tight text-neutral-900 leading-tight">{task.title}</h2>
            {(() => {
              // Teamwork-only: the label is "Open in Teamwork", so don't render
              // it for a future non-Teamwork producer (it'd be mislabeled).
              if (!task.sourceUrl || task.source?.kind !== 'teamwork') return null;
              let safeHref = null;
              try {
                const u = new URL(task.sourceUrl, window.location.href);
                if (u.protocol === 'http:' || u.protocol === 'https:') safeHref = u.href;
              } catch { /* invalid URL → no link */ }
              return safeHref && (
                <a
                  href={safeHref}
                  target="_blank"
                  rel="noopener noreferrer"
                  className="inline-flex items-center gap-1 text-xs font-bold text-blue-600 hover:text-blue-800 hover:underline"
                >
                  Open in Teamwork ↗
                </a>
              );
            })()}

            <div className="mt-4 flex items-center gap-3 flex-wrap">
              {assignedAgent && (task.status === "working" || task.status === "rejected") && (
                <div className={`inline-flex items-center gap-2 pl-1 pr-3 py-1 rounded-full border-2 bg-white ${task.status === "rejected" ? "border-red-300" : "border-indigo-300"}`}>
                  <div className={`w-7 h-7 rounded-full flex items-center justify-center text-white text-xs font-bold ring-2 ring-white ${task.status === "rejected" ? "bg-red-500" : "bg-indigo-500"}`}>
                    {assignedAgent.name.charAt(0)}
                  </div>
                  <div className="flex flex-col leading-tight">
                    <span className={`text-[10px] font-bold uppercase tracking-widest ${task.status === "rejected" ? "text-red-700" : "text-indigo-700"}`}>
                      {task.status === "rejected" ? "Agent · Fixing" : "Agent · Working"}
                    </span>
                    <span className="text-sm font-bold text-neutral-900">{assignedAgent.name}{assignedAgent.role && assignedAgent.role !== assignedAgent.name && (<span className="text-neutral-400 font-medium"> · {assignedAgent.role}</span>)}</span>
                  </div>
                </div>
              )}
              {task.status === "validating" && (() => { const validator = window.Bridge?.primaryValidator(station); return validator ? (
                <div className="inline-flex items-center gap-2 pl-1 pr-3 py-1 rounded-full border-2 bg-white border-amber-300">
                  <div className="w-7 h-7 rounded-full flex items-center justify-center text-white text-xs font-bold ring-2 ring-white bg-amber-500">
                    {validator?.name?.charAt(0)}
                  </div>
                  <div className="flex flex-col leading-tight">
                    <span className="text-[10px] font-bold uppercase tracking-widest text-amber-700">Validator · Reviewing</span>
                    <span className="text-sm font-bold text-neutral-900">{validator?.name}{validator?.role && validator.role !== validator.name && (<span className="text-neutral-400 font-medium"> · {validator.role}</span>)}</span>
                  </div>
                </div>
              ) : null; })()}
              {task.status === "queue" && !isShipped && (
                <span className="inline-flex items-center gap-2 text-sm text-neutral-500 font-medium">
                  <Clock size={14} /> Waiting in queue — no agent assigned yet
                </span>
              )}
              {isShipped && (
                <span className="inline-flex items-center gap-2 text-sm text-emerald-700 font-bold">
                  <CheckCircle size={16} /> Shipped — no further work needed
                </span>
              )}
            </div>
          </div>

          <button onClick={onClose} className="shrink-0 w-10 h-10 rounded-full bg-neutral-100 hover:bg-neutral-200 text-neutral-600 flex items-center justify-center transition-colors" aria-label="Close">
            <X size={20} />
          </button>
        </div>

        {/* Tabs */}
        <div className="px-8 pt-3 pb-3 border-b border-neutral-200 bg-white flex items-center gap-1">
          <TabBtn id="details">Details</TabBtn>
          <TabBtn id="history" badge={eventCount}>History</TabBtn>
          {(task.agentRuns || []).length > 0 && (
            <TabBtn id="agentLog" badge={(task.agentRuns || []).length}>Agent log</TabBtn>
          )}
          {(task.status === "human-review" || (task.humanReviewThread || []).length > 0) && (
            <TabBtn id="humanReview" badge={(task.humanReviewThread || []).length || undefined}>Human review</TabBtn>
          )}
          {task.humanPicker && (
            <TabBtn id="variants" badge={task.humanPicker.status === 'pending' ? task.humanPicker.variants?.length : undefined}>
              {task.humanPicker.status === 'picked' ? 'Picked variant' : 'Pick variant'}
            </TabBtn>
          )}
        </div>

        {/* Body */}
        <div className="flex-1 overflow-y-auto custom-scrollbar p-8 bg-neutral-50/40">
          {tab === "details" && (
            <div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
              <section className="lg:col-span-2 bg-white border-2 border-neutral-200 rounded-2xl p-6">
                <SectionLabel icon={<FileText size={14} />} text="Task Description" />
                <p className="text-neutral-800 text-base leading-relaxed">{task.description}</p>
                {task.source && (
                  <div className="mt-5 pt-5 border-t border-neutral-200 flex items-center gap-3 flex-wrap">
                    <span className="text-[11px] font-bold uppercase tracking-[0.18em] text-neutral-500">Source</span>
                    <SourceChip source={task.source} size="lg" />
                    <span className="text-xs text-neutral-500">
                      Imported from {task.source.kind === "teamwork" ? "Teamwork" : task.source.kind} — open the original to see the full history.
                    </span>
                  </div>
                )}
              </section>

              <section className="bg-white border-2 border-neutral-200 rounded-2xl p-6">
                <SectionLabel icon={<ArrowRight size={14} />} text="Objective" />
                <p className="text-neutral-800 text-base leading-relaxed">{task.objective || "—"}</p>
              </section>

              <section className="bg-white border-2 border-neutral-200 rounded-2xl p-6">
                <SectionLabel icon={<FileText size={14} />} text="Relevant Files" />
                {task.relevantFiles && task.relevantFiles.length > 0 ? (
                  <ul className="flex flex-col gap-2">
                    {task.relevantFiles.map((f) => (
                      <li key={f} className="font-mono text-sm bg-neutral-50 border border-neutral-200 px-3 py-2 rounded-lg text-neutral-800 break-all">{f}</li>
                    ))}
                  </ul>
                ) : (
                  <p className="text-neutral-400 text-sm italic">No files linked yet.</p>
                )}
              </section>

              <section className="lg:col-span-2 bg-white border-2 border-neutral-200 rounded-2xl p-6">
                <div className="flex items-center justify-between mb-4 flex-wrap gap-3">
                  <SectionLabel icon={<Hammer size={14} />} text="Step-by-Step SubTasks" accent="indigo" caption="Filled out by the agent as they work" />
                  <span className="text-xs font-bold text-indigo-700 bg-indigo-50 border border-indigo-200 px-2.5 py-1 rounded-full">{subtasksDone}/{subtasks.length} done</span>
                </div>
                {subtasks.length === 0 ? (
                  <p className="text-neutral-400 text-sm italic">Agent hasn't broken this down yet.</p>
                ) : (
                  <ul className="flex flex-col gap-3">
                    {subtasks.map((s) => (
                      <li key={s.id} className={`flex items-center gap-4 p-4 rounded-xl border-2 transition-colors ${s.done ? "bg-emerald-50/60 border-emerald-200" : "bg-neutral-50 border-neutral-200"}`}>
                        <BigCheck done={s.done} actor="agent" disabled={!subtasksEditable} onToggle={() => onToggleSubtask?.(task.id, s.id)} label={s.text} />
                        <span className={`text-base leading-snug flex-1 ${s.done ? "text-neutral-500 line-through" : "text-neutral-900 font-medium"}`}>{s.text}</span>
                      </li>
                    ))}
                  </ul>
                )}
                {!subtasksEditable && subtasks.length > 0 && (
                  <p className="mt-3 text-[11px] font-medium text-neutral-400 uppercase tracking-widest">
                    {task.status === "queue" ? "Locked — awaiting an agent." :
                     task.status === "validating" ? "Locked while the validator reviews." :
                     isShipped ? "Locked — task has shipped." : ""}
                  </p>
                )}
              </section>

              <section className="lg:col-span-2 bg-white border-2 border-neutral-200 rounded-2xl p-6">
                <div className="flex items-center justify-between mb-4 flex-wrap gap-3">
                  <SectionLabel icon={<ShieldCheck size={14} />} text="Acceptance Criteria" accent="amber" caption="Filled out by the validator" />
                  <span className="text-xs font-bold text-amber-700 bg-amber-50 border border-amber-200 px-2.5 py-1 rounded-full">{acceptanceDone}/{acceptance.length} met</span>
                </div>
                {acceptance.length === 0 ? (
                  <p className="text-neutral-400 text-sm italic">No acceptance criteria yet.</p>
                ) : (
                  <ul className="flex flex-col gap-3">
                    {acceptance.map((a) => (
                      <li key={a.id} className={`flex items-center gap-4 p-4 rounded-xl border-2 transition-colors ${a.done ? "bg-emerald-50/60 border-emerald-200" : "bg-neutral-50 border-neutral-200"}`}>
                        <BigCheck done={a.done} actor="validator" disabled={!acceptanceEditable} onToggle={() => onToggleAcceptance?.(task.id, a.id)} label={a.text} />
                        <span className={`text-base leading-snug flex-1 ${a.done ? "text-neutral-500 line-through" : "text-neutral-900 font-medium"}`}>{a.text}</span>
                      </li>
                    ))}
                  </ul>
                )}
                {!acceptanceEditable && acceptance.length > 0 && (
                  <p className="mt-3 text-[11px] font-medium text-neutral-400 uppercase tracking-widest">
                    {task.status === "queue" ? "Locked — task hasn't been worked yet." :
                     (task.status === "working" || task.status === "rejected") ? "Locked — agent is still working." :
                     isShipped ? "Locked — task has shipped." : ""}
                  </p>
                )}
              </section>
            </div>
          )}

          {tab === "history" && (
            <div>
              <div className="mb-6">
                <div className="text-[11px] font-bold uppercase tracking-[0.22em] text-neutral-400 mb-1">Progression history</div>
                <p className="text-sm text-neutral-600 max-w-2xl leading-relaxed">
                  Every assignment, submission, rejection, and approval — grouped by iteration. Rejected iterations are kept so you can see exactly what changed and why.
                </p>
              </div>
              <HistoryView task={task} />
            </div>
          )}

          {tab === "agentLog" && (
            <div>
              <div className="mb-6">
                <div className="text-[11px] font-bold uppercase tracking-[0.22em] text-neutral-400 mb-1">Agent log</div>
                <p className="text-sm text-neutral-600 max-w-2xl leading-relaxed">
                  Each station gets its own agent — and a rejection spawns a fresh run on the same station. Pick any run on the left to see what that agent thought and did.
                </p>
              </div>
              <AgentLogView runs={task.agentRuns || []} />
            </div>
          )}

          {tab === "humanReview" && (
            <HumanReviewPanel
              task={task}
              station={station}
              onApprove={onApprove}
              onReject={onReject}
              onAddComment={onAddHumanReviewComment}
            />
          )}

          {tab === "variants" && task.humanPicker && (
            <VariantPickerPanel
              humanPicker={task.humanPicker}
              onPickVariant={(!task.readOnly && onPickVariant) ? (variantId) => onPickVariant(task.id, variantId) : null}
            />
          )}
        </div>
      </div>
    </div>
  );
};

const SectionLabel = ({ icon, text, caption, accent }) => {
  const accentCls =
    accent === "indigo" ? "text-indigo-700" :
    accent === "amber" ? "text-amber-700" :
    "text-neutral-700";
  return (
    <div className="mb-3">
      <div className={`text-[11px] font-bold uppercase tracking-[0.22em] flex items-center gap-1.5 ${accentCls}`}>
        {icon} {text}
      </div>
      {caption && <div className="text-xs text-neutral-400 mt-1 font-medium">{caption}</div>}
    </div>
  );
};

const HumanReviewPanel = ({ task, station, onApprove, onReject, onAddComment }) => {
  const [draft, setDraft] = React.useState("");
  const thread = task.humanReviewThread || [];
  const isHumanReview = task.status === "human-review";

  const submit = () => {
    const text = draft.trim();
    if (!text) return;
    onAddComment && onAddComment(task.id, text);
    setDraft("");
  };

  return (
    <div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
      <div className="lg:col-span-2 space-y-4">
        <div>
          <div className="text-[11px] font-bold uppercase tracking-[0.22em] text-orange-700 mb-1 flex items-center gap-1.5">
            <UserCircle size={12} /> Human review thread
          </div>
          <p className="text-sm text-neutral-600 max-w-2xl leading-relaxed">
            Reviewers leave feedback here. The agent reads the thread the moment you reject — every comment becomes context for the next iteration.
          </p>
        </div>

        <div className="space-y-3">
          {thread.length === 0 && (
            <div className="text-sm text-neutral-500 bg-white border border-dashed border-neutral-300 rounded-xl p-6 text-center">
              No comments yet. Add the first note below.
            </div>
          )}
          {thread.map((c) => (
            <div key={c.id} className="bg-white border border-neutral-200 rounded-xl p-4 flex items-start gap-3">
              <div className="w-9 h-9 rounded-full bg-orange-100 text-orange-800 flex items-center justify-center text-sm font-bold shrink-0 border border-orange-200">
                {c.avatar || c.author.charAt(0)}
              </div>
              <div className="min-w-0 flex-1">
                <div className="flex items-center gap-2 mb-1">
                  <span className="text-sm font-bold text-neutral-800 leading-none">{c.author}</span>
                  <span className="text-[11px] text-neutral-400 leading-none">· {c.when}</span>
                </div>
                <p className="text-sm text-neutral-700 leading-relaxed whitespace-pre-wrap">{c.text}</p>
              </div>
            </div>
          ))}
        </div>

        {!task.readOnly && (
          <div className="bg-white border border-neutral-200 rounded-xl p-3">
            <textarea
              value={draft}
              onChange={(e) => setDraft(e.target.value)}
              placeholder="Leave a note for the agent…"
              rows={3}
              className="w-full text-sm text-neutral-800 placeholder-neutral-400 bg-transparent resize-none focus:outline-none px-1 py-1"
            />
            <div className="flex items-center justify-between pt-2 border-t border-neutral-100">
              <span className="text-[11px] text-neutral-400">Visible to teammates and the agent on next iteration.</span>
              <button
                onClick={submit}
                disabled={!draft.trim()}
                className="text-xs font-bold bg-neutral-900 text-white px-4 py-2 rounded-lg hover:bg-neutral-800 transition disabled:opacity-40 disabled:cursor-not-allowed"
              >
                Add comment
              </button>
            </div>
          </div>
        )}
      </div>

      <div className="lg:col-span-1">
        <div className="sticky top-0 bg-white border-2 border-orange-200 rounded-xl p-4 space-y-3">
          <div className="text-[11px] font-bold uppercase tracking-[0.22em] text-orange-700">Decision</div>
          {task.readOnly && (task.actions || []).includes('approve') && isHumanReview ? (
            // Snapshot mode with Teamwork write-back: real decisions. The
            // viewer-server moves the stage / swaps tags in Teamwork and
            // re-syncs before answering.
            <>
              <p className="text-sm text-neutral-600 leading-relaxed">
                Approve to move this ticket to <span className="font-semibold text-neutral-800">the next station</span> in Teamwork, or reject to flag it for rework.
              </p>
              <div className="flex flex-col gap-2">
                <button
                  disabled={!!task.actionPending}
                  onClick={() => onApprove && onApprove(task)}
                  className="text-xs font-bold bg-orange-500 text-white px-3 py-2.5 rounded-lg hover:bg-orange-600 transition flex items-center justify-center gap-1.5 disabled:opacity-40 disabled:cursor-not-allowed"
                >
                  <CheckCircle size={14} /> {task.actionPending ? "Sending…" : "Approve & ship"}
                </button>
                <button
                  disabled={!!task.actionPending}
                  onClick={() => onReject && onReject(task, station)}
                  className="text-xs font-bold bg-white text-red-600 border-2 border-red-200 px-3 py-2.5 rounded-lg hover:bg-red-50 transition disabled:opacity-40 disabled:cursor-not-allowed"
                >
                  Reject &amp; flag for rework
                </button>
              </div>
            </>
          ) : task.readOnly && isHumanReview ? (
            <p className="text-sm text-neutral-500 leading-relaxed">
              Read-only view — approve or reject this task in Teamwork.
            </p>
          ) : task.readOnly ? (
            <p className="text-sm text-neutral-500 leading-relaxed">
              This task is not awaiting human review.
            </p>
          ) : isHumanReview ? (
            <>
              <p className="text-sm text-neutral-600 leading-relaxed">
                Approve to ship to <span className="font-semibold text-neutral-800">the next station</span>, or reject to send it back with this thread as context.
              </p>
              <div className="flex flex-col gap-2">
                <button
                  onClick={() => onApprove && onApprove(task)}
                  className="text-xs font-bold bg-orange-500 text-white px-3 py-2.5 rounded-lg hover:bg-orange-600 transition flex items-center justify-center gap-1.5"
                >
                  <CheckCircle size={14} /> Approve &amp; ship
                </button>
                <button
                  onClick={() => onReject && onReject(task, station)}
                  className="text-xs font-bold bg-white text-red-600 border-2 border-red-200 px-3 py-2.5 rounded-lg hover:bg-red-50 transition"
                >
                  Reject &amp; send back
                </button>
              </div>
            </>
          ) : (
            <p className="text-sm text-neutral-500 leading-relaxed">
              This task is no longer in human review. The thread stays attached for posterity.
            </p>
          )}
        </div>
      </div>
    </div>
  );
};

window.TaskModal = TaskModal;
