// Packet Bandit Lab — Shared UI Components (Enhanced)

// ── Particle background canvas ──
const ParticleBackground = () => {
  const canvasRef = React.useRef(null);
  React.useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    const ctx = canvas.getContext('2d');
    let w = canvas.width = window.innerWidth;
    let h = canvas.height = window.innerHeight;
    let animId;
    const reduceMotion =
      typeof window.matchMedia === 'function' &&
      window.matchMedia('(prefers-reduced-motion: reduce)').matches;

    // Particles
    const N = 120;
    const particles = Array.from({ length: N }, () => ({
      x: Math.random() * w,
      y: Math.random() * h,
      r: Math.random() * 1.5 + 0.3,
      vx: (Math.random() - 0.5) * 0.18,
      vy: (Math.random() - 0.5) * 0.18,
      alpha: Math.random() * 0.5 + 0.1,
      color: ['#f97316','#38bdf8','#8b5cf6','#ffffff'][Math.floor(Math.random()*4)],
    }));

    // Grid-like data lines
    const dataLines = Array.from({ length: 8 }, () => ({
      y: Math.random() * h,
      speed: Math.random() * 0.4 + 0.1,
      alpha: Math.random() * 0.07 + 0.02,
      width: Math.random() * 200 + 100,
    }));

    const draw = () => {
      ctx.clearRect(0, 0, w, h);

      // Radial bg gradient
      const grad = ctx.createRadialGradient(w * 0.2, 0, 0, w * 0.2, 0, w * 0.8);
      grad.addColorStop(0, '#0f172a');
      grad.addColorStop(0.4, '#020617');
      grad.addColorStop(1, '#000');
      ctx.fillStyle = grad;
      ctx.fillRect(0, 0, w, h);

      // Atmospheric orbs
      const orbs = [
        { x: w * -0.05, y: h * 0.05, r: 500, c: '#f97316', a: 0.10 },
        { x: w * 1.1, y: h * 0.35, r: 420, c: '#38bdf8', a: 0.09 },
        { x: w * 0.15, y: h * 0.75, r: 380, c: '#8b5cf6', a: 0.10 },
      ];
      orbs.forEach(o => {
        const g = ctx.createRadialGradient(o.x, o.y, 0, o.x, o.y, o.r);
        g.addColorStop(0, o.c + Math.round(o.a * 255).toString(16).padStart(2,'0'));
        g.addColorStop(1, 'transparent');
        ctx.fillStyle = g;
        ctx.beginPath();
        ctx.arc(o.x, o.y, o.r, 0, Math.PI * 2);
        ctx.fill();
      });

      // Scanlines
      for (let y = 0; y < h; y += 4) {
        ctx.fillStyle = 'rgba(0,0,0,0.025)';
        ctx.fillRect(0, y, w, 2);
      }

      // Data stream lines
      dataLines.forEach(dl => {
        dl.y += dl.speed;
        if (dl.y > h) dl.y = -10;
        ctx.strokeStyle = `rgba(56,189,248,${dl.alpha})`;
        ctx.lineWidth = 1;
        ctx.setLineDash([4, 8]);
        ctx.beginPath();
        ctx.moveTo(0, dl.y);
        ctx.lineTo(w, dl.y);
        ctx.stroke();
        ctx.setLineDash([]);
      });

      // Particles + connections
      particles.forEach((p, i) => {
        p.x += p.vx; p.y += p.vy;
        if (p.x < 0) p.x = w; if (p.x > w) p.x = 0;
        if (p.y < 0) p.y = h; if (p.y > h) p.y = 0;

        ctx.beginPath();
        ctx.arc(p.x, p.y, p.r, 0, Math.PI * 2);
        ctx.fillStyle = p.color + Math.round(p.alpha * 255).toString(16).padStart(2,'0');
        ctx.fill();

        // Connect nearby
        for (let j = i + 1; j < Math.min(i + 8, N); j++) {
          const q = particles[j];
          const dx = p.x - q.x, dy = p.y - q.y;
          const dist = Math.sqrt(dx*dx + dy*dy);
          if (dist < 100) {
            ctx.strokeStyle = `rgba(56,189,248,${0.04 * (1 - dist/100)})`;
            ctx.lineWidth = 0.5;
            ctx.beginPath();
            ctx.moveTo(p.x, p.y);
            ctx.lineTo(q.x, q.y);
            ctx.stroke();
          }
        }
      });

      if (!reduceMotion) animId = requestAnimationFrame(draw);
    };

    draw();

    const onResize = () => {
      w = canvas.width = window.innerWidth;
      h = canvas.height = window.innerHeight;
      if (reduceMotion) draw();
    };
    window.addEventListener('resize', onResize);
    return () => { cancelAnimationFrame(animId); window.removeEventListener('resize', onResize); };
  }, []);

  return (
    <canvas ref={canvasRef} style={{
      position: 'fixed', inset: 0, zIndex: 0, pointerEvents: 'none', display: 'block',
    }} />
  );
};

