// MEGALIS — Intro openings.
//   boot  — title card; the MEGALIS logo settles centered into the Show Reel
//           video frame. handoff: 'static' (fade) | 'settle' (fly-in + settle).
//   combo — boot title card plays on the Show Reel window, then the REST of the
//           page cascades in around it (slow). cascadeMotion: 'slide'|'fade'|'wipe'.
// Plays on load, re-plays on change (App keys the overlay). Skippable (click).
// Respects prefers-reduced-motion (skips straight to the page).

// Cascade targets for the combo = everything EXCEPT the hero reel (which the boot reveals).
const COMBO_T = ['.nav', '.ticker', '.hero-bottom', '#about', '.clients', '#reel', '#contact', '#careers', 'footer'];
const COMBO_DELAYS = [0, 0.36, 0.72, 1.08, 1.44, 1.8, 2.16, 2.52, 2.88]; // 2.5× slower stagger
const COMBO_DUR = 1.7;   // seconds, per element (2.5× slower)
const cmSel = (attr) => COMBO_T.map((s) => `body[data-combo="${attr}"] ${s}`).join(',\n  ');
const cmHide = COMBO_T.map((s) => `body[data-combo="hide"] ${s}`).join(',\n  ');
const cmMotion = ['slide', 'fade', 'wipe'].map(cmSel).join(',\n  ');

const introStyles = `
  .intro {
    position: fixed; inset: 0; z-index: 100000;
    background: #000; overflow: hidden; cursor: pointer; color: #fff;
  }
  .intro .skip {
    position: absolute; right: clamp(16px, 3vw, 40px); bottom: clamp(16px, 3vw, 40px);
    z-index: 9; font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.2em;
    text-transform: uppercase; color: rgba(255,255,255,0.45);
    animation: introFadeIn 0.6s 0.5s var(--easing) both;
  }
  .intro .skip:hover { color: #fff; }
  @keyframes introFadeIn { from { opacity: 0; } to { opacity: 1; } }
  .intro[data-state="exit"] { animation: introExit 0.6s var(--easing) forwards; }
  @keyframes introExit { to { opacity: 0; visibility: hidden; } }

  /* ── BOOT — title card ───────────────────────────── */
  .intro-boot .boot-mark {
    position: fixed; display: block; z-index: 6;
    filter: drop-shadow(0 0 40px rgba(229,66,59,0.25));
  }
  .intro-boot[data-handoff="static"] .boot-mark {
    animation: bootFadeIn 0.9s 0.2s var(--easing) both;
  }
  @keyframes bootFadeIn { from { opacity: 0; } to { opacity: 1; } }
  .intro-boot[data-handoff="settle"] .boot-mark {
    animation: bootSettle 1.6s 0.1s cubic-bezier(.16,1,.3,1) both;
  }
  @keyframes bootSettle {
    from { transform: var(--from); opacity: 0; }
    22%  { opacity: 1; }
    to   { transform: none; opacity: 1; }
  }
  .intro-boot .boot-scan {
    position: absolute; left: 0; right: 0; height: 2px; z-index: 3;
    background: linear-gradient(90deg, transparent, #E5423B, transparent);
    animation: bootScan 1.5s 0.2s var(--easing) forwards;
  }
  @keyframes bootScan { 0%{top:8%;opacity:0} 20%{opacity:0.9} 100%{top:92%;opacity:0} }
  .intro-boot .boot-chrome {
    position: fixed; z-index: 7; transform: translateX(-50%);
    display: flex; flex-direction: column; gap: 14px;
    animation: introFadeIn 0.5s 0.2s var(--easing) both;
  }
  .intro-boot .boot-bar {
    width: 100%; height: 1px; background: rgba(255,255,255,0.18);
    position: relative; overflow: hidden;
  }
  .intro-boot .boot-bar::after {
    content: ""; position: absolute; inset: 0; background: #E5423B;
    transform-origin: left; transform: scaleX(0);
    animation: bootFill 1.6s 0.3s var(--easing) forwards;
  }
  @keyframes bootFill { to { transform: scaleX(1); } }
  .intro-boot .boot-meta {
    display: flex; justify-content: space-between; align-items: baseline;
    font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.2em;
    text-transform: uppercase; color: rgba(255,255,255,0.6);
  }
  .intro-boot .boot-meta .ctr { color: #fff; font-variant-numeric: tabular-nums; }
  .intro-boot .dots { display: inline-flex; }
  .intro-boot .dots i { font-style: normal; opacity: 0.15; animation: dotPulse 1.4s infinite; }
  .intro-boot .dots i:nth-child(2) { animation-delay: 0.18s; }
  .intro-boot .dots i:nth-child(3) { animation-delay: 0.36s; }
  @keyframes dotPulse { 0%,70%,100% { opacity: 0.15; } 35% { opacity: 1; } }

  /* ── COMBO — cascade the rest of the page around the reel ── */
  ${cmHide} { opacity: 0; }
  ${cmMotion} {
    animation-duration: ${COMBO_DUR}s;
    animation-timing-function: cubic-bezier(.22,1,.36,1);
    animation-fill-mode: both;
    will-change: transform, opacity, clip-path;
  }
  ${COMBO_T.map((s, i) => `body[data-combo] ${s} { animation-delay: ${COMBO_DELAYS[i]}s; }`).join('\n  ')}
  ${cmSel('slide')} { animation-name: csSlide; }
  ${cmSel('fade')}  { animation-name: csFade;  }
  ${cmSel('wipe')}  { animation-name: csWipe;  }
  @keyframes csSlide { from { opacity: 0; transform: translateY(-48px); } to { opacity: 1; transform: none; } }
  @keyframes csFade  { from { opacity: 0; } to { opacity: 1; } }
  @keyframes csWipe  { from { opacity: 0; clip-path: inset(0 0 100% 0); } to { opacity: 1; clip-path: inset(0 0 0 0); } }

  @media (prefers-reduced-motion: reduce) {
    .intro { display: none; }
    ${COMBO_T.map((s) => `body[data-combo] ${s}`).join(',\n    ')} { animation: none !important; opacity: 1 !important; transform: none !important; clip-path: none !important; }
  }
`;

