// Slide 2 — Investigation graph.
// Question → 4 investigation angles → hypotheses → SQL → verdicts → answer.
// Animated draw-in; hover or click any node to highlight its full path
// and inspect what that tool call did.

const { useState: s2use, useEffect: s2eff, useMemo: s2mem } = React;
const { pitchC, pitchMono, SqlBlock, StatusPill } = window;

// ──── Graph definition ──────────────────────────────────────────────────

const NODES = [
  // root question
  { id: 'q', kind: 'question', x: 70, y: 290, w: 250, h: 100, label: 'Are we known more for furniture or homeware?', sub: 'user question' },

  // angles
  { id: 'a1', kind: 'angle', x: 460, y:  60, w: 240, h: 70, color: pitchC.sea,    label: 'Funnel diagnosis',     sub: 'awareness → consideration → purchase' },
  { id: 'a2', kind: 'angle', x: 460, y: 195, w: 240, h: 70, color: pitchC.amber,  label: 'Category association', sub: 'furniture vs homeware split' },
  { id: 'a3', kind: 'angle', x: 460, y: 330, w: 240, h: 70, color: pitchC.purple, label: 'Competitive set',      sub: 'IKEA, Dunelm, John Lewis…' },
  { id: 'a4', kind: 'angle', x: 460, y: 465, w: 240, h: 70, color: pitchC.moss,   label: 'Image attributes',     sub: 'style, value, design at price' },

  // hypotheses (each → BSA SQL → DuckDB → verdict)
  { id: 'h1', kind: 'hyp', x: 840, y:  35, w: 280, h: 88, parent: 'a1', metric: 'prompted_awareness',     dim: 'by brand · all respondents',  rows: 14, verdict: 'sig', sql: SQL_H1() },
  { id: 'h2', kind: 'hyp', x: 840, y: 135, w: 280, h: 88, parent: 'a1', metric: 'future_consideration',   dim: 'by brand × category',          rows: 22, verdict: 'sig', sql: SQL_H2() },
  { id: 'h3', kind: 'hyp', x: 840, y: 235, w: 280, h: 88, parent: 'a2', metric: 'category_association',   dim: 'furniture vs homeware',        rows: 11, verdict: 'sig', sql: SQL_H3() },
  { id: 'h4', kind: 'hyp', x: 840, y: 335, w: 280, h: 88, parent: 'a2', metric: 'last_purchased_brand',   dim: 'Habitat share, both cats',     rows: 18, verdict: 'sig', sql: SQL_H4() },
  { id: 'h5', kind: 'hyp', x: 840, y: 435, w: 280, h: 88, parent: 'a3', metric: 'consideration_rank',     dim: 'vs IKEA, Dunelm, John Lewis',  rows: 12, verdict: 'flat', sql: SQL_H5() },
  { id: 'h6', kind: 'hyp', x: 840, y: 535, w: 280, h: 88, parent: 'a4', metric: 'image · style + value',  dim: 'attribute T2B agreement',      rows:  9, verdict: 'sig', sql: SQL_H6() },

  // answer
  { id: 'ans', kind: 'answer', x: 1330, y: 290, w: 250, h: 100, label: 'Grounded answer · 5 citations', sub: 'recommend: double down on homeware' },
];

function SQL_H1() {
  return `SELECT
  brand,
  SUM(weight * (response_value = 1)::INT) /
  SUM(weight)                              AS prompted_awareness,
  COUNT(*)                                 AS n
FROM survey
WHERE question_code = 'QC01_AR'
  AND period IN ('P11-13 Q4 25/26')
GROUP BY brand
ORDER BY prompted_awareness DESC`;
}
function SQL_H2() {
  return `SELECT
  brand,
  category,
  SUM(weight * (response_value >= 6)::INT) /
  SUM(weight)                              AS t2b_future
FROM survey
WHERE question_code = 'QC03_FUT'
  AND category IN ('furniture','homeware')
GROUP BY brand, category`;
}
function SQL_H3() {
  return `SELECT
  category,
  SUM(weight * (brand_mentioned = 'Habitat')::INT) /
  SUM(weight)                              AS pct_assoc
FROM brand_association
WHERE period = 'P11-13 Q4 25/26'
GROUP BY category`;
}
function SQL_H4() {
  return `SELECT
  category,
  SUM(weight * (last_brand = 'Habitat')::INT) /
  SUM(weight)                              AS share_of_last
FROM purchase
WHERE category IN ('furniture','homeware')
GROUP BY category`;
}
function SQL_H5() {
  return `SELECT
  brand,
  AVG(consideration_t2b) AS share,
  rank() OVER (ORDER BY AVG(consideration_t2b) DESC) AS rk
FROM brand_funnel
WHERE brand IN ('Habitat','IKEA','Dunelm','John Lewis','Next','M&S')
GROUP BY brand`;
}
function SQL_H6() {
  return `SELECT
  attribute,
  AVG(t2b_agreement)              AS habitat_t2b,
  AVG(CASE WHEN brand='IKEA' THEN t2b_agreement END) AS ikea_t2b
FROM brand_image
WHERE attribute IN ('stylish','value','style_at_price')
GROUP BY attribute`;
}

