// Atlas — shared UI: global state, design tokens helpers, reusable components, SVGGraph
const { useState, useEffect, useRef, useCallback } = React;

// ── Global state (simple pub/sub) ──────────────────────────────────────────
const _initState = () => ({
  screen: localStorage.getItem('atlas.screen') || 'login',
  // Existing demo flags
  namingChoice: null,      // null | 'acompana' | 'resuelve' | 'dismissed'
  debtSigned: false,
  saldoComplete: false,
  submitted: false,
  reflectionDone: false,
  crunchMode: false,
  postSession: false,
  // MVP-mock extensions
  currentUserId:    localStorage.getItem('atlas.userId')    || null,
  currentCourseId:  localStorage.getItem('atlas.courseId')  || null,
  currentSessionId: localStorage.getItem('atlas.sessionId') || null,
  selectedStudentId: null,  // T02StudentCards expanded card
  perspective: 'student',   // 'student' | 'teacher' — flipped after S09Zoom
});
window._atlasS  = window._atlasS  || _initState();
window._atlasLs = window._atlasLs || [];

const _PERSIST_KEYS = { screen:'atlas.screen', currentUserId:'atlas.userId', currentCourseId:'atlas.courseId', currentSessionId:'atlas.sessionId' };

function setAtlasState(updates) {
  window._atlasS = { ...window._atlasS, ...updates };
  Object.entries(_PERSIST_KEYS).forEach(([k, lsKey]) => {
    if (updates[k] !== undefined) {
      if (updates[k] === null) localStorage.removeItem(lsKey);
      else localStorage.setItem(lsKey, updates[k]);
    }
  });
  window._atlasLs.forEach(fn => fn({ ...window._atlasS }));
}

function useAtlasState() {
  const [s, setS] = useState({ ...window._atlasS });
  useEffect(() => {
    const fn = ns => setS({ ...ns });
    window._atlasLs.push(fn);
    return () => { window._atlasLs = window._atlasLs.filter(f => f !== fn); };
  }, []);
  return [s, setAtlasState];
}

function navigate(screen) { setAtlasState({ screen }); }

// ── Token shorthands ──────────────────────────────────────────────────────
const T = {
  ink9:    'hsl(var(--atlas-ink-900))',
  ink8:    'hsl(var(--atlas-ink-800))',
  ink7:    'hsl(var(--atlas-ink-700))',
  ink5:    'hsl(var(--atlas-ink-500))',
  ink4:    'hsl(var(--atlas-ink-400))',
  paper0:  'hsl(var(--atlas-paper-50))',
  paper1:  'hsl(var(--atlas-paper-100))',
  paper2:  'hsl(var(--atlas-paper-200))',
  paper3:  'hsl(var(--atlas-paper-300))',
  paper4:  'hsl(var(--atlas-paper-400))',
  warm4:   'hsl(var(--atlas-warm-400))',
  warm5:   'hsl(var(--atlas-warm-500))',
  warm6:   'hsl(var(--atlas-warm-600))',
  warm7:   'hsl(var(--atlas-warm-700))',
  cool2:   'hsl(var(--atlas-cool-200))',
  cool4:   'hsl(var(--atlas-cool-400))',
  cool5:   'hsl(var(--atlas-cool-500))',
  cool7:   'hsl(var(--atlas-cool-700))',
  acc5:    'hsl(var(--atlas-accent-500))',
  acc6:    'hsl(var(--atlas-accent-600))',
  acc7:    'hsl(var(--atlas-accent-700))',
  crit5:   'hsl(var(--atlas-critical-500))',
  crit7:   'hsl(var(--atlas-critical-700))',
  serif:   'var(--atlas-font-display)',
  sans:    'var(--atlas-font-sans)',
  mono:    'var(--atlas-font-mono)',
};

// ── Primitive components ──────────────────────────────────────────────────

function AtlasLogo({ size = 18 }) {
  return (
    <span style={{ fontFamily: T.serif, fontSize: size, fontWeight: 500,
      color: T.ink9, letterSpacing: '-0.02em',
      fontVariationSettings: '"opsz" 18, "GRAD" 0' }}>atlas</span>
  );
}

function Btn({ children, onClick, variant = 'primary', size = 'md', disabled, style: ext }) {
  const [hov, setHov] = useState(false);
  const pad = { sm: '0.4rem 0.9rem', md: '0.6rem 1.4rem', lg: '0.75rem 2rem' };
  const fs  = { sm: '0.875rem', md: '1rem', lg: '1rem' };
  const base = {
    fontFamily: T.sans, fontWeight: 600, border: 'none', borderRadius: 6,
    cursor: disabled ? 'not-allowed' : 'pointer', minHeight: 44,
    transition: 'background 150ms, box-shadow 150ms, opacity 150ms',
    padding: pad[size], fontSize: fs[size], opacity: disabled ? 0.45 : 1,
    ...ext,
  };
  const v = {
    primary:   { background: hov ? T.acc7    : T.acc6,   color: T.paper0, boxShadow: hov ? 'var(--atlas-shadow-md)' : 'var(--atlas-shadow-sm)' },
    secondary: { background: 'transparent',              color: T.ink7,   border: `1px solid ${T.paper4}` },
    warm:      { background: 'transparent',              color: T.warm6,  border: `1px solid ${T.warm6}` },
    ghost:     { background: 'transparent',              color: T.ink5,   border: 'none' },
    calm:      { background: hov ? T.acc7    : T.acc6,   color: 'white',  boxShadow: 'var(--atlas-shadow-sm)' },
    danger:    { background: hov ? T.crit7   : T.crit5,  color: 'white' },
  };
  return (
    <button onClick={disabled ? undefined : onClick} style={{ ...base, ...v[variant] }}
      onMouseEnter={() => setHov(true)} onMouseLeave={() => setHov(false)}>
      {children}
    </button>
  );
}