// ── Typewriter hook ──
const useTypewriter = (text, speed = 38, startDelay = 0) => {
  const [displayed, setDisplayed] = React.useState('');
  const [done, setDone] = React.useState(false);
  React.useEffect(() => {
    setDisplayed('');
    setDone(false);
    let i = 0;
    let tick;
    const start = setTimeout(() => {
      tick = setInterval(() => {
        i++;
        setDisplayed(text.slice(0, i));
        if (i >= text.length) { clearInterval(tick); setDone(true); }
      }, speed);
    }, startDelay);
    return () => { clearTimeout(start); clearInterval(tick); };
  }, [text, speed, startDelay]);
  return { displayed, done };
};

// ── Scroll reveal hook ──
const useScrollReveal = (threshold = 0.05) => {
  const ref = React.useRef(null);
  const [visible, setVisible] = React.useState(false);
  React.useEffect(() => {
    const el = ref.current;
    if (!el) return;
    // Fallback: always show after 1.2s even if IntersectionObserver doesn't fire
    const fallback = setTimeout(() => setVisible(true), 1200);
    const obs = new IntersectionObserver(([e]) => {
      if (e.isIntersecting) { setVisible(true); clearTimeout(fallback); obs.disconnect(); }
    }, { threshold, rootMargin: '0px 0px 60px 0px' });
    obs.observe(el);
    return () => { obs.disconnect(); clearTimeout(fallback); };
  }, []);
  return { ref, visible };
};

// ── BanditIcon ──
const BanditIcon = ({ size = 52 }) => (
  <img src="assets/packet-bandit-mascot.png" alt="Packet Bandit"
    style={{ width: size, height: size, borderRadius: '50%', objectFit: 'cover',
      objectPosition: 'center 18%', mixBlendMode: 'lighten', display: 'block', flexShrink: 0 }} />
);

// ── Terminal prompt label ──
const TermPrompt = ({ color = '#f97316', children }) => (
  <span style={{ fontFamily: 'ui-monospace,Menlo,monospace', fontSize: '0.78rem', letterSpacing: '0.04em' }}>
    <span style={{ color: '#4ade80' }}>root@bandit</span>
    <span style={{ color: '#9ca3af' }}>:</span>
    <span style={{ color: '#38bdf8' }}>~</span>
    <span style={{ color: '#9ca3af' }}>$ </span>
    <span style={{ color }}>{children}</span>
  </span>
);

// ── GlassCard ──
const GlassCard = ({ children, style = {}, glow = false }) => (
  <div style={{
    background: 'rgba(15,23,42,0.72)',
    border: `1px solid ${glow ? 'rgba(249,115,22,0.25)' : 'rgba(148,163,184,0.12)'}`,
    borderRadius: '0.85rem',
    boxShadow: glow ? '0 0 40px rgba(249,115,22,0.08), 0 24px 60px rgba(0,0,0,0.5)' : '0 24px 60px rgba(0,0,0,0.45)',
    backdropFilter: 'blur(16px)',
    WebkitBackdropFilter: 'blur(16px)',
    padding: '1.35rem',
    ...style,
  }}>
    {children}
  </div>
);

