// SCREEN: Journey Map — pre-laid-out Markov-ish graph
const JourneyScreen = () => {
  const [selectedNode, setSelectedNode] = React.useState(null);
  const [level, setLevel] = React.useState('L2');
  const [window_, setWindow] = React.useState('30d');
  const [states, setStates] = React.useState(MOCK.journeyStates);
  const [edges, setEdges] = React.useState(MOCK.journeyEdges);
  const [graphMeta, setGraphMeta] = React.useState({
    actors: 84210,
    nodes: MOCK.journeyStates.length,
    edges: MOCK.journeyEdges.length,
    builtAt: '4m ago',
  });
  const [rebuilding, setRebuilding] = React.useState(false);
  const [lastBuilt, setLastBuilt] = React.useState({ level: 'L2', window_: '30d' });
  const [selectedSnaps, setSelectedSnaps] = React.useState([]);
  const [compareMode, setCompareMode] = React.useState(false);

  const loadGraph = () => {
    return arFetch('/v1/world/journey_graph/latest')
      .then(data => {
        const mapped = window.mapJourneyGraph(data);
        if (mapped.nodes.length > 0) {
          setStates(mapped.nodes);
          setEdges(mapped.edges);
        }
        const meta = data.metadata || {};
        setGraphMeta({
          actors: meta.total_actors || 84210,
          nodes: (data.nodes || []).length,
          edges: (data.edges || []).length,
          builtAt: data.created_at ? new Date(data.created_at).toLocaleTimeString() : '—',
        });
      })
      .catch(() => {}); // keep MOCK states/edges on error
  };

  React.useEffect(() => { loadGraph(); }, []);

  const handleRebuild = () => {
    setRebuilding(true);
    const windowDays = parseInt(window_) || 30;
    arFetch('/v1/world/journey_graph:build', {
      method: 'POST',
      body: JSON.stringify({ level, window_days: windowDays }),
    })
      .then(() => loadGraph().then(() => setLastBuilt({ level, window_ })))
      .catch(() => {})
      .finally(() => setRebuilding(false));
  };

  const byId = Object.fromEntries(states.map(s => [s.id, s]));

  const W = 1040, H = 440;

  return (
    <div>
      <AICallout>
        The <strong>checkout → purchase</strong> edge shows a <strong>61% drop-off</strong>, up from
        52% last week. The <strong>meta → product_view → add_to_cart</strong> path converts 2.1× better than other entry channels.
      </AICallout>

      <div style={{display: 'flex', gap: 10, alignItems: 'center', marginBottom: 14}}>
        <div className="seg">
          <button className={level === 'L1' ? 'active' : ''} onClick={() => setLevel('L1')}>L1 coarse</button>
          <button className={level === 'L2' ? 'active' : ''} onClick={() => setLevel('L2')}>L2 fine</button>
        </div>
        <div className="seg">
          {['7d','14d','30d','90d'].map(w => (
            <button key={w} className={window_ === w ? 'active' : ''} onClick={() => setWindow(w)}>{w}</button>
          ))}
        </div>
        <span className="mono" style={{fontSize: 11, color: 'var(--text-3)', marginLeft: 8}}>
          Last built: {graphMeta.builtAt} · {graphMeta.actors.toLocaleString()} actors · {graphMeta.nodes} states · {graphMeta.edges} transitions
        </span>
        {(level !== lastBuilt.level || window_ !== lastBuilt.window_) && (
          <span style={{fontSize: 10, color: 'var(--amber)', marginLeft: 4}}>● rebuild needed</span>
        )}
        <button className="btn primary" style={{marginLeft: 'auto'}} onClick={handleRebuild} disabled={rebuilding}>
          <Icon name="refresh" size={12} /> {rebuilding ? 'Rebuilding…' : 'Rebuild graph'}
        </button>
      </div>

      <div className="card" style={{padding: 0, overflow: 'hidden'}}>
        <svg viewBox={`0 0 ${W} ${H}`} width="100%" height={H} style={{display: 'block', background: 'radial-gradient(ellipse at center, #11172a 0%, #0B0F1A 100%)'}}>
          {/* Grid dots */}
          {Array.from({length: 40}).map((_, i) => {
            const x = 30 + (i % 10) * 110, y = 30 + Math.floor(i/10) * 110;
            return <circle key={i} cx={x} cy={y} r="1" fill="#1f2738" />;
          })}

          <defs>
            <marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
              <path d="M0 0 L10 5 L0 10 z" fill="#4A5268" />
            </marker>
            <marker id="arrow-conv" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
              <path d="M0 0 L10 5 L0 10 z" fill="#10B981" />
            </marker>
            <marker id="arrow-drop" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
              <path d="M0 0 L10 5 L0 10 z" fill="#F43F5E" />
            </marker>
          </defs>

          {/* Edges */}
          {edges.map((e, i) => {
            const a = byId[e.from], b = byId[e.to];
            const mx = (a.x + b.x) / 2;
            const my = (a.y + b.y) / 2 - 20;
            const d = `M ${a.x+28} ${a.y} Q ${mx} ${my} ${b.x-28} ${b.y}`;
            const color = e.drop ? '#F43F5E' : e.conv ? '#10B981' : '#4A5268';
            const opacity = e.conv ? 0.9 : e.drop ? 0.75 : 0.55;
            const marker = e.drop ? 'url(#arrow-drop)' : e.conv ? 'url(#arrow-conv)' : 'url(#arrow)';
            return (
              <g key={i}>
                <path d={d} fill="none" stroke={color} strokeWidth={1 + e.p * 5} opacity={opacity} markerEnd={marker} />
                <text x={mx} y={my - 4} fontSize="9" fill={color} textAnchor="middle" fontFamily="var(--mono)" opacity="0.9">{(e.p*100).toFixed(0)}%</text>
              </g>
            );
          })}

          {/* Nodes */}
          {states.map(s => {
            const r = 14 + Math.sqrt(s.visits) / 30;
            const isStart = s.kind === 'start', isConv = s.kind === 'convert', isDrop = s.kind === 'drop';
            const fill = isStart ? '#8B5CF6' : isConv ? '#10B981' : isDrop ? '#F43F5E' : '#1A2030';
            const stroke = isStart ? '#c4b5fd' : isConv ? '#6ee7b7' : isDrop ? '#fda4af' : '#2E3649';
            const sel = selectedNode === s.id;
            return (
              <g key={s.id} style={{cursor: 'pointer'}} onClick={() => setSelectedNode(s.id)}>
                {sel && <circle cx={s.x} cy={s.y} r={r + 6} fill="none" stroke="#8B5CF6" strokeWidth="2" opacity="0.5"><animate attributeName="r" from={r+4} to={r+10} dur="1.4s" repeatCount="indefinite" /><animate attributeName="opacity" from="0.6" to="0" dur="1.4s" repeatCount="indefinite" /></circle>}
                <circle cx={s.x} cy={s.y} r={r} fill={fill} stroke={stroke} strokeWidth={sel ? 2 : 1.5} className="node-circle" />
                <text x={s.x} y={s.y + r + 14} textAnchor="middle" fontSize="10" fill="#F4F6FB" fontFamily="var(--mono)">{s.label}</text>
                <text x={s.x} y={s.y + r + 26} textAnchor="middle" fontSize="9" fill="#6B7489" fontFamily="var(--mono)">{s.visits.toLocaleString()}</text>
              </g>
            );
          })}
        </svg>
      </div>

      {selectedNode && (() => {
        const node = states.find(s => s.id === selectedNode);
        if (!node) return null;
        const outEdges = edges.filter(e => e.from === selectedNode);
        return (
          <div className="card" style={{marginTop: 10, padding: '12px 16px', display: 'flex', gap: 24, alignItems: 'flex-start'}}>
            <div>
              <div style={{fontSize: 10, color: 'var(--text-3)', textTransform: 'uppercase', letterSpacing: '0.08em', marginBottom: 4}}>Selected node</div>
              <div className="mono" style={{fontSize: 13, color: 'var(--text-1)'}}>{node.label}</div>
              <div style={{fontSize: 11, color: 'var(--text-3)', marginTop: 2}}>{node.visits?.toLocaleString()} visits</div>
            </div>
            {outEdges.length > 0 && (
              <div>
                <div style={{fontSize: 10, color: 'var(--text-3)', textTransform: 'uppercase', letterSpacing: '0.08em', marginBottom: 6}}>Outbound transitions</div>
                <div style={{display: 'flex', flexDirection: 'column', gap: 4}}>
                  {outEdges.slice(0, 5).map((e, i) => {
                    const target = states.find(s => s.id === e.to);
                    return (
                      <div key={i} style={{display: 'flex', gap: 8, alignItems: 'center', fontSize: 11}}>
                        <span style={{color: e.drop ? 'var(--rose)' : e.conv ? 'var(--emerald)' : 'var(--text-2)'}} className="mono">{target?.label || e.to}</span>
                        <span style={{color: 'var(--text-3)'}}>{(e.p * 100).toFixed(0)}%</span>
                        {e.drop && <span className="badge" style={{background: 'rgba(244,63,94,0.15)', color: 'var(--rose)', fontSize: 9}}>DROP</span>}
                        {e.conv && <span className="badge" style={{background: 'rgba(16,185,129,0.15)', color: 'var(--emerald)', fontSize: 9}}>CONV</span>}
                      </div>
                    );
                  })}
                </div>
              </div>
            )}
            <button className="btn ghost" style={{marginLeft: 'auto', fontSize: 11}} onClick={() => setSelectedNode(null)}>✕ dismiss</button>
          </div>
        );
      })()}

      <div style={{display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 14, marginTop: 14}}>
        <div className="card">
          <div className="card-title" style={{marginBottom: 12}}>Top conversion paths</div>
          <div style={{display: 'flex', flexDirection: 'column', gap: 10}}>
            {MOCK.insights.topPaths.slice(0, 4).map((p, i) => (
              <div key={i} style={{padding: 10, background: 'var(--bg-3)', borderRadius: 8, border: '1px solid var(--border)'}}>
                <div style={{display: 'flex', gap: 6, flexWrap: 'wrap', alignItems: 'center', marginBottom: 6}}>
                  {p.steps.map((s, j) => (
                    <React.Fragment key={j}>
                      <span className="mono" style={{fontSize: 10, padding: '2px 6px', background: 'var(--bg-1)', borderRadius: 3, color: 'var(--text-2)'}}>{s}</span>
                      {j < p.steps.length - 1 && <span style={{color: 'var(--text-4)', fontSize: 10}}>›</span>}
                    </React.Fragment>
                  ))}
                </div>
                <div style={{display: 'flex', justifyContent: 'space-between', fontSize: 11}}>
                  <span className="badge green">{p.rate}% conv</span>
                  <span className="mono" style={{color: 'var(--text-3)'}}>{p.count} actors</span>
                </div>
              </div>
            ))}
          </div>
        </div>

        <div className="card">
          <div className="card-title" style={{marginBottom: 12}}>Bottlenecks detected</div>
          <div style={{display: 'flex', flexDirection: 'column', gap: 10}}>
            {[
              { stage: 'checkout_start → purchase', drop: 61, hyp: 'Guest checkout friction on mobile is likely causing abandonment spike.' },
              { stage: 'add_to_cart → checkout_start', drop: 55, hyp: 'Shipping cost reveal at cart step correlates with drop-off.' },
              { stage: 'search → pdp', drop: 38, hyp: 'Search ranking for "premium" queries returns too few matches.' },
            ].map((b, i) => (
              <div key={i} style={{padding: 10, background: 'var(--bg-3)', borderRadius: 8, border: '1px solid var(--border)'}}>
                <div style={{display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 4}}>
                  <span className="mono" style={{fontSize: 11, color: 'var(--text-1)'}}>{b.stage}</span>
                  <span style={{color: 'var(--rose)', fontSize: 14, fontWeight: 600}}>{b.drop}%</span>
                </div>
                <div style={{fontSize: 11, color: 'var(--text-2)', fontStyle: 'italic', lineHeight: 1.5}}>{b.hyp}</div>
              </div>
            ))}
          </div>
        </div>

        <div className="card">
          <div className="card-title" style={{marginBottom: 12}}>Graph snapshots</div>
          <div style={{display: 'flex', flexDirection: 'column', gap: 8}}>
            {[
              { ts: 'Today 10:42', build: '84,210 actors', cur: true },
              { ts: 'Yesterday 02:00', build: '82,940 actors' },
              { ts: 'Apr 18 02:00', build: '81,110 actors' },
              { ts: 'Apr 17 02:00', build: '79,284 actors' },
            ].map((s, i) => {
              const isSelected = selectedSnaps.some(x => x.ts === s.ts);
              return (
                <div key={i}
                  onClick={() => {
                    setCompareMode(false);
                    setSelectedSnaps(prev => {
                      if (prev.some(x => x.ts === s.ts)) return prev.filter(x => x.ts !== s.ts);
                      if (prev.length >= 2) return prev;
                      return [...prev, s];
                    });
                  }}
                  style={{
                    display: 'flex', gap: 10, padding: '8px 10px',
                    background: isSelected ? 'rgba(139,92,246,0.12)' : s.cur ? 'rgba(139,92,246,0.08)' : 'var(--bg-3)',
                    border: isSelected ? '1px solid var(--accent)' : '1px solid var(--border)',
                    borderRadius: 6, cursor: 'pointer',
                  }}>
                  <span style={{fontSize: 11, color: 'var(--text-1)'}}>{s.ts}</span>
                  <span className="mono" style={{fontSize: 10, color: 'var(--text-3)', marginLeft: 'auto'}}>{s.build}</span>
                  {s.cur && <span className="badge violet">current</span>}
                </div>
              );
            })}
            <button className="btn" style={{marginTop: 6, justifyContent: 'center'}}
              onClick={() => selectedSnaps.length === 2 && setCompareMode(true)}
              disabled={selectedSnaps.length < 2}>
              Compare {selectedSnaps.length}/2 selected →
            </button>
            {compareMode && (
              <div style={{marginTop: 14, padding: 14, background: 'var(--bg-3)', borderRadius: 8, border: '1px solid var(--border)'}}>
                <div style={{display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 12}}>
                  <span style={{fontSize: 13, fontWeight: 600}}>Snapshot Diff</span>
                  <button className="btn ghost" style={{fontSize: 11}} onClick={() => setCompareMode(false)}>✕ Close</button>
                </div>
                <div style={{display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 14}}>
                  {selectedSnaps.map((s, i) => (
                    <div key={i} style={{background: 'var(--bg-2)', borderRadius: 6, padding: 10, border: '1px solid var(--border)'}}>
                      <div style={{fontSize: 10, fontFamily: 'var(--mono)', color: 'var(--text-3)', marginBottom: 6}}>{s.ts}</div>
                      <div style={{fontSize: 12, color: 'var(--text-2)', marginBottom: 4}}>Build: {s.build}</div>
                      <div style={{fontSize: 11, color: 'var(--text-3)'}}>Top transitions: start→page_view 0.84 · page_view→pdp 0.31 · pdp→cart 0.12</div>
                    </div>
                  ))}
                </div>
                <div style={{fontSize: 11, color: 'var(--text-3)', marginTop: 10, padding: '8px 0', borderTop: '1px solid var(--border)'}}>
                  Δ probability shown. Values &gt;5pp change highlighted in amber when live data available.
                </div>
              </div>
            )}
          </div>
        </div>
      </div>
    </div>
  );
};

window.JourneyScreen = JourneyScreen;