function Card({ children, style }) {
  return (
    <div style={{ background: T.paper1, borderRadius: 8, padding: 20,
      boxShadow: 'var(--atlas-shadow-sm)', ...style }}>{children}</div>
  );
}

function Ref({ children }) {
  return (
    <span style={{ fontFamily: T.mono, fontSize: '0.8125rem',
      background: T.paper2, border: `1px solid ${T.paper4}`,
      borderRadius: 2, padding: '0.1em 0.35em' }}>{children}</span>
  );
}

function TopBar({ left, center, right, style }) {
  return (
    <div style={{ height: 48, background: T.paper0, borderBottom: `1px solid ${T.paper3}`,
      display: 'flex', alignItems: 'center', justifyContent: 'space-between',
      padding: '0 20px', flexShrink: 0, gap: 12, ...style }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>{left}</div>
      <div>{center}</div>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>{right}</div>
    </div>
  );
}

function Chip({ children, style }) {
  return (
    <span style={{ fontFamily: T.mono, fontSize: '0.75rem', fontWeight: 500,
      background: T.paper2, border: `1px solid ${T.paper4}`, borderRadius: 4,
      padding: '3px 8px', color: T.ink5, ...style }}>{children}</span>
  );
}

// ── SVGGraph ──────────────────────────────────────────────────────────────
// openAnimation: triggers the momento de oro sequence
// openedEdgeId: after animation, marks the edge as opened permanently
function SVGGraph({ nodes, edges, width = 560, height = 390, miniMode = false,
  openAnimation = false, onAnimDone, openedEdgeId: propOpenedEdgeId,
  onNodeClick, selectedNodeId }) {

  const [animPhase, setAnimPhase] = useState(0);
  // 0=idle 1=srcGlow 2=tgtTurn 3=edgeDraw 4=headline 5=done
  const [openedEdgeId, setOpenedEdgeId] = useState(propOpenedEdgeId || null);

  useEffect(() => {
    if (!openAnimation) return;
    const ts = [
      setTimeout(() => setAnimPhase(1), 150),
      setTimeout(() => setAnimPhase(2), 350),
      setTimeout(() => setAnimPhase(3), 450),
      setTimeout(() => setAnimPhase(4), 1050),
      setTimeout(() => {
        setAnimPhase(5);
        setOpenedEdgeId(AtlasData.animEdgeId);
        if (onAnimDone) onAnimDone();
      }, 1200),
    ];
    return () => ts.forEach(clearTimeout);
  }, [openAnimation]);

  const R = miniMode ? 16 : 22;
  const labelSize = miniMode ? 8 : 10;
  const monoSize  = miniMode ? 7 : 9;

  function getNodeById(id) { return nodes.find(n => n.id === id); }

  function getEdgeLine(edge) {
    const s = getNodeById(edge.src), t = getNodeById(edge.tgt);
    if (!s || !t) return null;
    const dx = t.x - s.x, dy = t.y - s.y;
    const len = Math.sqrt(dx*dx + dy*dy);
    if (len === 0) return null;
    const ux = dx/len, uy = dy/len;
    return {
      x1: s.x + ux*(R+2), y1: s.y + uy*(R+2),
      x2: t.x - ux*(R+8), y2: t.y - uy*(R+8),
      len: Math.round(len),
    };
  }

  const animEdge = edges.find(e => e.id === AtlasData.animEdgeId);
  const animTgtId = animEdge?.tgt;
  const animSrcId = animEdge?.src;

  return (
    <svg viewBox="0 0 580 395" width={width} height={height} style={{ overflow: 'visible' }}>
      <defs>
        <marker id="aw"  markerWidth="7" markerHeight="7" refX="6" refY="3.5" orient="auto"><path d="M0,0.5 L6,3.5 L0,6.5 Z" fill="hsl(var(--atlas-warm-400))"/></marker>
        <marker id="ac"  markerWidth="7" markerHeight="7" refX="6" refY="3.5" orient="auto"><path d="M0,0.5 L6,3.5 L0,6.5 Z" fill="hsl(var(--atlas-cool-400))"/></marker>
        <marker id="af"  markerWidth="7" markerHeight="7" refX="6" refY="3.5" orient="auto"><path d="M0,0.5 L6,3.5 L0,6.5 Z" fill="hsl(var(--atlas-cool-200))"/></marker>
      </defs>

      {/* Edges */}
      {edges.map(edge => {
        const p = getEdgeLine(edge);
        if (!p) return null;
        const isAnim      = edge.id === AtlasData.animEdgeId;
        const isNowOpen   = isAnim && (animPhase >= 3 || edge.id === openedEdgeId);
        const isSatisfied = edge.satisfied || edge.id === openedEdgeId;
        let stroke, sw, dash, marker, opacity = 1;

        if (isNowOpen || isSatisfied) {
          stroke = 'hsl(var(--atlas-warm-400))'; sw = 2; dash = 'none'; marker = 'url(#aw)';
        } else if (edge.gated) {
          stroke = 'hsl(var(--atlas-cool-400))'; sw = 1.5; dash = '6 4'; marker = 'url(#ac)';
        } else {
          stroke = 'hsl(var(--atlas-cool-200))'; sw = 1; dash = 'none'; marker = 'url(#af)'; opacity = 0.45;
        }

        return (
          <line key={edge.id}
            x1={p.x1} y1={p.y1} x2={p.x2} y2={p.y2}
            stroke={stroke} strokeWidth={sw}
            strokeDasharray={isAnim && animPhase === 3 ? `${p.len} ${p.len}` : dash}
            markerEnd={marker} opacity={opacity}
            className={isAnim && animPhase === 3 ? 'atlas-edge-draw' : ''}
            style={isAnim && animPhase === 3 ? { '--edge-len': `${p.len}px` } : {}}
          />
        );
      })}

      {/* Nodes */}
      {nodes.map(node => {
        const isAnimTgt = node.id === animTgtId;
        const isAnimSrc = node.id === animSrcId;
        const showGlow  = isAnimSrc && animPhase === 1;
        const isOpened  = isAnimTgt && animPhase >= 2;
        const isSelected = node.id === selectedNodeId;

        let fill, stroke, sw;
        if (isOpened) {
          fill = 'hsl(var(--atlas-warm-400))'; stroke = 'hsl(var(--atlas-warm-600))'; sw = 2;
        } else {
          const s = {
            locked:      ['hsl(var(--atlas-cool-700))', 'hsl(var(--atlas-cool-400))', 1],
            available:   [T.paper1,                     T.paper4,                     1],
            in_progress: ['hsl(var(--atlas-accent-100))','hsl(var(--atlas-accent-500))', 2],
            completed:   ['hsl(var(--atlas-warm-200))', 'hsl(var(--atlas-warm-500))',  1],
            gated:       ['hsl(var(--atlas-cool-500))', 'hsl(var(--atlas-cool-700))',  1],
          };
          [fill, stroke, sw] = s[node.state] || s.locked;
        }

        return (
          <g key={node.id} style={{ cursor: onNodeClick ? 'pointer' : 'default' }}
            onClick={() => onNodeClick?.(node.id)}>
            {/* Glow ring on src during anim */}
            {showGlow && (
              <circle cx={node.x} cy={node.y} r={R+10}
                fill="none" stroke="hsl(var(--atlas-warm-400))" strokeWidth={6} opacity={0.35}
                className="atlas-glow-fade" />
            )}
            {isSelected && (
              <circle cx={node.x} cy={node.y} r={R+4}
                fill="none" stroke={T.acc5} strokeWidth={2} opacity={0.6} />
            )}
            <circle cx={node.x} cy={node.y} r={R}
              fill={fill} stroke={stroke} strokeWidth={sw}
              className={isAnimTgt ? 'atlas-node-warm' : node.state === 'in_progress' ? 'atlas-node-pulse' : ''}
              style={{ transition: 'fill 400ms ease-out' }}
            />
            {/* Icon / short label inside */}
            {node.state === 'locked' && !isOpened ? (
              <text x={node.x} y={node.y+4} textAnchor="middle" fontSize={miniMode?9:12} fill="hsl(var(--atlas-ink-400))">⚿</text>
            ) : (
              <text x={node.x} y={node.y+4} textAnchor="middle"
                fontFamily={T.mono} fontSize={monoSize} fontWeight="700"
                fill={node.state==='gated' || isOpened ? 'white' : 'hsl(var(--atlas-ink-700))'}>
                {node.shortLabel}
              </text>
            )}
            {/* Label below */}
            <text x={node.x} y={node.y+R+14} textAnchor="middle"
              fontFamily={T.sans} fontSize={labelSize} fontWeight="500"
              fill={node.state==='locked' ? T.ink4 : T.ink5}>
              {node.label.length > 12 ? node.label.slice(0,11)+'…' : node.label}
            </text>
          </g>
        );
      })}

      {/* Opening headline — phase 4+ */}
      {animPhase >= 4 && (
        <text x={290} y={380} textAnchor="middle"
          fontFamily={T.serif} fontSize={13} fontWeight={500}
          fill="hsl(var(--atlas-warm-600))"
          className="atlas-fade-slide-up"
          fontVariationSettings='"opsz" 18'>
          Conexión desbloqueada: RL → RES
        </text>
      )}
    </svg>
  );
}

Object.assign(window, { useAtlasState, setAtlasState, navigate, T, AtlasLogo, Btn, Card, Ref, TopBar, Chip, SVGGraph });
