// Visualization components: Skills Constellation, Patent Rover, Career Timeline
// Theme via CSS vars: --accent, --fg, --bg, --muted, --surface

// ─────────────────────────────────────────────────────────────
// Skills Constellation — animated node graph, hoverable
// ─────────────────────────────────────────────────────────────
function SkillsConstellation({ height = 420 }) {
  const P = window.PAULYN;
  const isMobile = window.innerWidth <= 768;

  // Mobile: card-based layout
  if (isMobile) {
    return React.createElement(SkillsCardsMobile, null);
  }

  // Desktop: SVG constellation
  return React.createElement(SkillsConstellationSVG, { height });
}

function SkillsCardsMobile() {
  const P = window.PAULYN;
  const cats = Object.entries(P.skills);
  const [expanded, setExpanded] = React.useState(null);
  const catColors = ['#ff9ec7', '#a99eff', '#9ed3ff', '#ffd4a3', '#6eff9e', '#ff6fb5'];

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
      {cats.map(([cat, items], ci) => {
        const isOpen = expanded === ci;
        const color = catColors[ci % catColors.length];
        return (
          <div key={cat}>
            <button onClick={() => setExpanded(isOpen ? null : ci)}
              style={{
                width: '100%', textAlign: 'left', cursor: 'pointer',
                padding: '14px 16px', borderRadius: isOpen ? '14px 14px 0 0' : 14,
                background: isOpen ? 'var(--surface)' : 'transparent',
                border: '1px solid var(--hairline)',
                borderBottom: isOpen ? '1px solid var(--hairline)' : '1px solid var(--hairline)',
                fontFamily: 'inherit', color: 'var(--fg)',
                display: 'flex', alignItems: 'center', gap: 10,
                transition: 'background 0.2s',
              }}>
              <span style={{ width: 10, height: 10, borderRadius: 5, background: color, boxShadow: `0 0 8px ${color}`, flexShrink: 0 }} />
              <span style={{ fontSize: 14, fontWeight: 600, flex: 1 }}>{cat}</span>
              <span style={{ fontSize: 12, color: 'var(--muted)', marginRight: 4 }}>{items.length}</span>
              <span style={{ fontSize: 11, color: 'var(--muted)', transform: isOpen ? 'rotate(90deg)' : 'none', transition: 'transform 0.2s' }}>▸</span>
            </button>
            {isOpen && (
              <div style={{
                padding: '12px 16px', borderRadius: '0 0 14px 14px',
                background: 'var(--surface)', border: '1px solid var(--hairline)', borderTop: 'none',
                display: 'flex', flexWrap: 'wrap', gap: 8,
                animation: 'fadeIn 0.3s ease',
              }}>
                {items.map(item => (
                  <span key={item} style={{
                    fontSize: 12, padding: '6px 12px', borderRadius: 12,
                    background: `${color}18`, color: 'var(--fg)',
                    border: `1px solid ${color}33`,
                  }}>{item}</span>
                ))}
              </div>
            )}
          </div>
        );
      })}
    </div>
  );
}

