/* ============================================================
   EFFECTS — terminal, decrypted text, type-on, live ticker, icons
   ============================================================ */
const { useState: useState_e, useEffect: useEffect_e, useRef: useRef_e } = React;

function LogoMark({ size = 24 }) {
  return (
    <svg width={size} height={size} viewBox="0 0 32 32" fill="none" style={{ overflow: 'visible' }}>
      <rect x="2" y="2" width="28" height="28" stroke="currentColor" strokeWidth="1" opacity="0.35" />
      <rect x="7" y="7" width="18" height="18" stroke="currentColor" strokeWidth="1" opacity="0.7" />
      <rect x="13" y="13" width="6" height="6" fill="currentColor" />
      <line x1="16" y1="0" x2="16" y2="4" stroke="currentColor" strokeWidth="1" />
      <line x1="16" y1="28" x2="16" y2="32" stroke="currentColor" strokeWidth="1" />
      <line x1="0" y1="16" x2="4" y2="16" stroke="currentColor" strokeWidth="1" />
      <line x1="28" y1="16" x2="32" y2="16" stroke="currentColor" strokeWidth="1" />
    </svg>
  );
}

function DecryptedText({ text, speed = 38, className = '', trigger = 'view' }) {
  const [out, setOut] = useState_e(text);
  const ref = useRef_e(null);
  const startedRef = useRef_e(false);

  useEffect_e(() => {
    const start = () => {
      if (startedRef.current) return;
      startedRef.current = true;
      const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()_+-={}[]|:;<>?/';
      let frame = 0;
      const total = text.length;
      const stepsPerChar = 3;
      const totalSteps = total * stepsPerChar;
      const id = setInterval(() => {
        frame++;
        const revealed = Math.floor(frame / stepsPerChar);
        let str = '';
        for (let i = 0; i < total; i++) {
          if (i < revealed) str += text[i];
          else if (text[i] === ' ') str += ' ';
          else str += chars[Math.floor(Math.random() * chars.length)];
        }
        setOut(str);
        if (frame >= totalSteps) { clearInterval(id); setOut(text); }
      }, speed);
      return () => clearInterval(id);
    };
    if (trigger === 'view') {
      const io = new IntersectionObserver((entries) => { entries.forEach((e) => { if (e.isIntersecting) start(); }); }, { threshold: 0.2 });
      if (ref.current) io.observe(ref.current);
      return () => io.disconnect();
    } else {
      const t = setTimeout(start, 80);
      return () => clearTimeout(t);
    }
  }, [text, speed, trigger]);

  return <span ref={ref} className={className}>{out}</span>;
}

function TypeLines({ lines, speed = 28, pauseEnd = 1600, className = '' }) {
  const [idx, setIdx] = useState_e(0);
  const [out, setOut] = useState_e('');
  const [phase, setPhase] = useState_e('type');

  useEffect_e(() => {
    const current = lines[idx];
    if (phase === 'type') {
      if (out.length < current.length) {
        const t = setTimeout(() => setOut(current.slice(0, out.length + 1)), speed);
        return () => clearTimeout(t);
      }
      const t = setTimeout(() => setPhase('erase'), pauseEnd);
      return () => clearTimeout(t);
    } else {
      if (out.length > 0) {
        const t = setTimeout(() => setOut(current.slice(0, out.length - 1)), speed / 2);
        return () => clearTimeout(t);
      }
      setPhase('type');
      setIdx((i) => (i + 1) % lines.length);
    }
  }, [out, phase, idx, lines, speed, pauseEnd]);

  return <span className={className}>{out}<span className="caret" /></span>;
}