const BOOT_MS = 2900;     // standalone boot
const COMBO_BLACK_MS = 1700; // combo: black title-card phase before the reveal
const COMBO_TOTAL_MS = COMBO_BLACK_MS + Math.round((COMBO_DELAYS[COMBO_DELAYS.length - 1] + COMBO_DUR) * 1000);
const EXIT_MS = 600;

function Intro({ variant, handoff = 'static', cascadeMotion = 'slide', onDone }) {
  const active = variant && variant !== 'none';
  const [state, setState] = React.useState('play');
  const [count, setCount] = React.useState(0);
  const [rect, setRect] = React.useState(null);
  const [reveal, setReveal] = React.useState(false); // combo: rest starts cascading
  const reduce = React.useRef(
    typeof matchMedia !== 'undefined' && matchMedia('(prefers-reduced-motion: reduce)').matches
  );

  // lifecycle
  React.useEffect(() => {
    if (!active || reduce.current) { onDone && onDone(); return undefined; }
    setState('play'); setCount(0); setReveal(false);
    if (variant === 'combo') {
      const tReveal = setTimeout(() => { setState('exit'); setReveal(true); }, COMBO_BLACK_MS);
      const tDone = setTimeout(() => { onDone && onDone(); }, COMBO_TOTAL_MS);
      return () => { clearTimeout(tReveal); clearTimeout(tDone); };
    }
    const tExit = setTimeout(() => setState('exit'), BOOT_MS - EXIT_MS);
    const tDone = setTimeout(() => { onDone && onDone(); }, BOOT_MS);
    return () => { clearTimeout(tExit); clearTimeout(tDone); };
  }, [variant, active, onDone]);

  // measure the Show Reel video frame so the boot logo settles centered into it
  React.useEffect(() => {
    if (!active || reduce.current || !(variant === 'boot' || variant === 'combo')) return undefined;
    const measure = () => {
      const el = document.querySelector('.hero-reel');
      if (!el) return;
      const r = el.getBoundingClientRect();
      if (r.width <= 0) return;
      // Logo sized to match the wordmark inside the Show Reel video, centered.
      const w = Math.min(r.width * 0.54, 820);
      const h = w * (241 / 1568);
      setRect({
        x: r.left + (r.width - w) / 2,
        y: r.top + (r.height - h) / 2,
        w,
        h,
      });
    };
    measure();
    const t1 = setTimeout(measure, 80);
    const t2 = setTimeout(measure, 300);
    window.addEventListener('resize', measure);
    return () => { clearTimeout(t1); clearTimeout(t2); window.removeEventListener('resize', measure); };
  }, [variant, active]);

  // percentage counter
  React.useEffect(() => {
    if (!active || !(variant === 'boot' || variant === 'combo') || state !== 'play') return undefined;
    let raf; const start = performance.now();
    const span = variant === 'combo' ? COMBO_BLACK_MS - 200 : 1900;
    const tick = (now) => {
      const p = Math.min(1, (now - start) / span);
      setCount(Math.round(p * 100));
      if (p < 1) raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [variant, active, state]);

  // combo: drive the page reveal via a body attribute (pre-hide → cascade)
  React.useEffect(() => {
    if (!active || reduce.current || variant !== 'combo') return undefined;
    document.body.setAttribute('data-combo', reveal ? (cascadeMotion || 'slide') : 'hide');
    return () => { document.body.removeAttribute('data-combo'); };
  }, [variant, active, reveal, cascadeMotion]);

  const skip = React.useCallback(() => {
    setState('exit');
    setTimeout(() => { onDone && onDone(); }, EXIT_MS * 0.5);
  }, [onDone]);

  if (!active || reduce.current) return null;

  const pct = count >= 100 ? '100%' : String(count).padStart(2, '0') + '%';
  let markStyle = null, chromeStyle = null;
  if (rect) {
    const vw = window.innerWidth, vh = window.innerHeight;
    const cx = rect.x + rect.w / 2, cy = rect.y + rect.h / 2;
    const settleFrom = `translate(${(vw / 2 - cx).toFixed(1)}px, ${(vh / 2 - cy).toFixed(1)}px) scale(1.22)`;
    markStyle = { left: rect.x, top: rect.y, width: rect.w, height: rect.h, '--from': settleFrom };
    chromeStyle = { left: cx, top: rect.y + rect.h + 30, width: Math.max(rect.w, 240) };
  }

  return (
    <>
      <style>{introStyles}</style>
      <div className="intro intro-boot" data-handoff={handoff} data-state={state}
           data-variant={variant} onClick={skip} role="button" aria-label="Skip intro">
        <div className="boot-scan" />
        {rect && (
          <img className="boot-mark" src="assets/megalis-logo.png" alt="MEGALIS" style={markStyle} />
        )}
        {rect && (
          <div className="boot-chrome" style={chromeStyle}>
            <div className="boot-bar" />
            <div className="boot-meta">
              <span>Rendering<span className="dots"><i>.</i><i>.</i><i>.</i></span></span>
              <span className="ctr">{pct}</span>
            </div>
          </div>
        )}
        <span className="skip">Skip ✕</span>
      </div>
    </>
  );
}

Object.assign(window, { Intro });