function SkillsConstellationSVG({ height = 420 }) {
  const P = window.PAULYN;
  const svgRef = React.useRef(null);
  const [hover, setHover] = React.useState(null);
  const [size, setSize] = React.useState({ w: 600, h: height });

  React.useEffect(() => {
    const el = svgRef.current?.parentElement;
    if (!el) return;
    const ro = new ResizeObserver(() => setSize({ w: el.clientWidth, h: height }));
    ro.observe(el);
    return () => ro.disconnect();
  }, [height]);

  // Layout: categories around a circle; items around their category
  const cats = Object.entries(P.skills);
  const cx = size.w / 2, cy = size.h / 2;
  const catR = Math.min(size.w, size.h) * 0.28;
  const itemR = Math.min(size.w, size.h) * 0.44;

  const nodes = [];
  const edges = [];
  cats.forEach(([cat, items], ci) => {
    const angle = (ci / cats.length) * Math.PI * 2 - Math.PI / 2;
    const ccx = cx + Math.cos(angle) * catR;
    const ccy = cy + Math.sin(angle) * catR;
    const catId = `cat-${ci}`;
    nodes.push({ id: catId, x: ccx, y: ccy, label: cat, type: 'cat', ci });
    edges.push({ from: 'center', to: catId });
    items.forEach((item, ii) => {
      const spread = Math.PI / (items.length + 2);
      const a = angle + (ii - (items.length - 1) / 2) * spread * 0.7;
      const r = itemR + (ii % 2) * 20;
      const ix = cx + Math.cos(a) * r;
      const iy = cy + Math.sin(a) * r;
      const nid = `${catId}-${ii}`;
      nodes.push({ id: nid, x: ix, y: iy, label: item, type: 'item', ci });
      edges.push({ from: catId, to: nid });
    });
  });
  const nmap = Object.fromEntries(nodes.map(n => [n.id, n]));
  nmap.center = { x: cx, y: cy };

  const activeCat = hover?.type === 'cat' ? hover.ci : hover?.type === 'item' ? hover.ci : null;

  return (
    <div style={{ position: 'relative', height, width: '100%' }}>
      <svg ref={svgRef} width="100%" height={height} style={{ overflow: 'visible' }}>
        <defs>
          <radialGradient id="constel-glow">
            <stop offset="0%" stopColor="var(--accent)" stopOpacity="0.4" />
            <stop offset="100%" stopColor="var(--accent)" stopOpacity="0" />
          </radialGradient>
        </defs>
        <circle cx={cx} cy={cy} r={catR * 1.8} fill="url(#constel-glow)" />
        {edges.map((e, i) => {
          const a = nmap[e.from], b = nmap[e.to];
          if (!a || !b) return null;
          const isActive = activeCat !== null && (b.ci === activeCat || a.ci === activeCat);
          return <line key={i} x1={a.x} y1={a.y} x2={b.x} y2={b.y}
            stroke="var(--accent)" strokeOpacity={isActive ? 0.6 : 0.15} strokeWidth={isActive ? 1.2 : 0.6} style={{ transition: 'all 0.2s' }} />;
        })}
        <circle cx={cx} cy={cy} r={18} fill="var(--accent)" />
        <circle cx={cx} cy={cy} r={28} fill="none" stroke="var(--accent)" strokeOpacity={0.3} >
          <animate attributeName="r" values="28;38;28" dur="3s" repeatCount="indefinite" />
          <animate attributeName="stroke-opacity" values="0.3;0;0.3" dur="3s" repeatCount="indefinite" />
        </circle>
        <text x={cx} y={cy + 4} textAnchor="middle" fill="var(--on-accent,#fff)" fontSize="10" fontWeight="700" style={{ pointerEvents: 'none' }}>PO</text>
        {nodes.map(n => {
          const isHover = hover?.id === n.id;
          const dim = activeCat !== null && n.ci !== activeCat && n.id !== 'center';
          const r = n.type === 'cat' ? (isHover ? 10 : 8) : (isHover ? 5 : 3.5);
          return (
            <g key={n.id} style={{ cursor: 'pointer', opacity: dim ? 0.25 : 1, transition: 'opacity 0.2s' }}
              onMouseEnter={() => setHover(n)} onMouseLeave={() => setHover(null)} onClick={() => setHover(prev => prev?.id === n.id ? null : n)}>
              <circle cx={n.x} cy={n.y} r={r + 8} fill="transparent" />
              <circle cx={n.x} cy={n.y} r={r} fill={n.type === 'cat' ? 'var(--accent)' : 'var(--fg)'} style={{ transition: 'r 0.2s' }} />
              {n.type === 'cat' && (
                <text x={n.x} y={n.y - 14} textAnchor="middle" fill="var(--fg)" fontSize="11" fontWeight="600" style={{ pointerEvents: 'none' }}>{n.label}</text>
              )}
              {isHover && n.type === 'item' && (
                <g style={{ pointerEvents: 'none' }}>
                  <rect x={n.x + 8} y={n.y - 12} width={n.label.length * 6.5 + 12} height={20} rx={10} fill="var(--surface)" stroke="var(--accent)" strokeOpacity="0.3" />
                  <text x={n.x + 14} y={n.y + 2} fill="var(--fg)" fontSize="11" fontWeight="500">{n.label}</text>
                </g>
              )}
            </g>
          );
        })}
      </svg>
      {hover && (
        <div style={{ position: 'absolute', bottom: 8, left: 12, fontSize: 11, color: 'var(--muted)', letterSpacing: 0.5, textTransform: 'uppercase' }}>
          {hover.type === 'cat' ? 'Category' : 'Skill'} · {hover.label}
        </div>
      )}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Patent Rover Viz — animated terrain scan
// ─────────────────────────────────────────────────────────────
function PatentRover({ height = 260 }) {
  const [t, setT] = React.useState(0);
  React.useEffect(() => {
    let raf;
    const start = performance.now();
    const tick = (now) => { setT((now - start) / 1000); raf = requestAnimationFrame(tick); };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, []);

  const w = 520, h = height;
  // Terrain path — sinusoidal
  const terrain = [];
  for (let x = 0; x <= w; x += 10) {
    const y = h - 40 - Math.sin(x * 0.02) * 14 - Math.sin(x * 0.008 + 1) * 10;
    terrain.push([x, y]);
  }
  const terrainD = `M 0 ${h} L ${terrain.map(p => p.join(' ')).join(' L ')} L ${w} ${h} Z`;

  // Rovers positions
  const rovers = [
    { speed: 28, offset: 0, color: 'var(--accent)' },
    { speed: 22, offset: 120, color: 'var(--accent-2, var(--accent))' },
    { speed: 25, offset: 300, color: 'var(--accent)' },
  ];

  // Victim location
  const victim = { x: 380, y: h - 60 };

  return (
    <svg viewBox={`0 0 ${w} ${h}`} width="100%" height={h} style={{ display: 'block' }}>
      <defs>
        <linearGradient id="sky-grad" x1="0" x2="0" y1="0" y2="1">
          <stop offset="0%" stopColor="var(--surface)" />
          <stop offset="100%" stopColor="var(--bg)" />
        </linearGradient>
        <radialGradient id="pulse-grad">
          <stop offset="0%" stopColor="var(--accent)" stopOpacity="0.5" />
          <stop offset="100%" stopColor="var(--accent)" stopOpacity="0" />
        </radialGradient>
      </defs>
      <rect width={w} height={h} fill="url(#sky-grad)" />
      {/* stars */}
      {[[60, 40], [130, 25], [220, 55], [340, 30], [450, 50], [480, 20]].map(([x, y], i) => (
        <circle key={i} cx={x} cy={y} r="1" fill="var(--fg)" opacity={0.3 + 0.3 * Math.sin(t * 2 + i)} />
      ))}
      {/* Victim signal pulses */}
      {[0, 1, 2].map(i => {
        const phase = (t + i * 0.8) % 2.4;
        const r = phase * 40;
        const op = Math.max(0, 1 - phase / 2.4);
        return <circle key={i} cx={victim.x} cy={victim.y} r={r} fill="none" stroke="var(--accent)" strokeOpacity={op * 0.6} strokeWidth="1.5" />;
      })}
      <circle cx={victim.x} cy={victim.y} r="4" fill="var(--accent)" />
      <text x={victim.x} y={victim.y - 14} textAnchor="middle" fontSize="9" fill="var(--fg)" opacity="0.8" fontFamily="monospace">SIGNAL</text>

      {/* terrain */}
      <path d={terrainD} fill="var(--muted-bg, rgba(0,0,0,0.06))" />
      <path d={`M 0 ${h - 40} ${terrain.map(p => 'L ' + p.join(' ')).join(' ')}`} fill="none" stroke="var(--fg)" strokeOpacity="0.3" strokeWidth="1" />

      {/* rovers */}
      {rovers.map((r, i) => {
        const x = (r.offset + t * r.speed) % w;
        const ty = h - 40 - Math.sin(x * 0.02) * 14 - Math.sin(x * 0.008 + 1) * 10 - 10;
        const dist = Math.hypot(x - victim.x, ty - victim.y);
        const connected = dist < 150;
        return (
          <g key={i}>
            {connected && (
              <line x1={x} y1={ty} x2={victim.x} y2={victim.y} stroke="var(--accent)" strokeOpacity="0.4" strokeWidth="0.8" strokeDasharray="3 2" />
            )}
            <circle cx={x} cy={ty + 25} r="18" fill="url(#pulse-grad)" />
            {/* Rover body */}
            <rect x={x - 6} y={ty - 4} width="12" height="8" rx="1.5" fill={r.color} />
            <rect x={x - 4} y={ty - 6} width="8" height="3" fill={r.color} />
            {/* antenna */}
            <line x1={x} y1={ty - 6} x2={x + 3} y2={ty - 14} stroke={r.color} strokeWidth="1" />
            <circle cx={x + 3} cy={ty - 14} r="1.5" fill={r.color}>
              <animate attributeName="r" values="1.5;2.5;1.5" dur="1s" repeatCount="indefinite" />
            </circle>
            {/* wheels */}
            <circle cx={x - 4} cy={ty + 4} r="2" fill="var(--fg)" opacity="0.7" />
            <circle cx={x + 4} cy={ty + 4} r="2" fill="var(--fg)" opacity="0.7" />
          </g>
        );
      })}

      {/* Label */}
      <g fontFamily='"JetBrains Mono", monospace' fontSize="10" fill="var(--fg)" opacity="0.7">
        <text x="14" y="20">U.S. PATENT 12,302,448</text>
        <text x="14" y="34" opacity="0.5">rescue_rover.sys // distributed signal detection</text>
      </g>
    </svg>
  );
}

// ─────────────────────────────────────────────────────────────
// Career Timeline — scroll-driven / interactive steps
// ─────────────────────────────────────────────────────────────
function CareerTimeline() {
  const P = window.PAULYN;
  const steps = [
    { year: 'Georgia State', title: 'B.S. Computer Science', body: `Dean's List. Concentration: Computer Software Systems.`, tag: 'Education' },
    { year: '2020', title: 'Software Engineer · Macy\'s Technology', body: 'Self-checkout with React + Spring Boot. REST APIs for transaction processing. JMeter perf testing on GCP.', tag: 'First role' },
    { year: '2020→', title: 'Joined T-Mobile', body: 'Started on enterprise B2B platforms. Angular micro-frontends, Spring Boot microservices across AWS & Azure.', tag: 'T-Mobile' },
    { year: '2022', title: 'Promoted to Lead FSE', body: 'Own technical direction for user access, subscription, and enterprise platform capabilities serving 1K+ users.', tag: 'Lead' },
    { year: '2023', title: 'AI Workflow Architecture', body: 'Began architecting AI-assisted workflows — prompt libraries, context-rich agents. Drove 3–5× personal velocity.', tag: 'AI' },
    { year: '2024', title: '25% Team Delivery Speed-up', body: 'Coached team on agentic workflows. Standardized CI/CD with DevOps. Mentored 4+ engineers.', tag: 'Impact' },
    { year: 'May 2025', title: 'U.S. Patent Issued', body: 'Rescue Rover — distributed mobile signal detection for search-and-rescue. Patent No. 12,302,448.', tag: 'Patent' },
    { year: 'Now', title: 'Building what\'s next', body: 'Scaling AI-native engineering culture. Finding big problems worth solving.', tag: 'Present' },
  ];

  const [active, setActive] = React.useState(steps.length - 1);

  return (
    <div style={{ display: 'flex', gap: 32, alignItems: 'stretch' }}>
      {/* left: step list */}
      <div style={{ flex: '0 0 200px', borderRight: '1px solid var(--hairline, rgba(0,0,0,0.08))', paddingRight: 16 }}>
        {steps.map((s, i) => (
          <button key={i} onClick={() => setActive(i)}
            style={{ display: 'block', width: '100%', textAlign: 'left', background: 'transparent', border: 'none', cursor: 'pointer',
              padding: '10px 12px', borderRadius: 8, marginBottom: 4, fontFamily: 'inherit', fontSize: 13,
              color: i === active ? 'var(--fg)' : 'var(--muted)', fontWeight: i === active ? 600 : 400,
              background: i === active ? 'var(--surface)' : 'transparent', transition: 'all 0.15s' }}>
            <div style={{ fontSize: 10, letterSpacing: 1, textTransform: 'uppercase', opacity: 0.6, marginBottom: 2 }}>{s.year}</div>
            <div style={{ fontSize: 13 }}>{s.tag}</div>
          </button>
        ))}
      </div>
      {/* right: active step detail */}
      <div style={{ flex: 1, padding: '8px 4px', minHeight: 260 }}>
        <div key={active} style={{ animation: 'fadeIn 0.4s ease' }}>
          <div style={{ fontFamily: '"JetBrains Mono", monospace', fontSize: 11, letterSpacing: 1, textTransform: 'uppercase', color: 'var(--accent)', marginBottom: 6 }}>{steps[active].year}</div>
          <h3 style={{ fontSize: 24, fontWeight: 600, margin: '0 0 10px', color: 'var(--fg)', letterSpacing: -0.4 }}>{steps[active].title}</h3>
          <p style={{ fontSize: 15, lineHeight: 1.6, color: 'var(--muted)', margin: 0, maxWidth: 480 }}>{steps[active].body}</p>

          {/* Progress dots */}
          <div style={{ display: 'flex', gap: 6, marginTop: 32 }}>
            {steps.map((_, i) => (
              <button key={i} onClick={() => setActive(i)}
                style={{ width: i === active ? 24 : 8, height: 8, borderRadius: 4, border: 'none',
                  background: i <= active ? 'var(--accent)' : 'var(--hairline, rgba(0,0,0,0.1))', cursor: 'pointer', transition: 'all 0.2s' }} />
            ))}
          </div>
        </div>
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Architecture Diagram — animated system view
// ─────────────────────────────────────────────────────────────
function ArchitectureDiagram({ height = 300 }) {
  const [t, setT] = React.useState(0);
  React.useEffect(() => {
    let raf;
    const start = performance.now();
    const tick = (now) => { setT((now - start) / 1000); raf = requestAnimationFrame(tick); };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, []);

  const w = 640, h = height;
  // Nodes: user → MFE shell → micro-frontends → API gateway → services → dbs
  const layers = [
    { label: 'Users · 1K+', x: 40, nodes: [{ y: h/2, r: 14, label: '👥' }] },
    { label: 'Angular Shell', x: 130, nodes: [{ y: h/2, r: 16, label: 'MFE' }] },
    { label: 'Micro-Frontends', x: 225, nodes: [{ y: 60, r: 12, label: 'Access' }, { y: h/2, r: 12, label: 'Subs' }, { y: h - 60, r: 12, label: 'Admin' }] },
    { label: 'API / Spring Boot', x: 340, nodes: [{ y: 80, r: 12, label: 'Auth' }, { y: h/2, r: 12, label: 'Orch' }, { y: h - 80, r: 12, label: 'Data' }] },
    { label: 'MongoDB', x: 455, nodes: [{ y: 80, r: 12, label: '🍃' }, { y: h - 80, r: 12, label: '🍃' }] },
    { label: 'AWS · Azure', x: 560, nodes: [{ y: 80, r: 12, label: '☁️' }, { y: h - 80, r: 12, label: '☁️' }] },
  ];

  // Packets travelling along edges
  const edges = [];
  for (let i = 0; i < layers.length - 1; i++) {
    layers[i].nodes.forEach(a => {
      layers[i+1].nodes.forEach(b => {
        edges.push({ x1: layers[i].x, y1: a.y, x2: layers[i+1].x, y2: b.y });
      });
    });
  }

  return (
    <svg viewBox={`0 0 ${w} ${h}`} width="100%" height={h} style={{ display: 'block' }}>
      {edges.map((e, i) => {
        const phase = ((t * 0.3) + i * 0.07) % 1;
        return (
          <g key={i}>
            <line x1={e.x1} y1={e.y1} x2={e.x2} y2={e.y2} stroke="var(--fg)" strokeOpacity="0.08" strokeWidth="1" />
            <circle cx={e.x1 + (e.x2 - e.x1) * phase} cy={e.y1 + (e.y2 - e.y1) * phase} r="2" fill="var(--accent)" opacity={Math.sin(phase * Math.PI)} />
          </g>
        );
      })}
      {layers.map((layer, li) => (
        <g key={li}>
          <text x={layer.x} y={h - 10} textAnchor="middle" fontSize="10" fontFamily='"JetBrains Mono", monospace' fill="var(--muted)">{layer.label}</text>
          {layer.nodes.map((n, ni) => (
            <g key={ni}>
              <circle cx={layer.x} cy={n.y} r={n.r + 4} fill="var(--accent)" opacity="0.1" />
              <circle cx={layer.x} cy={n.y} r={n.r} fill="var(--surface)" stroke="var(--accent)" strokeWidth="1.5" />
              <text x={layer.x} y={n.y + 3} textAnchor="middle" fontSize="9" fill="var(--fg)" fontWeight="500">{n.label}</text>
            </g>
          ))}
        </g>
      ))}
    </svg>
  );
}

Object.assign(window, { SkillsConstellation, PatentRover, CareerTimeline, ArchitectureDiagram });