// ── TerminalCard — card with terminal chrome ──
const TerminalCard = ({ children, title = '', style = {}, accent = '#f97316' }) => (
  <div style={{
    background: 'rgba(2,6,23,0.85)',
    border: '1px solid rgba(148,163,184,0.15)',
    borderRadius: '0.75rem',
    boxShadow: '0 24px 60px rgba(0,0,0,0.5)',
    backdropFilter: 'blur(16px)',
    WebkitBackdropFilter: 'blur(16px)',
    overflow: 'hidden',
    ...style,
  }}>
    {/* Chrome bar */}
    <div style={{
      display: 'flex', alignItems: 'center', gap: '0.5rem',
      padding: '0.55rem 1rem',
      background: 'rgba(15,23,42,0.9)',
      borderBottom: `1px solid rgba(148,163,184,0.1)`,
    }}>
      <span style={{ width: 10, height: 10, borderRadius: '50%', background: '#ef4444', display: 'inline-block' }} />
      <span style={{ width: 10, height: 10, borderRadius: '50%', background: '#f59e0b', display: 'inline-block' }} />
      <span style={{ width: 10, height: 10, borderRadius: '50%', background: '#4ade80', display: 'inline-block' }} />
      {title && <span style={{ marginLeft: '0.5rem', fontFamily: 'ui-monospace,monospace', fontSize: '0.72rem', color: '#6b7280', letterSpacing: '0.04em' }}>{title}</span>}
      <span style={{ flex: 1 }} />
      <span style={{ width: 6, height: 6, borderRadius: '50%', background: accent, opacity: 0.7, boxShadow: `0 0 6px ${accent}` }} />
    </div>
    <div style={{ padding: '1.25rem' }}>
      {children}
    </div>
  </div>
);

// ── SectionHeading ──
const SectionHeading = ({ children, accent = false }) => (
  <div style={{
    fontSize: '0.72rem', fontWeight: 700, letterSpacing: '0.14em',
    textTransform: 'uppercase', color: accent ? '#f97316' : '#9ca3af',
    display: 'flex', alignItems: 'center', gap: '0.65rem',
    marginBottom: '1rem',
    fontFamily: 'ui-monospace,monospace',
  }}>
    <span style={{ color: '#4ade80', opacity: 0.7 }}>//</span>
    {children}
    <span style={{ flex: 1, height: '1px', background: 'rgba(148,163,184,0.1)' }} />
  </div>
);

// ── SectionDivider ──
const SectionDivider = () => (
  <hr style={{ width: '120px', height: '2px', background: 'linear-gradient(90deg,#f97316,#38bdf8)', border: 'none', margin: '0 auto 2rem' }} />
);

// ── Badge ──
const Badge = ({ children, color = 'orange' }) => {
  const colors = {
    orange: { bg: 'rgba(249,115,22,0.12)', text: '#f97316', border: 'rgba(249,115,22,0.28)' },
    blue:   { bg: 'rgba(56,189,248,0.12)',  text: '#38bdf8', border: 'rgba(56,189,248,0.28)' },
    purple: { bg: 'rgba(139,92,246,0.12)',  text: '#8b5cf6', border: 'rgba(139,92,246,0.28)' },
    green:  { bg: 'rgba(74,222,128,0.12)',  text: '#4ade80', border: 'rgba(74,222,128,0.28)' },
    web3:   { bg: 'rgba(139,92,246,0.15)',  text: '#a78bfa', border: 'rgba(139,92,246,0.35)' },
    amber:  { bg: 'rgba(245,158,11,0.12)',  text: '#f59e0b', border: 'rgba(245,158,11,0.28)' },
  };
  const c = colors[color] || colors.orange;
  return (
    <span style={{
      fontSize: '0.65rem', fontWeight: 700, letterSpacing: '0.12em', textTransform: 'uppercase',
      padding: '0.18rem 0.52rem', borderRadius: '999px',
      background: c.bg, color: c.text, border: `1px solid ${c.border}`,
      fontFamily: 'ui-monospace,monospace',
    }}>
      {children}
    </span>
  );
};