// ──── Edge calculator ───────────────────────────────────────────────────

function edgePath(a, b) {
  // start at right edge of a, end at left edge of b
  const x1 = a.x + a.w, y1 = a.y + a.h / 2;
  const x2 = b.x,        y2 = b.y + b.h / 2;
  const mid = (x1 + x2) / 2;
  return `M ${x1} ${y1} C ${mid} ${y1}, ${mid} ${y2}, ${x2} ${y2}`;
}

// ──── Main component ────────────────────────────────────────────────────

function Slide2Graph() {
  // animate-in timing: 0=question, 1=angles, 2=hyps, 3=answer
  const [stage, setStage] = s2use(0);
  const [hover, setHover] = s2use(null);
  const [clicked, setClicked] = s2use('a2'); // default selected so the panel has content

  s2eff(() => {
    const timers = [
      setTimeout(() => setStage(1), 400),
      setTimeout(() => setStage(2), 1200),
      setTimeout(() => setStage(3), 2200),
      setTimeout(() => setStage(4), 2900),
    ];
    return () => timers.forEach(clearTimeout);
  }, []);

  const byId = s2mem(() => Object.fromEntries(NODES.map(n => [n.id, n])), []);
  const selected = hover || clicked;

  // Compute highlighted set (ancestors + descendants of selected)
  const highlighted = s2mem(() => {
    if (!selected) return new Set();
    const out = new Set([selected]);
    // walk up via parent
    let cur = byId[selected];
    while (cur && cur.parent) { out.add(cur.parent); cur = byId[cur.parent]; }
    // root question is parent of all angles
    if (selected.startsWith('a') || selected.startsWith('h')) out.add('q');
    // descendants
    const queue = [selected];
    while (queue.length) {
      const id = queue.shift();
      NODES.forEach(n => {
        if (n.parent === id) { out.add(n.id); queue.push(n.id); }
      });
    }
    // answer is always downstream of any hypothesis
    if (selected.startsWith('h') || selected.startsWith('a') || selected === 'q') out.add('ans');
    return out;
  }, [selected, byId]);

  const isHi = (id) => !selected || highlighted.has(id);

  // Build edges: angles ← question; hypotheses ← angles; answer ← hypotheses
  const edges = s2mem(() => {
    const es = [];
    NODES.filter(n => n.kind === 'angle').forEach(a => es.push({ from: 'q',   to: a.id, group: 'qa' }));
    NODES.filter(n => n.kind === 'hyp').forEach(h => es.push({ from: h.parent, to: h.id, group: 'ah' }));
    NODES.filter(n => n.kind === 'hyp').forEach(h => es.push({ from: h.id,    to: 'ans', group: 'ha' }));
    return es;
  }, []);

  const sel = selected ? byId[selected] : null;

  return (
    <div style={{
      flex: 1, minHeight: 0,
      display: 'grid',
      gridTemplateColumns: '1.55fr 1fr',
      gap: 28,
      marginTop: 22,
    }}>

      {/* LEFT — the graph */}
      <div style={{
        background: '#fff',
        border: `1px solid ${pitchC.hair}`,
        borderRadius: 14,
        padding: '18px 18px 12px',
        position: 'relative',
        overflow: 'hidden',
      }}>
        {/* column labels */}
        <div style={{
          display: 'grid',
          gridTemplateColumns: '195px 280px 280px 1fr',
          gap: 0,
          paddingLeft: 8, paddingRight: 8,
          marginBottom: 8,
          fontSize: 12,
          fontWeight: 600,
          letterSpacing: 0.18,
          textTransform: 'uppercase',
          color: pitchC.muted2,
          fontFamily: pitchMono,
        }}>
          <span>Question</span>
          <span>Investigation angles</span>
          <span style={{ paddingLeft: 16 }}>Hypotheses · SQL · verdict</span>
          <span style={{ textAlign: 'right' }}>Synthesis</span>
        </div>

        <svg viewBox="0 0 1620 680" style={{ width: '100%', height: '100%', display: 'block' }}>
          {/* edges */}
          {edges.map((e, i) => {
            const a = byId[e.from], b = byId[e.to];
            const visible =
              (e.group === 'qa' && stage >= 1) ||
              (e.group === 'ah' && stage >= 2) ||
              (e.group === 'ha' && stage >= 3);
            const dim = selected && !(highlighted.has(e.from) && highlighted.has(e.to));
            const stroke = dim ? '#e9e9ef' : (selected && highlighted.has(e.from) && highlighted.has(e.to) ? pitchC.orange : '#c8c8d0');
            return (
              <path
                key={i}
                d={edgePath(a, b)}
                fill="none"
                stroke={stroke}
                strokeWidth={dim ? 1.4 : (selected ? 2.4 : 1.8)}
                strokeLinecap="round"
                strokeDasharray="600"
                strokeDashoffset={visible ? 0 : 600}
                style={{
                  transition: 'stroke-dashoffset 700ms cubic-bezier(.2,.7,.2,1), stroke 240ms ease, stroke-width 240ms ease',
                  transitionDelay: visible ? `${(i % 6) * 60}ms` : '0ms',
                }}
              />
            );
          })}

          {/* nodes */}
          {NODES.map((n) => {
            const visible =
              (n.kind === 'question' && stage >= 0) ||
              (n.kind === 'angle'    && stage >= 1) ||
              (n.kind === 'hyp'      && stage >= 2) ||
              (n.kind === 'answer'   && stage >= 4);
            return (
              <g
                key={n.id}
                onMouseEnter={() => setHover(n.id)}
                onMouseLeave={() => setHover(null)}
                onClick={() => setClicked(n.id)}
                style={{
                  cursor: 'pointer',
                  opacity: visible ? (isHi(n.id) ? 1 : 0.32) : 0,
                  transform: visible ? 'translate(0,0)' : 'translate(0, 6px)',
                  transformOrigin: `${n.x + n.w / 2}px ${n.y + n.h / 2}px`,
                  transition: 'opacity 320ms ease, transform 320ms ease',
                }}
              >
                <NodeShape node={n} selected={selected === n.id} />
              </g>
            );
          })}
        </svg>
      </div>

      {/* RIGHT — detail inspector */}
      <div style={{
        background: '#fff',
        border: `1px solid ${pitchC.hair}`,
        borderRadius: 14,
        padding: '20px 22px',
        display: 'flex', flexDirection: 'column',
        minHeight: 0,
        gap: 14,
      }}>
        <NodeInspector node={sel} />
      </div>

    </div>
  );
}

