// Atlas · Step 4 — Live agent research console (real SSE from /api/research)
const { useState: useStateRes, useEffect: useEffectRes, useRef: useRefRes } = React;

function getActivityStatus(lines, agentLabel, agentState) {
  // Find where this agent's section starts in the log
  const headerIdx = lines.findIndex(l => l.startsWith('◆') && l.includes(agentLabel));
  const section = headerIdx >= 0 ? lines.slice(headerIdx + 1) : [];

  if (agentLabel === 'Specialist') return 'Designing strategy…';
  if (agentLabel.includes('Synthesizer')) return 'Synthesizing…';
  if (agentLabel.includes('Review')) {
    if (agentState === 'rejected') return 'Gaps identified — running targeted research…';
    return 'Reviewing completeness…';
  }
  if (agentLabel.includes('Enrichment')) return 'Enriching data…';

  const hasCheck  = section.some(l => l.trim().startsWith('✓'));
  if (hasCheck) return 'Analyzing results…';

  if (section.some(l => l.includes('▶ PubMed')))          return 'Querying PubMed…';
  if (section.some(l => l.includes('▶ OpenAlex')))         return 'Querying OpenAlex…';
  if (section.some(l => l.includes('▶ arXiv') || l.includes('▶ Preprint'))) return 'Querying preprints…';
  if (section.some(l => l.includes('▶ ClinicalTrials') || l.includes('▶ Clinical'))) return 'Querying ClinicalTrials…';
  if (section.some(l => l.includes('▶ Patent') || l.includes('▶ PPUBS'))) return 'Querying patents…';
  if (section.some(l => l.includes('▶ Web')))              return 'Searching web…';

  return 'Working…';
}

function deriveAgentStates(lines, isDone, manifestAgents, gapManifestAgents, reviewStatus) {
  const has = (pattern) => lines.some(l => l.includes(pattern));

  const hasSpecialist     = has('SPECIALIST') && has('Initializing');
  const hasSynthesizer    = has('◆ SYNTHESIZER');
  const hasReview         = has('◆ REVIEW AGENT');
  const hasWriting        = has('◆ WRITING AGENT');
  const hasEnrichment     = has('◆ ENRICHMENT SWEEP') && !has('◆ ENRICHMENT SWEEP COMPLETE');
  const hasEnrichmentDone = has('◆ ENRICHMENT SWEEP COMPLETE');

  const st = (active, done) => isDone && done !== false ? 'done' : done ? 'done' : active ? 'active' : 'pending';

  // Build typed agent rows from the manifest if available; otherwise empty until it arrives
  const typedRows = [];
  if (manifestAgents && manifestAgents.length > 0) {
    const seenLabels = new Set();
    for (const { label } of manifestAgents) {
      if (seenLabels.has(label)) continue;
      seenLabels.add(label);
      const headerLine = lines.find(l => l.startsWith('◆') && l.includes(label));
      const started = !!headerLine;
      // Agent is done if a later agent has started, or synthesizer/enrichment is running
      const labelIdx = manifestAgents.findIndex(a => a.label === label);
      const nextStarted = manifestAgents.slice(labelIdx + 1).some(a =>
        lines.some(l => l.startsWith('◆') && l.includes(a.label))
      );
      const isDoneAgent = started && (nextStarted || hasEnrichment || hasEnrichmentDone || hasSynthesizer || isDone);
      const isActive = started && !isDoneAgent;
      typedRows.push({ label, state: st(isActive, isDoneAgent) });
    }
  }

  const firstTypedStarted = typedRows.length > 0 && typedRows.some(r => r.state !== 'pending');

  const reviewIdx = lines.reduce((acc, l, i) => l.includes('◆ REVIEW AGENT') ? i : acc, -1);
  const gapIdx    = lines.reduce((acc, l, i) => (l.includes('GAP RESEARCH SUBAGENT') || l.includes('gap-filling')) ? i : acc, -1);
  const hasGap = (gapManifestAgents && gapManifestAgents.length > 0)
    || lines.some(l => l.includes('GAP RESEARCH SUBAGENT') || l.includes('gap-filling'));

  const hasGapSpecialist = hasGap && has('gap-filling') && has('Designing');
  const hasResynth       = hasGap && has('Re-synthesizing');
  const hasReviewAfterGap = hasGap && lines.slice(gapIdx).some(l => l.includes('◆ REVIEW AGENT'));

  const agents = [
    { label: "Review Agent",  state: 'done' },
    { label: "Outline Agent", state: 'done' },
    { label: "Specialist",    state: st(hasSpecialist, firstTypedStarted || isDone) },
    ...typedRows,
    { label: "Enrichment Sweep", state: st(hasEnrichment, hasEnrichmentDone || isDone) },
    { label: "Synthesizer",      state: st(hasSynthesizer && !hasGap, hasReview || isDone) },
    { label: "Review Agent",     state: !hasGap ? st(hasReview, hasWriting || isDone) : 'rejected' },
    { label: "Writing Agent",    state: st(hasWriting, isDone) },
  ];

  if (hasGap) {
    const gapRows = [];
    gapRows.push({ label: "Specialist", state: st(hasGapSpecialist, !!(gapManifestAgents) || isDone) });

    if (gapManifestAgents && gapManifestAgents.length > 0) {
      const gapSeenLabels = new Set();
      gapManifestAgents.forEach(({ label }, idx) => {
        if (gapSeenLabels.has(label)) return;
        gapSeenLabels.add(label);
        const headerLine = lines.find(l => l.startsWith('◆') && l.includes(label));
        const started = !!headerLine;
        const nextStarted = gapManifestAgents.slice(idx + 1).some(a =>
          lines.some(l => l.startsWith('◆') && l.includes(a.label))
        );
        const isDoneAgent = started && (nextStarted || hasResynth || isDone);
        const isActive = started && !isDoneAgent;
        gapRows.push({ label, state: st(isActive, isDoneAgent) });
      });
    }

    gapRows.push({ label: "Synthesizer",  state: st(hasResynth, hasReviewAfterGap || isDone) });
    gapRows.push({ label: "Review Agent", state: st(hasReviewAfterGap && !hasWriting, hasWriting || isDone) });

    const writingIdx = agents.findIndex(a => a.label === "Writing Agent");
    agents.splice(writingIdx, 0, ...gapRows);
  }

  return agents;
}