// ── Tag ──
const Tag = ({ children }) => (
  <span style={{
    fontSize: '0.68rem', padding: '0.12rem 0.42rem', borderRadius: '4px',
    background: 'rgba(56,189,248,0.07)', border: '1px solid rgba(56,189,248,0.18)', color: '#38bdf8',
    fontFamily: 'ui-monospace,monospace',
  }}>
    {children}
  </span>
);

// ── BtnPrimary ──
const BtnPrimary = ({ children, onClick, style = {} }) => {
  const [h, setH] = React.useState(false);
  return (
    <button onClick={onClick}
      onMouseEnter={() => setH(true)} onMouseLeave={() => setH(false)}
      style={{
        display: 'inline-flex', alignItems: 'center', gap: '0.45rem',
        background: 'linear-gradient(135deg,#f97316,#ea580c)', color: '#020617',
        fontWeight: 700, fontSize: '0.86rem', padding: '0.6rem 1.1rem',
        borderRadius: '999px', border: 'none', cursor: 'pointer', letterSpacing: '0.02em',
        transform: h ? 'translateY(-2px)' : 'none',
        boxShadow: h ? '0 10px 28px rgba(249,115,22,0.35)' : '0 4px 12px rgba(249,115,22,0.15)',
        transition: 'all 0.2s cubic-bezier(0.16,1,0.3,1)',
        ...style,
      }}>
      {children}
    </button>
  );
};

// ── BtnSecondary ──
const BtnSecondary = ({ children, onClick, style = {} }) => {
  const [h, setH] = React.useState(false);
  return (
    <button onClick={onClick}
      onMouseEnter={() => setH(true)} onMouseLeave={() => setH(false)}
      style={{
        display: 'inline-flex', alignItems: 'center', gap: '0.45rem',
        background: h ? 'rgba(56,189,248,0.08)' : 'rgba(15,23,42,0.5)',
        color: '#38bdf8', fontWeight: 600, fontSize: '0.86rem', padding: '0.6rem 1.1rem',
        borderRadius: '999px', border: `1px solid ${h ? 'rgba(56,189,248,0.35)' : 'rgba(148,163,184,0.18)'}`,
        cursor: 'pointer', letterSpacing: '0.02em',
        transform: h ? 'translateY(-1px)' : 'none',
        transition: 'all 0.2s cubic-bezier(0.16,1,0.3,1)',
        ...style,
      }}>
      {children}
    </button>
  );
};

// ── SectionRule ──
const SectionRule = ({ label }) => (
  <div style={{
    fontSize: '0.7rem', fontWeight: 700, letterSpacing: '0.14em', textTransform: 'uppercase',
    color: '#9ca3af', display: 'flex', alignItems: 'center', gap: '0.75rem', margin: '2.5rem 0 1.25rem',
    fontFamily: 'ui-monospace,monospace',
  }}>
    <span style={{ color: '#4ade80', opacity: 0.6 }}>▸</span>
    {label}
    <span style={{ flex: 1, height: '1px', background: 'linear-gradient(90deg, rgba(148,163,184,0.15), transparent)' }} />
  </div>
);

// ── PageFooter ──
const PageFooter = () => (
  <footer style={{ marginTop: '4rem', padding: '1.5rem 0', borderTop: '1px solid rgba(148,163,184,0.08)', textAlign: 'center' }}>
    <span style={{ fontFamily: 'ui-monospace,monospace', fontSize: '0.75rem', color: '#6b7280', letterSpacing: '0.06em' }}>
      <span style={{ color: '#4ade80' }}>●</span> Packet Bandit Lab{' '}
      <span style={{ color: 'rgba(148,163,184,0.3)' }}>·</span>{' '}
      Iterating in public.
    </span>
  </footer>
);

// ── RevealBlock — scroll-triggered fade-in ──
const RevealBlock = ({ children, delay = 0, style = {} }) => {
  const { ref, visible } = useScrollReveal();
  return (
    <div ref={ref} style={{
      opacity: visible ? 1 : 0,
      transform: visible ? 'translateY(0)' : 'translateY(32px)',
      transition: `opacity 0.9s cubic-bezier(0.16,1,0.3,1) ${delay}s, transform 0.9s cubic-bezier(0.16,1,0.3,1) ${delay}s`,
      ...style,
    }}>
      {children}
    </div>
  );
};