// ──── Node visual ───────────────────────────────────────────────────────

function NodeShape({ node, selected }) {
  if (node.kind === 'question') {
    return (
      <g>
        <rect x={node.x} y={node.y} width={node.w} height={node.h}
          rx="14" ry="14"
          fill="#fff"
          stroke={selected ? pitchC.orange : pitchC.ink}
          strokeWidth={selected ? 2.5 : 1.5}
        />
        <rect x={node.x} y={node.y} width="5" height={node.h} rx="2" fill="url(#gradBrand)" />
        <text x={node.x + 22} y={node.y + 28} fontSize="11" fontWeight="700"
          fill={pitchC.navy} letterSpacing="2" fontFamily="JetBrains Mono">QUESTION</text>
        <foreignObject x={node.x + 22} y={node.y + 36} width={node.w - 32} height={node.h - 40}>
          <div xmlns="http://www.w3.org/1999/xhtml" style={{
            fontFamily: 'Hanken Grotesk, sans-serif',
            fontSize: 14.5, lineHeight: 1.25,
            color: pitchC.ink, fontWeight: 500,
          }}>{node.label}</div>
        </foreignObject>
        <defs>
          <linearGradient id="gradBrand" x1="0" y1="0" x2="0" y2="1">
            <stop offset="0%" stopColor="#ff663a" />
            <stop offset="50%" stopColor="#7f3399" />
            <stop offset="100%" stopColor="#000099" />
          </linearGradient>
        </defs>
      </g>
    );
  }
  if (node.kind === 'angle') {
    return (
      <g>
        <rect x={node.x} y={node.y} width={node.w} height={node.h}
          rx="12" ry="12"
          fill="#fff"
          stroke={selected ? pitchC.orange : node.color}
          strokeWidth={selected ? 2.5 : 1.6}
        />
        <rect x={node.x} y={node.y} width="4" height={node.h} rx="2" fill={node.color} />
        <text x={node.x + 18} y={node.y + 22} fontSize="10" fontWeight="700"
          fill={node.color} letterSpacing="2" fontFamily="JetBrains Mono">ANGLE</text>
        <text x={node.x + 18} y={node.y + 42} fontSize="15" fontWeight="600"
          fill={pitchC.ink} fontFamily="Hanken Grotesk">{node.label}</text>
        <text x={node.x + 18} y={node.y + 60} fontSize="12"
          fill={pitchC.muted} fontFamily="Hanken Grotesk">{node.sub}</text>
      </g>
    );
  }
  if (node.kind === 'hyp') {
    const vcolor = node.verdict === 'sig' ? pitchC.moss : node.verdict === 'flat' ? pitchC.muted2 : pitchC.ember;
    const vbg    = node.verdict === 'sig' ? pitchC.mossBg : '#f0f0f5';
    const vlabel = node.verdict === 'sig' ? 'SIG' : node.verdict === 'flat' ? 'FLAT' : 'FAIL';
    return (
      <g>
        <rect x={node.x} y={node.y} width={node.w} height={node.h}
          rx="10" ry="10"
          fill="#fff"
          stroke={selected ? pitchC.orange : pitchC.hair2}
          strokeWidth={selected ? 2.5 : 1.2}
        />
        <text x={node.x + 14} y={node.y + 22} fontSize="11" fontWeight="700"
          fill={pitchC.muted2} letterSpacing="1.6" fontFamily="JetBrains Mono">{node.id.toUpperCase()}</text>
        <text x={node.x + 14} y={node.y + 44} fontSize="13.5" fontWeight="600"
          fill={pitchC.ink} fontFamily="JetBrains Mono">{node.metric}</text>
        <text x={node.x + 14} y={node.y + 62} fontSize="12"
          fill={pitchC.muted} fontFamily="Hanken Grotesk">{node.dim}</text>
        {/* verdict pill */}
        <rect x={node.x + node.w - 60} y={node.y + 10} width="48" height="22" rx="11" ry="11"
          fill={vbg} stroke={vcolor} strokeWidth="1" />
        <text x={node.x + node.w - 36} y={node.y + 25} fontSize="10.5" fontWeight="700"
          textAnchor="middle"
          fill={vcolor} letterSpacing="1" fontFamily="JetBrains Mono">{vlabel}</text>
        {/* rows count */}
        <text x={node.x + node.w - 14} y={node.y + node.h - 12} fontSize="11"
          textAnchor="end"
          fill={pitchC.muted2} fontFamily="JetBrains Mono">{node.rows} rows</text>
      </g>
    );
  }
  if (node.kind === 'answer') {
    return (
      <g>
        <rect x={node.x} y={node.y} width={node.w} height={node.h}
          rx="14" ry="14"
          fill={selected ? pitchC.moss : '#fff'}
          stroke={selected ? pitchC.orange : pitchC.moss}
          strokeWidth={selected ? 2.5 : 1.8}
        />
        <text x={node.x + 18} y={node.y + 28} fontSize="11" fontWeight="700"
          fill={selected ? '#fff' : pitchC.moss} letterSpacing="2" fontFamily="JetBrains Mono">ANSWER</text>
        <foreignObject x={node.x + 18} y={node.y + 36} width={node.w - 32} height={node.h - 40}>
          <div xmlns="http://www.w3.org/1999/xhtml" style={{
            fontFamily: 'Hanken Grotesk, sans-serif',
            fontSize: 14, lineHeight: 1.25,
            color: selected ? '#fff' : pitchC.ink,
            fontWeight: 500,
          }}>{node.label}<br/><span style={{
            fontSize: 12, fontWeight: 400,
            color: selected ? '#e0f0e8' : pitchC.muted,
          }}>{node.sub}</span></div>
        </foreignObject>
      </g>
    );
  }
  return null;
}