const TERMINAL_SCRIPT = [
  { t: 0, line: '$ cyrion engage --target acme.corp --mode autonomous', kind: 'cmd' },
  { t: 320, line: '» initializing agent swarm — 8 vCPU / 32G ram', kind: 'sys' },
  { t: 560, line: '» loading exploit corpus    [████████████] 248,317 modules', kind: 'sys' },
  { t: 880, line: '[01] recon       ', kind: 'step', sub: 'scanning *.acme.corp · 142 hosts · 18 services', color: 'accent' },
  { t: 1380, line: '    └─ found    api.acme.corp / 443  · staging-v2.acme.corp / 8443', kind: 'log' },
  { t: 1780, line: '[02] surface     ', kind: 'step', sub: 'fingerprinting · classifying · prioritizing', color: 'accent' },
  { t: 2280, line: '    └─ classified  graphql · s3-bucket(pub) · jwt-rsa256 · admin-portal', kind: 'log' },
  { t: 2780, line: '[03] vector      ', kind: 'step', sub: 'agent.beta hypothesizing 6 attack paths', color: 'amber' },
  { t: 3280, line: '    └─ chain     IDOR → priv-esc → cred-exfil  · confidence 0.94', kind: 'log' },
  { t: 3780, line: '[04] exploit     ', kind: 'step', sub: 'generating PoC · sandboxed validation', color: 'red' },
  { t: 4380, line: '    └─ confirmed CVE candidate · CRIT · CVSS 9.4', kind: 'log-red' },
  { t: 4880, line: '[05] report      ', kind: 'step', sub: 'remediation steps · ticket draft · audit trail', color: 'green' },
  { t: 5380, line: '    └─ artifact  acme-2026-04.pdf · 47 findings · 0 false-positives', kind: 'log-green' },
  { t: 5780, line: '» session complete · 6m 12s · drift < 0.3% ', kind: 'sys' },
];

function Terminal() {
  const [step, setStep] = useState_e(0);
  const [tick, setTick] = useState_e(0);
  const containerRef = useRef_e(null);

  useEffect_e(() => {
    const timers = TERMINAL_SCRIPT.map((entry, i) => setTimeout(() => setStep(i + 1), entry.t + tick));
    const restart = setTimeout(() => { setStep(0); setTick((x) => x + 1); }, 8400);
    return () => { timers.forEach(clearTimeout); clearTimeout(restart); };
  }, [tick]);

  useEffect_e(() => { const el = containerRef.current; if (el) el.scrollTop = el.scrollHeight; }, [step]);

  const visible = TERMINAL_SCRIPT.slice(0, step);

  return (
    <div className="card" style={{ background: '#0b0c0f', overflow: 'hidden', position: 'relative' }}>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '12px 16px', borderBottom: '1px solid var(--line)', background: 'var(--bg-lift)' }}>
        <div style={{ display: 'flex', gap: 6 }}>
          <span style={{ width: 8, height: 8, background: '#3a3e47' }} />
          <span style={{ width: 8, height: 8, background: '#3a3e47' }} />
          <span style={{ width: 8, height: 8, background: 'var(--accent)', boxShadow: '0 0 8px var(--accent-shadow)' }} />
        </div>
        <div className="caption" style={{ fontSize: 10 }}>cyrion · ssh · agent-swarm-01</div>
        <div className="caption tnum" style={{ fontSize: 10, color: 'var(--accent)' }}>●&nbsp; ACTIVE</div>
      </div>
      <div ref={containerRef} style={{ padding: '20px 22px', fontSize: 12.5, lineHeight: 1.7, height: 420, overflow: 'hidden', position: 'relative' }}>
        {visible.map((entry, i) => <TerminalLine key={i} entry={entry} />)}
        {step < TERMINAL_SCRIPT.length && <span className="caret" />}
        <div className="scanlines" />
      </div>
    </div>
  );
}

function TerminalLine({ entry }) {
  const stepColors = { accent: 'var(--accent)', amber: 'var(--amber)', red: 'var(--red)', green: 'var(--green)' };
  if (entry.kind === 'cmd') return <div style={{ color: 'var(--ink)', whiteSpace: 'pre' }}><span style={{ color: 'var(--accent)' }}>{entry.line.slice(0, 1)}</span>{entry.line.slice(1)}</div>;
  if (entry.kind === 'sys') return <div style={{ color: 'var(--ink-dim)', whiteSpace: 'pre' }}>{entry.line}</div>;
  if (entry.kind === 'step') return (
    <div style={{ display: 'flex', alignItems: 'baseline', gap: 12, whiteSpace: 'pre' }}>
      <span style={{ color: stepColors[entry.color] || 'var(--accent)', fontWeight: 600 }}>{entry.line}</span>
      <span style={{ color: 'var(--ink-mute)' }}>{entry.sub}</span>
    </div>
  );
  if (entry.kind === 'log') return <div style={{ color: 'var(--ink-mute)', whiteSpace: 'pre' }}>{entry.line}</div>;
  if (entry.kind === 'log-red') return <div style={{ color: 'var(--ink-mute)', whiteSpace: 'pre' }}>{entry.line}<span style={{ color: 'var(--red)' }}> ◆</span></div>;
  if (entry.kind === 'log-green') return <div style={{ color: 'var(--green)', whiteSpace: 'pre' }}>{entry.line}</div>;
  return <div>{entry.line}</div>;
}