// ── GlitchText — subtle glitch on hover ──
const GlitchText = ({ children, style = {} }) => {
  const [glitch, setGlitch] = React.useState(false);
  return (
    <span
      onMouseEnter={() => { setGlitch(true); setTimeout(() => setGlitch(false), 400); }}
      style={{
        display: 'inline-block',
        position: 'relative',
        animation: glitch ? 'glitch 0.4s steps(2,end)' : 'none',
        ...style,
      }}
    >
      {children}
    </span>
  );
};

// Hover/tap scanner for the hero mascot.
const MascotScanner = ({ src, alt }) => {
  const [active, setActive] = React.useState(false);
  const [pos, setPos] = React.useState({ x: 50, y: 50 });
  const timerRef = React.useRef(null);

  const triggerScan = React.useCallback(() => {
    setActive(true);
    clearTimeout(timerRef.current);
    timerRef.current = setTimeout(() => setActive(false), 1450);
  }, []);

  const updatePointer = React.useCallback((event) => {
    const rect = event.currentTarget.getBoundingClientRect();
    const x = ((event.clientX - rect.left) / rect.width) * 100;
    const y = ((event.clientY - rect.top) / rect.height) * 100;
    setPos({
      x: Math.max(10, Math.min(90, x)),
      y: Math.max(10, Math.min(90, y)),
    });
  }, []);

  React.useEffect(() => () => clearTimeout(timerRef.current), []);

  const tiltX = (50 - pos.y) * 0.035;
  const tiltY = (pos.x - 50) * 0.045;

  return (
    <div
      className="mascot-scanner"
      role="button"
      tabIndex={0}
      aria-label="Scan Packet Bandit mascot"
      data-active={active ? 'true' : 'false'}
      onPointerEnter={triggerScan}
      onPointerMove={updatePointer}
      onPointerDown={triggerScan}
      onFocus={triggerScan}
      onKeyDown={(event) => {
        if (event.key === 'Enter' || event.key === ' ') {
          event.preventDefault();
          triggerScan();
        }
      }}
      style={{
        '--scanner-x': `${pos.x}%`,
        '--scanner-y': `${pos.y}%`,
        transform: `perspective(900px) rotateX(${tiltX}deg) rotateY(${tiltY}deg)`,
      }}
    >
      <div className="mascot-scanner__ring" aria-hidden="true" />
      <div className="mascot-scanner__frame">
        <img className="mascot-scanner__image" src={src} alt={alt} />
        <span className="mascot-scanner__beam" aria-hidden="true" />
        <span className="mascot-scanner__reticle" aria-hidden="true" />
        <span className="mascot-scanner__readout" aria-hidden="true">
          <span className="mascot-scanner__dot" />
          scan complete
        </span>
      </div>
    </div>
  );
};

// Step-through TCP three-way handshake. Educational interactive that
// teaches the SYN / SYN-ACK / ACK sequence and the half-open state that
// makes SYN flood DoS possible.
const TCP_STEPS = [
  {
    label: 'idle',
    packet: null,
    state: 'CLOSED',
    summary: 'No connection. Press Start — the client opens a socket and prepares a SYN.',
  },
  {
    label: 'SYN',
    packet: { direction: 'c2s', flags: 'SYN', seq: 'seq=x' },
    state: 'SYN-SENT',
    summary: 'Client picks a random ISN x and sends a SYN segment. It now waits for a reply.',
  },
  {
    label: 'SYN+ACK',
    packet: { direction: 's2c', flags: 'SYN+ACK', seq: 'seq=y, ack=x+1' },
    state: 'SYN-RCVD',
    summary: 'Server reserves a slot, picks its own ISN y, and answers with SYN+ACK acknowledging x+1.',
    note: 'If the client never sends step 3, this slot stays half-open. Flood thousands of these and the server\'s queue fills up — that\'s a SYN flood.',
  },
  {
    label: 'ACK',
    packet: { direction: 'c2s', flags: 'ACK', seq: 'seq=x+1, ack=y+1' },
    state: 'ESTABLISHED',
    summary: 'Client acknowledges y+1. Both sides agree on initial sequence numbers — connection is open.',
  },
];