// ──── Inspector panel ───────────────────────────────────────────────────

function NodeInspector({ node }) {
  if (!node) {
    return (
      <div style={{
        flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center',
        textAlign: 'center', color: pitchC.muted2, fontSize: 16,
      }}>
        Hover or click a node to inspect its tool call
      </div>
    );
  }

  if (node.kind === 'question') {
    return (
      <Inspector
        eyebrow="USER QUESTION"
        title={node.label}
        body={
          <div>
            <Row k="route"        v="research" />
            <Row k="time_context" v="P11-13 Q4 25/26" />
            <Row k="self_contained" v="true · catalog-grounded" />
            <Hint>The orchestrator routes between <code>respond</code> and <code>research</code>, resolves time refs to exact catalog periods, and rewrites ambiguous follow-ups as self-contained queries.</Hint>
          </div>
        }
      />
    );
  }
  if (node.kind === 'angle') {
    return (
      <Inspector
        eyebrow="INVESTIGATION ANGLE"
        title={node.label}
        body={
          <div>
            <Row k="dimension" v={node.sub} />
            <Row k="hypotheses" v={`${NODES.filter(h => h.parent === node.id).length} planned`} />
            <Hint>Angles are <code>angle_planner.py</code> templates. Each becomes one or more hypotheses expanded into H-queries the Basis Survey Agent can ground and execute.</Hint>
          </div>
        }
      />
    );
  }
  if (node.kind === 'hyp') {
    const vcolor = node.verdict === 'sig' ? pitchC.moss : pitchC.muted2;
    return (
      <Inspector
        eyebrow={`HYPOTHESIS · ${node.id.toUpperCase()}`}
        title={node.metric}
        body={
          <div style={{ display: 'flex', flexDirection: 'column', gap: 10, minHeight: 0, flex: 1 }}>
            <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
              <Chip label={`${node.rows} rows`} />
              <Chip label={node.dim} />
              <Chip label={node.verdict === 'sig' ? 'statistically significant' : 'no significant change'} color={vcolor} />
            </div>
            <div style={{ flex: 1, minHeight: 0 }}>
              <SqlBlock sql={node.sql} maxHeight={250} />
            </div>
          </div>
        }
      />
    );
  }
  if (node.kind === 'answer') {
    return (
      <Inspector
        eyebrow="ANSWER SYNTHESIS"
        title={node.label}
        body={
          <div>
            <Row k="claims_cited" v="5 (each opens its evidence)" />
            <Row k="key_findings" v="4 surfaced" />
            <Row k="hero_charts" v="2 consolidated across hypotheses" />
            <Hint>A single LLM pass over the grouped evidence — but it never authors a number. It can only cite claims it can't edit, each resolving to the frozen evidence that proves it.</Hint>
          </div>
        }
      />
    );
  }
  return null;
}