const CVE_FEED = [
  { id: 'CVE-2026-0481', sev: 'CRIT', asset: 'graphql / api.acme', action: 'patched', time: '00:02' },
  { id: 'CVE-2026-0476', sev: 'HIGH', asset: 's3 / backups-prod', action: 'validated', time: '00:14' },
  { id: 'CVE-2026-0463', sev: 'CRIT', asset: 'jwt / auth-svc-2', action: 'exploited', time: '00:47' },
  { id: 'CVE-2026-0457', sev: 'MED', asset: 'next.js / marketing-v3', action: 'queued', time: '01:12' },
  { id: 'CVE-2026-0451', sev: 'HIGH', asset: 'kube / clstr-eu-1', action: 'isolated', time: '01:38' },
  { id: 'CVE-2026-0443', sev: 'CRIT', asset: 'github-actions / ci-deploy', action: 'exploited', time: '02:04' },
  { id: 'CVE-2026-0439', sev: 'LOW', asset: 'lambda / image-resize', action: 'ignored', time: '02:21' },
  { id: 'CVE-2026-0431', sev: 'HIGH', asset: 'redis / cache-eu-3', action: 'patched', time: '02:55' },
];

function Ticker() {
  const items = [...CVE_FEED, ...CVE_FEED];
  return (
    <div className="marquee" style={{ borderTop: '1px solid var(--line)', borderBottom: '1px solid var(--line)', padding: '14px 0' }}>
      <div className="marquee-track">
        {items.map((it, i) => (
          <div key={i} style={{ display: 'flex', alignItems: 'center', gap: 14, whiteSpace: 'nowrap', fontSize: 12 }}>
            <span className="dim tnum">{it.time}</span>
            <SevDot sev={it.sev} />
            <span className="ink tnum">{it.id}</span>
            <span className="dim">·</span>
            <span className="mute">{it.asset}</span>
            <span className="dim">→</span>
            <span style={{ color: it.action === 'exploited' ? 'var(--red)' : it.action === 'patched' ? 'var(--green)' : 'var(--ink-mute)' }}>{it.action}</span>
            <span style={{ color: 'var(--ink-faint)', fontSize: 18, lineHeight: 1 }}>—</span>
          </div>
        ))}
      </div>
    </div>
  );
}

function SevDot({ sev }) {
  const map = { CRIT: { c: 'var(--red)', label: 'CRIT' }, HIGH: { c: 'var(--amber)', label: 'HIGH' }, MED: { c: 'var(--accent)', label: 'MED ' }, LOW: { c: 'var(--ink-dim)', label: 'LOW ' } };
  const v = map[sev] || map.LOW;
  return <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6, fontSize: 10, letterSpacing: '0.1em', color: v.c }}><span style={{ width: 6, height: 6, background: v.c, boxShadow: `0 0 8px ${v.c}` }} />{v.label}</span>;
}

function Counter({ to, suffix = '', duration = 1400, prefix = '' }) {
  const [n, setN] = useState_e(0);
  const ref = useRef_e(null);
  useEffect_e(() => {
    let raf, start;
    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => {
        if (e.isIntersecting) {
          const tick = (ts) => {
            if (!start) start = ts;
            const k = Math.min(1, (ts - start) / duration);
            const eased = 1 - Math.pow(1 - k, 3);
            setN(to * eased);
            if (k < 1) raf = requestAnimationFrame(tick); else setN(to);
          };
          raf = requestAnimationFrame(tick);
          io.disconnect();
        }
      });
    }, { threshold: 0.4 });
    if (ref.current) io.observe(ref.current);
    return () => { io.disconnect(); cancelAnimationFrame(raf); };
  }, [to, duration]);
  const display = Number.isInteger(to) ? Math.round(n).toLocaleString() : n.toFixed(1);
  return <span ref={ref} className="tnum">{prefix}{display}{suffix}</span>;
}

function Glitch({ children }) {
  const [hover, setHover] = useState_e(false);
  return (
    <span onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)} style={{ position: 'relative', display: 'inline-block' }}>
      <span style={{ position: 'relative', zIndex: 2 }}>{children}</span>
      {hover && (
        <>
          <span aria-hidden style={{ position: 'absolute', left: 2, top: 0, color: 'var(--accent)', opacity: 0.65, mixBlendMode: 'screen', clipPath: 'inset(0 0 50% 0)' }}>{children}</span>
          <span aria-hidden style={{ position: 'absolute', left: -2, top: 0, color: 'var(--red)', opacity: 0.4, mixBlendMode: 'screen', clipPath: 'inset(50% 0 0 0)' }}>{children}</span>
        </>
      )}
    </span>
  );
}