const TCPHandshakeLab = () => {
  const [step, setStep] = React.useState(0);
  // `phase` is 'pre' just before a packet appears at the source, then
  // flips to 'post' on the next animation frame so the CSS transition fires.
  const [phase, setPhase] = React.useState('post');

  const current = TCP_STEPS[step];
  const packet = current.packet;

  React.useEffect(() => {
    if (!packet) return;
    let cancelled = false;
    setPhase('pre');
    const outer = requestAnimationFrame(() => {
      if (cancelled) return;
      requestAnimationFrame(() => {
        if (cancelled) return;
        setPhase('post');
      });
    });
    return () => { cancelled = true; cancelAnimationFrame(outer); };
  }, [step]);

  const packetLeft = !packet
    ? null
    : phase === 'pre'
      ? (packet.direction === 'c2s' ? 0 : 100)
      : (packet.direction === 'c2s' ? 100 : 0);

  const advance = () => setStep(s => Math.min(s + 1, TCP_STEPS.length - 1));
  const reset = () => { setStep(0); setPhase('post'); };

  const lastStep = TCP_STEPS.length - 1;
  const buttonLabel = step === 0 ? 'Start' : step === lastStep ? 'Done' : 'Next ▸';

  return (
    <div className="tcp-lab">
      <SectionHeading>TCP handshake</SectionHeading>

      <div className="tcp-lab__wire" aria-label="Three-way handshake animation">
        <div className="tcp-lab__endpoint" data-active={step >= 1}>
          <span className="tcp-lab__dot" />
          <span className="tcp-lab__label">CLIENT</span>
        </div>
        <div className="tcp-lab__line">
          {packet && (
            <span
              className={`tcp-lab__packet tcp-lab__packet--${packet.direction}`}
              style={{ left: `${packetLeft}%` }}
            >
              {packet.flags}
            </span>
          )}
        </div>
        <div className="tcp-lab__endpoint" data-active={step >= 2}>
          <span className="tcp-lab__dot" />
          <span className="tcp-lab__label">SERVER</span>
        </div>
      </div>

      {packet && (
        <div className="tcp-lab__header-readout" aria-live="polite">
          <span className="tcp-lab__flags">{packet.flags}</span>
          <span className="tcp-lab__seq">{packet.seq}</span>
        </div>
      )}

      <div className="tcp-lab__statusrow">
        <span>step {step}/{lastStep}</span>
        <span className={`tcp-lab__state tcp-lab__state--s${step}`}>{current.state}</span>
      </div>

      <div className="tcp-lab__dots" aria-hidden="true">
        {TCP_STEPS.map((_, i) => (
          <span key={i} className={`tcp-lab__progress ${i <= step ? 'is-on' : ''}`} />
        ))}
      </div>

      <div className="tcp-lab__actions">
        <button type="button" className="tcp-lab__btn" onClick={reset} disabled={step === 0}>↻ Reset</button>
        <button type="button" className="tcp-lab__btn tcp-lab__btn--primary" onClick={advance} disabled={step === lastStep}>
          {buttonLabel}
        </button>
      </div>

      <p className="tcp-lab__summary">{current.summary}</p>

      {current.note && (
        <p className="tcp-lab__note">
          <span className="tcp-lab__note-tag">⚠ security</span>
          {current.note}
        </p>
      )}
    </div>
  );
};

Object.assign(window, {
  ParticleBackground, useTypewriter, useScrollReveal,
  BanditIcon, TermPrompt, GlassCard, TerminalCard,
  SectionHeading, SectionDivider, Badge, Tag,
  BtnPrimary, BtnSecondary, SectionRule, PageFooter,
  RevealBlock, GlitchText, MascotScanner, TCPHandshakeLab,
});