function Inspector({ eyebrow, title, body }) {
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 14, minHeight: 0, flex: 1 }}>
      <div style={{
        fontSize: 13, fontWeight: 700, letterSpacing: 2,
        color: pitchC.orange, fontFamily: pitchMono,
      }}>{eyebrow}</div>
      <div style={{
        fontSize: 24, lineHeight: 1.15, fontWeight: 500,
        color: pitchC.ink, fontFamily: 'Hanken Grotesk, sans-serif',
        letterSpacing: -0.005,
        marginTop: -6,
      }}>{title}</div>
      <div style={{ flex: 1, minHeight: 0, display: 'flex', flexDirection: 'column' }}>
        {body}
      </div>
    </div>
  );
}

function Row({ k, v }) {
  return (
    <div style={{
      display: 'grid', gridTemplateColumns: '130px 1fr',
      padding: '6px 0',
      borderTop: `1px solid ${pitchC.hair}`,
      fontSize: 14, fontFamily: pitchMono,
    }}>
      <span style={{ color: pitchC.muted2 }}>{k}</span>
      <span style={{ color: pitchC.ink }}>{v}</span>
    </div>
  );
}

function Chip({ label, color }) {
  return (
    <span style={{
      padding: '4px 10px',
      borderRadius: 999,
      background: color ? `${color}1f` : pitchC.bgSoft,
      color: color || pitchC.muted,
      fontFamily: pitchMono,
      fontSize: 12.5,
      fontWeight: 500,
      letterSpacing: -0.005,
      border: color ? `1px solid ${color}55` : `1px solid ${pitchC.hair}`,
    }}>{label}</span>
  );
}

function Hint({ children }) {
  return (
    <div style={{
      marginTop: 12, padding: '10px 12px',
      background: pitchC.bgSoft, borderRadius: 8,
      fontSize: 14, lineHeight: 1.35,
      color: pitchC.muted,
    }}>{children}</div>
  );
}

window.Slide2Graph = Slide2Graph;