function Reveal({ children, delay = 0, as = 'div', className = '', style }) {
  const ref = useRef_e(null);
  const [inView, setInView] = useState_e(false);
  useEffect_e(() => {
    const io = new IntersectionObserver((entries) => { entries.forEach((e) => { if (e.isIntersecting) { setInView(true); io.disconnect(); } }); }, { threshold: 0.15, rootMargin: '0px 0px -40px 0px' });
    if (ref.current) io.observe(ref.current);
    return () => io.disconnect();
  }, []);
  const Cmp = as;
  return <Cmp ref={ref} className={`reveal${inView ? ' in-view' : ''}${className ? ' ' + className : ''}`} style={{ transitionDelay: `${delay}ms`, ...style }}>{children}</Cmp>;
}

function IconGlobe({ size = 18 }) { return (<svg width={size} height={size} viewBox="0 0 24 24" fill="none"><circle cx="12" cy="12" r="9" stroke="currentColor" strokeWidth="1.3" /><ellipse cx="12" cy="12" rx="4" ry="9" stroke="currentColor" strokeWidth="1.3" /><line x1="3" y1="12" x2="21" y2="12" stroke="currentColor" strokeWidth="1.3" /></svg>); }
function IconMobile({ size = 18 }) { return (<svg width={size} height={size} viewBox="0 0 24 24" fill="none"><rect x="7" y="2" width="10" height="20" stroke="currentColor" strokeWidth="1.3" /><line x1="10" y1="18.5" x2="14" y2="18.5" stroke="currentColor" strokeWidth="1.3" /></svg>); }
function IconCloud({ size = 18 }) { return (<svg width={size} height={size} viewBox="0 0 24 24" fill="none"><path d="M7 17h10a4 4 0 0 0 0-8 5.5 5.5 0 0 0-10.6-1.8A4.2 4.2 0 0 0 7 17z" stroke="currentColor" strokeWidth="1.3" strokeLinejoin="round" /></svg>); }
function IconShieldCheck({ size = 18 }) { return (<svg width={size} height={size} viewBox="0 0 24 24" fill="none"><path d="M12 2 4 5v6c0 5 3.5 8.5 8 11 4.5-2.5 8-6 8-11V5l-8-3z" stroke="currentColor" strokeWidth="1.3" strokeLinejoin="round" /><path d="M8.5 12.2 11 14.8 15.8 9.5" stroke="currentColor" strokeWidth="1.4" strokeLinecap="square" fill="none" /></svg>); }
function IconClipboard({ size = 18 }) { return (<svg width={size} height={size} viewBox="0 0 24 24" fill="none"><rect x="5" y="4" width="14" height="17" stroke="currentColor" strokeWidth="1.3" /><rect x="9" y="2" width="6" height="4" stroke="currentColor" strokeWidth="1.3" /><line x1="8" y1="11" x2="16" y2="11" stroke="currentColor" strokeWidth="1.1" /><line x1="8" y1="15" x2="16" y2="15" stroke="currentColor" strokeWidth="1.1" /></svg>); }
function IconPlug({ size = 18 }) { return (<svg width={size} height={size} viewBox="0 0 24 24" fill="none"><path d="M9 3v5M15 3v5M6 8h12v4a6 6 0 0 1-12 0V8z" stroke="currentColor" strokeWidth="1.3" strokeLinejoin="round" /><line x1="12" y1="18" x2="12" y2="22" stroke="currentColor" strokeWidth="1.3" /></svg>); }
function IconCheck({ size = 12, color = 'currentColor' }) { return (<svg width={size} height={size} viewBox="0 0 16 16" fill="none"><path d="M3 8.5 6.2 12 13 4" stroke={color} strokeWidth="1.6" strokeLinecap="square" fill="none" /></svg>); }
function IconCrosshair({ size = 18 }) { return (<svg width={size} height={size} viewBox="0 0 24 24" fill="none"><circle cx="12" cy="12" r="7" stroke="currentColor" strokeWidth="1.3" /><circle cx="12" cy="12" r="1.6" fill="currentColor" /><line x1="12" y1="1" x2="12" y2="5" stroke="currentColor" strokeWidth="1.3" /><line x1="12" y1="19" x2="12" y2="23" stroke="currentColor" strokeWidth="1.3" /><line x1="1" y1="12" x2="5" y2="12" stroke="currentColor" strokeWidth="1.3" /><line x1="19" y1="12" x2="23" y2="12" stroke="currentColor" strokeWidth="1.3" /></svg>); }
function IconSliders({ size = 18 }) { return (<svg width={size} height={size} viewBox="0 0 24 24" fill="none"><line x1="4" y1="6" x2="20" y2="6" stroke="currentColor" strokeWidth="1.3" /><line x1="4" y1="12" x2="20" y2="12" stroke="currentColor" strokeWidth="1.3" /><line x1="4" y1="18" x2="20" y2="18" stroke="currentColor" strokeWidth="1.3" /><rect x="7" y="4" width="4" height="4" stroke="currentColor" strokeWidth="1.3" /><rect x="14" y="10" width="4" height="4" stroke="currentColor" strokeWidth="1.3" /><rect x="5" y="16" width="4" height="4" stroke="currentColor" strokeWidth="1.3" /></svg>); }
function IconPlay({ size = 18 }) { return (<svg width={size} height={size} viewBox="0 0 24 24" fill="none"><circle cx="12" cy="12" r="9" stroke="currentColor" strokeWidth="1.3" /><path d="M10 8.5 16 12 10 15.5z" fill="currentColor" /></svg>); }
function IconFileCheck({ size = 18 }) { return (<svg width={size} height={size} viewBox="0 0 24 24" fill="none"><path d="M6 2h9l4 4v16H6z" stroke="currentColor" strokeWidth="1.3" strokeLinejoin="round" /><path d="M8.5 13 11 15.5 16 10" stroke="currentColor" strokeWidth="1.4" fill="none" strokeLinecap="square" /></svg>); }
function IconGithub({ size = 16 }) { return (<svg width={size} height={size} viewBox="0 0 24 24" fill="none"><path d="M12 2C6.5 2 2 6.6 2 12.3c0 4.5 2.9 8.3 6.9 9.6.5.1.7-.2.7-.5v-1.9c-2.8.6-3.4-1.4-3.4-1.4-.5-1.2-1.1-1.5-1.1-1.5-.9-.6.1-.6.1-.6 1 .1 1.5 1 1.5 1 .9 1.6 2.3 1.1 2.9.9.1-.7.4-1.1.6-1.4-2.3-.3-4.6-1.1-4.6-5 0-1.1.4-2 1-2.7-.1-.3-.4-1.3.1-2.7 0 0 .8-.3 2.8 1a9.6 9.6 0 0 1 5 0c1.9-1.3 2.8-1 2.8-1 .5 1.4.2 2.4.1 2.7.6.7 1 1.6 1 2.7 0 3.9-2.3 4.7-4.6 5 .4.3.7.9.7 1.9v2.9c0 .3.2.6.7.5A9.9 9.9 0 0 0 22 12.3C22 6.6 17.5 2 12 2z" fill="currentColor" /></svg>); }
function IconX({ size = 16 }) { return (<svg width={size} height={size} viewBox="0 0 24 24" fill="none"><path d="M4 4l16 16M20 4 4 20" stroke="currentColor" strokeWidth="1.6" /></svg>); }
function IconLinkedIn({ size = 16 }) { return (<svg width={size} height={size} viewBox="0 0 24 24" fill="none"><rect x="2" y="2" width="20" height="20" stroke="currentColor" strokeWidth="1.3" /><circle cx="7" cy="6.5" r="1.4" fill="currentColor" /><path d="M11 17v-4.5c0-1.6 1-2.5 2.3-2.5S16 11 16 12.7V17" stroke="currentColor" strokeWidth="1.6" fill="none" /><line x1="11" y1="10" x2="11" y2="17" stroke="currentColor" strokeWidth="1.6" /><line x1="7" y1="10" x2="7" y2="17" stroke="currentColor" strokeWidth="1.6" /></svg>); }

Object.assign(window, {
  LogoMark, DecryptedText, TypeLines, Terminal, Ticker, SevDot, Counter, Glitch, Reveal,
  IconGlobe, IconMobile, IconCloud, IconShieldCheck, IconClipboard, IconPlug, IconCheck,
  IconCrosshair, IconSliders, IconPlay, IconFileCheck, IconGithub, IconX, IconLinkedIn,
});
