// 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 [compareA, setCompareA] = React.useState(null);
  const [compareB, setCompareB] = React.useState(null);
  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 [rebuildToast, setRebuildToast] = React.useState(null);

  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_ });
        setRebuildToast('Graph rebuilt successfully');
        setTimeout(() => setRebuildToast(null), 3000);
      }))
      .catch(() => {
        // Demo mode: simulate rebuild success
        setLastBuilt({ level, window_ });
        setGraphMeta(prev => ({...prev, builtAt: 'just now', actors: prev.actors + Math.floor(Math.random() * 500)}));
        setRebuildToast('Demo mode — graph rebuild simulated');
        setTimeout(() => setRebuildToast(null), 3000);
      })
      .finally(() => setRebuilding(false));
  };

  const byId = Object.fromEntries(states.map(s => [s.id, s]));

  const W = 1040, H = 440;

  return (
    <React.Fragment>
    <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];
            if (!a || !b) return null; // guard: skip edges referencing missing nodes
            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)', cursor: 'pointer'}}
                onClick={() => { if (window.AR_NAVIGATE) window.AR_NAVIGATE('insights'); }}>
                <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.', sev: 'CRITICAL' },
              { stage: 'add_to_cart → checkout_start', drop: 55, hyp: 'Shipping cost reveal at cart step correlates with drop-off.', sev: 'HIGH' },
              { stage: 'search → pdp', drop: 38, hyp: 'Search ranking for "premium" queries returns too few matches.', sev: 'MEDIUM' },
            ].map((b, i) => (
              <div key={i} style={{padding: 10, background: 'var(--bg-3)', borderRadius: 8, border: '1px solid var(--border)', cursor: 'pointer'}}
                onClick={() => {
                  try { sessionStorage.setItem('ar_decision_prefill', JSON.stringify({title: 'Fix bottleneck: ' + b.stage, description: b.hyp, severity: b.sev, fixes: []})); } catch(e) {}
                  if (window.AR_NAVIGATE) window.AR_NAVIGATE('insights');
                }}>
                <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 style={{fontSize: 10, color: 'var(--text-3)', marginTop: 4}}>Click → view in Insights</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, id: 'snap_0' },
              { ts: 'Yesterday 02:00', build: '82,940 actors', id: 'snap_1' },
              { ts: 'Apr 18 02:00', build: '81,110 actors', id: 'snap_2' },
              { ts: 'Apr 17 02:00', build: '79,284 actors', id: 'snap_3' },
            ].map((s, i) => {
              const isA = compareA === s.id, isB = compareB === s.id;
              return (
                <div key={i} onClick={() => {
                  if (!compareA) { setCompareA(s.id); }
                  else if (!compareB && s.id !== compareA) { setCompareB(s.id); }
                  else { setCompareA(s.id); setCompareB(null); }
                }} style={{display: 'flex', gap: 10, padding: '8px 10px', background: isA || isB ? 'rgba(139,92,246,0.12)' : s.cur ? 'rgba(139,92,246,0.04)' : 'var(--bg-3)', border: `1px solid ${isA||isB ? 'var(--accent)' : '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>}
                  {isA && <span className="badge cyan" style={{fontSize: 9}}>A</span>}
                  {isB && <span className="badge amber" style={{fontSize: 9}}>B</span>}
                </div>
              );
            })}
            {compareA && !compareB && (
              <div style={{fontSize: 11, color: 'var(--text-3)', padding: '6px 4px'}}>Select a second snapshot to compare →</div>
            )}
            {compareA && compareB && (
              <div style={{padding: 10, background: 'rgba(139,92,246,0.07)', border: '1px solid rgba(139,92,246,0.3)', borderRadius: 8, fontSize: 11}}>
                <div style={{color: 'var(--text-2)', marginBottom: 6}}>Comparing <span className="badge cyan" style={{fontSize: 9}}>A</span> vs <span className="badge amber" style={{fontSize: 9}}>B</span></div>
                <div style={{color: 'var(--emerald)', marginBottom: 2}}>+ checkout → purchase improved 5pp</div>
                <div style={{color: 'var(--rose)', marginBottom: 2}}>− add_to_cart → checkout dropped 3pp</div>
                <div style={{color: 'var(--text-3)'}}>+1,270 new actors resolved</div>
                <button className="btn" style={{marginTop: 8, fontSize: 11}} onClick={() => { setCompareA(null); setCompareB(null); }}>Clear</button>
              </div>
            )}
            {!compareA && (
              <div style={{fontSize: 11, color: 'var(--text-4)', padding: '4px', textAlign: 'center'}}>Click two snapshots to compare</div>
            )}
          </div>
        </div>
      </div>
    </div>
    {rebuildToast && (
      <div style={{position:'fixed',bottom:24,right:24,zIndex:2000,padding:'10px 18px',background:'var(--bg-3)',border:'1px solid var(--border)',color:'var(--text-2)',borderRadius:8,fontSize:12,boxShadow:'0 4px 20px rgba(0,0,0,0.4)'}}>
        ✅ {rebuildToast}
      </div>
    )}
    </React.Fragment>
  );
};

window.JourneyScreen = JourneyScreen;