function StepResearch({ reportId, goBack, goNext, goHome, loading, error, refreshedFrom }) {
  const [lines, setLines] = useStateRes([]);
  const [done, setDone] = useStateRes(false);
  const [started, setStarted] = useStateRes(false);
  const [streamError, setStreamError] = useStateRes(null);
  const [reconnecting, setReconnecting] = useStateRes(false);
  const [stuck, setStuck] = useStateRes(false);
  const [sourcesUsed, setSourcesUsed] = useStateRes(null);
  const [reviewStatus, setReviewStatus] = useStateRes(null);
  const [manifestAgents, setManifestAgents] = useStateRes(null);
  const [gapManifestAgents, setGapManifestAgents] = useStateRes(null);
  const consoleRef = useRefRes(null);
  const esRef = useRefRes(null);
  const reconnectTimeoutRef = useRefRes(null);
  const messageIndexRef = useRefRes(0);

  // Auto-scroll console
  useEffectRes(() => {
    if (consoleRef.current) {
      consoleRef.current.scrollTop = consoleRef.current.scrollHeight;
    }
  }, [lines]);

  // Start: fire background task then open SSE replay
  const startResearch = (isReconnect = false, forceRestart = false) => {
    if (!reportId) return;
    if (!isReconnect && !forceRestart && started) return;

    setStarted(true);
    setStreamError(null);
    setReconnecting(false);
    messageIndexRef.current = 0;

    // Fire background task (idempotent — safe to call if already running)
    if (!isReconnect) {
      fetch(`/api/research-background/${reportId}`, { method: "POST" }).catch(() => {});
    }

    const es = new EventSource(`/api/research/${reportId}`);
    esRef.current = es;

    es.onmessage = (e) => {
      try {
        const data = JSON.parse(e.data);
        if (data.stuck) {
          setStuck(true);
        } else if (data.done) {
          setDone(true);
          setStuck(false);
          es.close();
        } else if (data.sources_used) {
          setSourcesUsed(data.sources_used);
        } else if (data.review_status) {
          setReviewStatus(data.review_status);
        } else if (data.manifest) {
          setManifestAgents(data.manifest);
        } else if (data.gap_manifest) {
          setGapManifestAgents(data.gap_manifest);
        } else if (data.text !== undefined) {
          const idx = messageIndexRef.current;
          messageIndexRef.current++;

          setLines((prev) => {
            // Replay synchronization: if we already have this line at this index, ignore it.
            if (idx < prev.length) return prev;
            return [...prev, data.text];
          });
        }
      } catch (err) {}
    };

    es.onerror = () => {
      es.close();
      if (!done) {
        setReconnecting(true);
        setStreamError("Connection lost. Reconnecting to agent logs…");
        
        // Auto-reconnect after 3 seconds
        if (reconnectTimeoutRef.current) clearTimeout(reconnectTimeoutRef.current);
        reconnectTimeoutRef.current = setTimeout(() => {
          console.log("[research] Attempting auto-reconnect...");
          startResearch(true);
        }, 3000);
      }
    };
  };

  // Auto-start when component mounts with a valid reportId
  useEffectRes(() => {
    if (reportId && !started) startResearch();
    return () => { 
      if (esRef.current) esRef.current.close(); 
      if (reconnectTimeoutRef.current) clearTimeout(reconnectTimeoutRef.current);
    };
  }, [reportId]);

  const retryResearch = async () => {
    if (esRef.current) esRef.current.close();
    if (reconnectTimeoutRef.current) clearTimeout(reconnectTimeoutRef.current);
    await fetch(`/api/research/${reportId}/reset`, { method: "POST" }).catch(() => {});
    setStuck(false);
    setLines([]);
    setDone(false);
    setManifestAgents(null);
    setGapManifestAgents(null);
    setReviewStatus(null);
    setSourcesUsed(null);
    setStreamError(null);
    messageIndexRef.current = 0;
    startResearch(false, true);
  };

  const renderLine = (line, i) => {
    if (!line && line !== "") return <div key={i} className="line">&nbsp;</div>;
    const l = line;
    if (l.startsWith("━")) return <div key={i} className="line rule">{l}</div>;
    if (l.startsWith("◆")) return <div key={i} className="line"><span className="heavy">{l}</span></div>;
    if (l.trim().startsWith("✓")) return <div key={i} className="line"><span className="ok">{l}</span></div>;
    if (l.trim().startsWith("▶")) return <div key={i} className="line"><span className="warn">{l}</span></div>;
    if (l.trim().startsWith("→")) return <div key={i} className="line heavy">{l}</div>;
    if (l.trim().startsWith("[Subagent")) return <div key={i} className="line"><span className="info">{l}</span></div>;
    if (l.trim() === "") return <div key={i} className="line">&nbsp;</div>;
    return <div key={i} className="line">{l}</div>;
  };

  return (
    <div className="canvas-inner">
      <div className="console-page">
        {/* Side rail */}
        <div className="console-side">
          <div className="eyebrow" style={{ marginBottom: 12 }}>Pipeline status</div>

          <div className="agent-list">
            {(() => {
              const agents = deriveAgentStates(lines, done, manifestAgents, gapManifestAgents, reviewStatus);
              const doneAgents    = agents.filter(a => a.state === 'done' || a.state === 'rejected');
              const activeAgent   = agents.find(a => a.state === 'active');
              const pendingAgents = agents.filter(a => a.state === 'pending');

              return (
                <>
                  {/* Completed agents — compact single-line rows */}
                  {doneAgents.map((a, i) => (
                    <div key={i} style={{ display: "flex", alignItems: "center", gap: 8, padding: "3px 0" }}>
                      {a.state === 'rejected'
                        ? <span style={{ width: 12, textAlign: "center", color: "var(--rose)", fontSize: 10, flexShrink: 0 }}>✕</span>
                        : <Icon name="checkSmall" size={12} strokeWidth={2.4} style={{ color: "var(--success)", flexShrink: 0 }} />
                      }
                      <span style={{ fontSize: 11, color: "var(--ink-4)", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{a.label}</span>
                    </div>
                  ))}

                  {/* Active agent — expanded with focus text */}
                  {activeAgent && (
                    <div style={{ display: "flex", alignItems: "flex-start", gap: 10, padding: "8px 0 8px 10px", margin: "4px 0", borderLeft: "2px solid var(--warm)" }}>
                      <span style={{
                        width: 6, height: 6, borderRadius: "50%", flexShrink: 0, marginTop: 4,
                        background: "var(--warm)",
                        animation: "pulse 1.2s ease-in-out infinite",
                      }} />
                      <div style={{ flex: 1, minWidth: 0 }}>
                        <div style={{ fontSize: 12, color: "var(--ink-2)", fontWeight: 500 }}>{activeAgent.label}</div>
                        <div style={{ fontSize: 11, color: "var(--ink-4)", fontFamily: "var(--mono)", marginTop: 2 }}>{getActivityStatus(lines, activeAgent.label, activeAgent.state)}</div>
                      </div>
                    </div>
                  )}

                  {/* Up next — hidden while Specialist or Review Agent is active (outcome unknown) */}
                  {pendingAgents.length > 0
                    && !(activeAgent?.label === 'Specialist' && (manifestAgents?.length ?? 0) === 0)
                    && activeAgent?.label !== 'Review Agent'
                    && (
                    <div style={{ marginTop: 6, fontSize: 11, color: "var(--ink-5)", fontStyle: "italic", lineHeight: 1.4 }}>
                      Next: {pendingAgents.slice(0, 3).map(a => a.label).join(" → ")}{pendingAgents.length > 3 ? "…" : ""}
                    </div>
                  )}
                </>
              );
            })()}
          </div>

          {sourcesUsed && (
            <div style={{ marginTop: 16 }}>
              <div className="eyebrow" style={{ marginBottom: 8 }}>Sources used</div>
              <div style={{ display: "flex", flexWrap: "wrap", gap: 6 }}>
                {Object.entries(sourcesUsed).map(([key, count]) => count > 0 && (
                  <span key={key} style={{
                    fontSize: 10, fontFamily: "var(--mono)", padding: "2px 7px",
                    background: "var(--bg-2)", border: "1px solid var(--line)",
                    borderRadius: 4, color: "var(--ink-3)", whiteSpace: "nowrap",
                  }}>
                    {key.replace(/_/g, ' ')} {count}
                  </span>
                ))}
              </div>
            </div>
          )}


          {started && !done && (
            <div style={{ marginTop: 16, padding: "10px 12px", background: "var(--bg-2)", borderRadius: "var(--radius)", border: "1px solid var(--line)", fontSize: 12, color: "var(--ink-3)", lineHeight: 1.5 }}>
              Research is running in the background. You'll receive an email notification when your report is ready.<br />
              <button
                className="btn ghost sm"
                onClick={goHome}
                style={{ marginTop: 8, width: "100%", justifyContent: "center" }}
              >
                ← Back to homepage
              </button>
            </div>
          )}
          {done && (
            <div style={{ marginTop: 16, padding: "10px 12px", background: "var(--success-tint)", borderRadius: "var(--radius)", border: "1px solid var(--success-line)", fontSize: 12, color: "var(--success)" }}>
              <strong>Draft ready.</strong><br />
              Research complete and draft generated.
            </div>
          )}
          {streamError && (
            <div style={{ 
              marginTop: 16, padding: "12px", 
              background: reconnecting ? "var(--bg-2)" : "var(--warm-tint)", 
              borderRadius: "var(--radius)", 
              border: `1px solid ${reconnecting ? "var(--line)" : "var(--warm-line)"}`, 
              fontSize: 12, color: reconnecting ? "var(--ink-3)" : "var(--warm)",
              boxShadow: reconnecting ? "none" : "0 4px 12px rgba(251, 191, 36, 0.15)",
              position: "relative", overflow: "hidden"
            }}>
              {reconnecting && (
                <div style={{ 
                  position: "absolute", bottom: 0, left: 0, height: 2, background: "var(--warm)", 
                  animation: "loading-bar 3s linear infinite" 
                }} />
              )}
              <div style={{ display: "flex", gap: 8, alignItems: "flex-start" }}>
                <span style={{ fontSize: 14 }}>{reconnecting ? "⏳" : "⚠️"}</span>
                <div>
                  <strong style={{ display: "block", marginBottom: 2 }}>{reconnecting ? "Reconnecting..." : "Connection Lost"}</strong>
                  {streamError}
                </div>
              </div>
            </div>
          )}
        </div>

        {/* Console */}
        <div className="console-main">
          {stuck && (
            <div style={{
              marginBottom: 12, padding: "12px 16px",
              background: "var(--warm-tint)", border: "1px solid var(--warm-line)",
              borderRadius: "var(--radius)", fontSize: 13, color: "var(--warm)",
              display: "flex", alignItems: "center", justifyContent: "space-between", gap: 12,
            }}>
              <span>⚠️ No activity for 5 minutes — research may be stuck.</span>
              <div style={{ display: "flex", gap: 8, flexShrink: 0 }}>
                <button className="btn ghost sm" onClick={() => setStuck(false)}>Keep Waiting</button>
                <button className="btn primary sm" onClick={retryResearch}>Retry Research</button>
              </div>
            </div>
          )}
          {refreshedFrom && (
            <div style={{ display: "flex", alignItems: "center", gap: 8, padding: "8px 14px", marginBottom: 10,
              background: "var(--ink-1)", border: "1px solid var(--ink-2)", borderRadius: "var(--radius)",
              fontSize: 12, color: "var(--ink-4)" }}>
              <Icon name="refresh" size={13} />
              Refreshed report — scope and outline carried over from prior run.
              <button className="btn ghost" style={{ marginLeft: "auto", padding: "2px 8px", fontSize: 11 }} onClick={goBack}>
                View scope
              </button>
            </div>
          )}
          <div className="console-head">
            <span className="eyebrow">Agent console</span>
            <span style={{ fontFamily: "var(--mono)", fontSize: 11, color: "var(--ink-3)" }}>
              {lines.length} lines · {done ? "complete" : started ? "running…" : "waiting"}
            </span>
          </div>
          <div className="console-body" ref={consoleRef}>
            {!started && !reportId && (
              <div className="line" style={{ color: "var(--ink-4)", fontStyle: "italic" }}>
                No report ID found. Return to Brief and submit your brief first.
              </div>
            )}
            {!started && reportId && (
              <div className="line" style={{ color: "var(--ink-4)", fontStyle: "italic" }}>Starting research pipeline…</div>
            )}
            {lines.map((l, i) => renderLine(l, i))}
            {started && !done && (
              <div className="line" style={{ opacity: 0.5 }}>
                <span style={{ animation: "blink 1s step-end infinite", display: "inline-block" }}>▌</span>
              </div>
            )}
          </div>
        </div>
      </div>

      <style>{`
        @keyframes blink { 0%, 100% { opacity: 1; } 50% { opacity: 0; } }
        @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }
        @keyframes loading-bar { 0% { width: 0; } 100% { width: 100%; } }
        .console-page { display: grid; grid-template-columns: 240px 1fr; gap: 32px; }
        .console-main { display: flex; flex-direction: column; }
        .console-head { display: flex; justify-content: space-between; align-items: center; padding-bottom: 12px; border-bottom: 1px solid var(--line); margin-bottom: 0; }
        .console-body { font-family: var(--mono); font-size: 12px; line-height: 1.7; background: var(--bg-2); color: var(--ink-2); border-radius: var(--radius-lg); padding: 20px 24px; height: 520px; overflow-y: auto; border: 1px solid var(--line); }
        .console-body .line { white-space: pre-wrap; word-break: break-word; }
        .console-body .rule { color: var(--line-2); }
        .console-body .heavy { color: var(--ink); font-weight: 600; }
        .console-body .ok { color: var(--success); }
        .console-body .warn { color: var(--warm); }
        .console-body .info { color: #4F52B2; }
        .console-body .agent-name { color: var(--ink); }
      `}</style>

      <div className="actionbar">
        <div className="left">
          {done ? "Draft ready. Click to review." : "Agents are running. This typically takes 30-45 minutes."}
        </div>
        <div className="right">
          <button className="btn ghost" onClick={goHome}><Icon name="arrowLeft" size={14} /> Home</button>
          <button className="btn primary lg" disabled={!done || loading} onClick={goNext}>
            {loading ? "Loading draft…" : "View draft"}
            {!loading && <Icon name="arrowRight" size={14} />}
          </button>
        </div>
      </div>
    </div>
  );
}

window.StepResearch = StepResearch;
