// Cinematic primitives — custom cursor, petal drift, side nav, takeover modal.

const { useState: useStateC, useEffect: useEffectC, useRef: useRefC } = React;

/* -------------------- CUSTOM CURSOR (heart) -------------------- */
function CustomCursor({ enabled }) {
  const dotRef = useRefC(null);
  const trailRef = useRefC(null);
  const [hover, setHover] = useStateC(false);

  useEffectC(() => {
    if (!enabled) return;
    let raf;
    let x = window.innerWidth / 2, y = window.innerHeight / 2;
    let tx = x, ty = y;
    function move(e) { x = e.clientX; y = e.clientY; }
    function tick() {
      tx += (x - tx) * 0.2;
      ty += (y - ty) * 0.2;
      if (dotRef.current) {
        dotRef.current.style.left = x + 'px';
        dotRef.current.style.top  = y + 'px';
      }
      if (trailRef.current) {
        trailRef.current.style.left = tx + 'px';
        trailRef.current.style.top  = ty + 'px';
      }
      raf = requestAnimationFrame(tick);
    }
    function over(e) {
      const t = e.target;
      if (!t || !t.closest) return;
      const interactive = t.closest('a, button, [data-cursor="hover"], .er-card, .er-event, .er-series__row, .er-quiz__opts button');
      setHover(!!interactive);
    }
    window.addEventListener('mousemove', move);
    window.addEventListener('mouseover', over);
    raf = requestAnimationFrame(tick);
    return () => {
      window.removeEventListener('mousemove', move);
      window.removeEventListener('mouseover', over);
      cancelAnimationFrame(raf);
    };
  }, [enabled]);

  if (!enabled) return null;
  return (
    <>
      <div ref={dotRef}   className={`er-cursor ${hover ? 'er-cursor--hover' : ''}`} />
      <div ref={trailRef} className="er-cursor__trail" />
    </>
  );
}

/* -------------------- PETAL DRIFT -------------------- */
function Petals({ count = 14 }) {
  const petals = React.useMemo(() => Array.from({ length: count }).map((_, i) => {
    const left = Math.random() * 100;
    const drift = (Math.random() * 200 - 100).toFixed(0) + 'px';
    const dur = (16 + Math.random() * 14).toFixed(1) + 's';
    const delay = -(Math.random() * 24).toFixed(1) + 's';
    const scale = (0.6 + Math.random() * 0.8).toFixed(2);
    const hue = Math.random() > 0.5 ? 'var(--er-rose)' : 'var(--er-rose-soft)';
    return { left, drift, dur, delay, scale, hue, key: i };
  }), [count]);

  return (
    <div className="er-petals" aria-hidden="true">
      {petals.map(p => (
        <span
          key={p.key}
          className="er-petal"
          style={{
            left: `${p.left}%`,
            transform: `scale(${p.scale})`,
            background: p.hue,
            '--drift': p.drift,
            '--dur': p.dur,
            '--delay': p.delay }}
        />
      ))}
    </div>
  );
}

/* -------------------- SIDE NAV -------------------- */
const SIDENAV_ITEMS = [
  { id: 'hero',       label: 'i.   the door' },
  { id: 'pitch',      label: 'ii.  the itch' },
  { id: 'books',      label: 'iii. the books' },
  { id: 'series',     label: 'iv.  the universe' },
  { id: 'about',      label: 'v.   the authors' },
  { id: 'quiz',       label: 'vi.  read me first' },
  { id: 'newsletter', label: 'vii. the list' },
  { id: 'events',     label: 'viii.the diary' },
  { id: 'press',      label: 'ix.  the rest' },
];

function SideNav() {
  const [active, setActive] = useStateC('hero');
  useEffectC(() => {
    const observers = [];
    SIDENAV_ITEMS.forEach((item) => {
      const el = document.getElementById(item.id);
      if (!el) return;
      const io = new IntersectionObserver((entries) => {
        entries.forEach((e) => { if (e.isIntersecting) setActive(item.id); });
      }, { rootMargin: '-40% 0px -55% 0px' });
      io.observe(el);
      observers.push(io);
    });
    return () => observers.forEach((o) => o.disconnect());
  }, []);
  return (
    <nav className="er-sidenav" aria-label="Chapters">
      {SIDENAV_ITEMS.map((item) => (
        <a
          key={item.id}
          className={`er-sidenav__item ${active === item.id ? 'er-sidenav__item--active' : ''}`}
          onClick={() => scrollToId(item.id)}
          data-cursor="hover"
        >
          <span>{item.label}</span>
        </a>
      ))}
    </nav>
  );
}

/* -------------------- SCROLL-AWARE HEADER WRAPPER -------------------- */
function useScrolled(threshold = 40) {
  const [scrolled, setScrolled] = useStateC(false);
  useEffectC(() => {
    function onScroll() { setScrolled(window.scrollY > threshold); }
    onScroll();
    window.addEventListener('scroll', onScroll, { passive: true });
    return () => window.removeEventListener('scroll', onScroll);
  }, [threshold]);
  return scrolled;
}

/* -------------------- BOOK TAKEOVER MODAL -------------------- */
function BookTakeover({ book, onClose }) {
  useEffectC(() => {
    function key(e) { if (e.key === 'Escape') onClose(); }
    window.addEventListener('keydown', key);
    document.body.style.overflow = 'hidden';
    return () => {
      window.removeEventListener('keydown', key);
      document.body.style.overflow = '';
    };
  }, [onClose]);

  if (!book) return null;

  return (
    <div className="er-takeover" onClick={onClose} role="dialog" aria-modal="true">
      <div className="er-takeover__inner" onClick={(e) => e.stopPropagation()}>
        <button className="er-takeover__close" onClick={onClose}>Close ✕</button>

        <div className="er-takeover__cover">
          {book.cover ? (
            <img src={book.cover} alt={`${book.title} cover`} />
          ) : (
            <div className="er-book__placeholder" style={{ width: 320, height: 480 }}>
              <strong>{book.title}</strong>
              <span>cover · reveal · TBC</span>
            </div>
          )}
        </div>

        <div className="er-takeover__body">
          <div className="label label--accent">{book.series} · {book.seriesNum}</div>
          <h2>{book.title}</h2>
          <p className="er-takeover__tagline">{book.blurb}</p>

          <div className="er-takeover__cta-top">
            {book.readUrl ? (
              <a className="er-cta er-cta--filled" href={book.readUrl} target="_blank" rel="noopener">
                Read now on Amazon
              </a>
            ) : book.preorderUrl ? (
              <a className="er-cta er-cta--filled" href={book.preorderUrl} target="_blank" rel="noopener">
                Pre-order now on Amazon
              </a>
            ) : (
              <button className="er-cta er-cta--filled" onClick={() => {
                onClose();
                setTimeout(() => scrollToId('newsletter'), 100);
              }}>
                Pre-order now
              </button>
            )}
          </div>

          {book.tropes && (
            <div className="er-takeover__tropes">
              {book.tropes.map((t, i) => <span key={i}>{t}</span>)}
            </div>
          )}

          <div className="er-takeover__meta">
            <div>
              <span className="label">Release</span>
              <strong>{book.date}</strong>
            </div>
            <div>
              <span className="label">Status</span>
              <strong>{book.status}</strong>
            </div>
            <div>
              <span className="label">Heat</span>
              <strong>{book.heat || 'volcanic'}</strong>
            </div>
          </div>

          {book.synopsis && (
            <div className="er-takeover__synopsis">
              {book.synopsis.split('\n').map((para, i) => (
                <p key={i}>{para}</p>
              ))}
            </div>
          )}

          {book.expect && (
            <div className="er-takeover__expect">
              <div className="label label--accent" style={{ marginBottom: 8 }}>What to expect</div>
              <p>{book.expect}</p>
            </div>
          )}

          <div className="er-takeover__actions">
            {book.readUrl ? (
              <a className="er-cta er-cta--filled" href={book.readUrl} target="_blank" rel="noopener">
                Read now on Amazon
              </a>
            ) : book.preorderUrl ? (
              <a className="er-cta er-cta--filled" href={book.preorderUrl} target="_blank" rel="noopener">
                Pre-order now on Amazon
              </a>
            ) : (
              <button className="er-cta er-cta--filled" onClick={() => {
                onClose();
                setTimeout(() => scrollToId('newsletter'), 100);
              }}>
                Tell me when it drops
              </button>
            )}
            <a className="er-cta er-cta--ghost" href="warnings.html">
              Content warnings
            </a>
          </div>

          {!book.preorderUrl && !book.readUrl && (
            <div className="label" style={{ marginTop: 12 }}>
              Preorder links go live closer to release. RSVP to the Club to be first.
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

/* ============================================================
   COUNTDOWN — to launch day
   ============================================================ */

function Countdown({ target, label }) {
  const compute = () => {
    const t = (target?.getTime?.() ?? new Date(target).getTime()) - Date.now();
    if (t <= 0) return { days: 0, hours: 0, minutes: 0, seconds: 0, done: true };
    return {
      days: Math.floor(t / 86400000),
      hours: Math.floor((t % 86400000) / 3600000),
      minutes: Math.floor((t % 3600000) / 60000),
      seconds: Math.floor((t % 60000) / 1000),
      done: false };
  };
  const [t, setT] = useStateC(compute);
  useEffectC(() => {
    const id = setInterval(() => setT(compute()), 1000);
    return () => clearInterval(id);
  }, [target]);

  const pad = (n) => String(n).padStart(2, '0');

  return (
    <div className="er-countdown" aria-live="polite">
      <div className="er-countdown__label">{label}</div>
      <div className="er-countdown__tiles">
        <div className="er-countdown__tile">
          <span className="er-countdown__num">{t.days}</span>
          <span className="er-countdown__unit">days</span>
        </div>
        <div className="er-countdown__sep">·</div>
        <div className="er-countdown__tile">
          <span className="er-countdown__num">{pad(t.hours)}</span>
          <span className="er-countdown__unit">hours</span>
        </div>
        <div className="er-countdown__sep">·</div>
        <div className="er-countdown__tile">
          <span className="er-countdown__num">{pad(t.minutes)}</span>
          <span className="er-countdown__unit">minutes</span>
        </div>
        <div className="er-countdown__sep">·</div>
        <div className="er-countdown__tile">
          <span className="er-countdown__num">{pad(t.seconds)}</span>
          <span className="er-countdown__unit">seconds</span>
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { CustomCursor, Petals, SideNav, useScrolled, BookTakeover, SIDENAV_ITEMS, SnakeOrnament, Countdown });

/* ============================================================
   SNAKE ORNAMENT — photographic gold serpent (placeholder).
   Muted, sits behind hero text so words read on top.
   ============================================================ */

function SnakeOrnament() {
  return (
    <img
      className="er-snake-photo"
      src="assets/brand/snake-photo.png"
      alt=""
      aria-hidden="true"
    />
  );
}

function SnakeTrail({ enabled = true } = {}) {
  const wrapRef = useRefC(null);
  const bgPathRef = useRefC(null);
  const fgPathRef = useRefC(null);
  const headRef = useRefC(null);

  useEffectC(() => {
    if (!enabled) return;
    let pathLen = 1;
    let raf = 0;

    function buildPath(docH) {
      // Intro: weaves through the brand wordmark area, then settles into a column
      let d = 'M 230 -18 ';
      d += 'C 240 20, 220 50, 180 50 ';
      d += 'C 140 50, 130 14, 100 32 ';
      d += 'C 70 50, 70 80, 60 120 ';
      d += 'C 50 150, 36 160, 28 200 ';

      const startY = 200;
      const remaining = Math.max(400, docH - startY);
      const segH = 280;
      const segments = Math.max(8, Math.ceil(remaining / segH));
      const actualSegH = remaining / segments;
      const amp = 22;
      for (let i = 0; i < segments; i++) {
        const dir = i % 2 === 0 ? -1 : 1;
        const y0 = startY + i * actualSegH;
        const y1 = startY + (i + 1) * actualSegH;
        d += `C 28 ${y0 + actualSegH * 0.3}, ${28 + dir * amp} ${y0 + actualSegH * 0.5}, 28 ${y1} `;
      }
      return d;
    }

    function rebuild() {
      const w = wrapRef.current;
      if (!w) return;
      const docH = Math.max(
        document.body.scrollHeight,
        document.documentElement.scrollHeight,
        window.innerHeight
      );
      w.style.height = docH + 'px';
      const svg = w.querySelector('svg');
      svg.setAttribute('viewBox', `0 -20 280 ${docH + 20}`);
      svg.setAttribute('height', String(docH + 20));

      const d = buildPath(docH);
      bgPathRef.current.setAttribute('d', d);
      fgPathRef.current.setAttribute('d', d);
      const allBody = w.querySelectorAll('[data-snake-body]');
      allBody.forEach((p) => p.setAttribute('d', d));
      pathLen = fgPathRef.current.getTotalLength();
      // Initialize dash arrays on every body layer
      const allLayers = [fgPathRef.current, ...allBody];
      allLayers.forEach((el) => {
        el.style.strokeDasharray = String(pathLen);
      });
      tick();
    }

    function tick() {
      if (!fgPathRef.current || !headRef.current) return;
      const fg = fgPathRef.current;
      const docH = Math.max(
        document.body.scrollHeight,
        document.documentElement.scrollHeight,
        window.innerHeight
      );
      const sh = Math.max(1, docH - window.innerHeight);
      const p = Math.max(0, Math.min(1, window.scrollY / sh));
      const introLen = Math.min(280, pathLen);
      const drawn = Math.max(introLen, pathLen * p);
      const dashOffset = String(pathLen - drawn);
      fg.style.strokeDashoffset = dashOffset;
      const layers = wrapRef.current?.querySelectorAll('[data-snake-body]') || [];
      layers.forEach((el) => {
        el.style.strokeDashoffset = dashOffset;
      });
      try {
        const pt = fg.getPointAtLength(drawn);
        const next = fg.getPointAtLength(Math.min(drawn + 4, pathLen));
        const dx = next.x - pt.x;
        const dy = next.y - pt.y;
        const angle = (Math.atan2(dy, dx) * 180) / Math.PI - 90;
        headRef.current.setAttribute('transform', `translate(${pt.x}, ${pt.y}) rotate(${angle})`);
      } catch (_) {}
    }

    function onScroll() {
      cancelAnimationFrame(raf);
      raf = requestAnimationFrame(tick);
    }

    rebuild();
    window.addEventListener('resize', rebuild);
    window.addEventListener('scroll', onScroll, { passive: true });
    // One settle-pass once images/fonts settle; no ongoing observer to avoid loops
    const settleTimer = setTimeout(rebuild, 1500);

    return () => {
      window.removeEventListener('resize', rebuild);
      window.removeEventListener('scroll', onScroll);
      cancelAnimationFrame(raf);
      clearTimeout(settleTimer);
    };
  }, [enabled]);

  if (!enabled) return null;

  return (
    <div ref={wrapRef} className="er-snake" aria-hidden="true">
      <svg viewBox="0 -20 280 1020" width="280" height="1020" preserveAspectRatio="none">
        <defs>
          {/* Gold body gradient — bright edge to deep shadow back to bright */}
          <linearGradient id="er-snake-body" x1="0" y1="0" x2="1" y2="0">
            <stop offset="0%"   stopColor="#7a5018" />
            <stop offset="30%"  stopColor="#c9a05c" />
            <stop offset="55%"  stopColor="#f0d28a" />
            <stop offset="75%"  stopColor="#c9a05c" />
            <stop offset="100%" stopColor="#6a4514" />
          </linearGradient>
          <linearGradient id="er-snake-shine" x1="0" y1="0" x2="1" y2="0">
            <stop offset="0%"   stopColor="rgba(245,222,164,0)" />
            <stop offset="50%"  stopColor="rgba(255,235,184,0.85)" />
            <stop offset="100%" stopColor="rgba(245,222,164,0)" />
          </linearGradient>
        </defs>

        {/* faint reference */}
        <path ref={bgPathRef} d="" stroke="var(--er-rule)" strokeWidth="1" fill="none" strokeDasharray="1 6" opacity="0.4" />

        {/* dark underbody (depth shadow) */}
        <path
          data-snake-body
          d=""
          stroke="#2a1a08"
          strokeWidth="10"
          fill="none"
          strokeLinecap="round"
          opacity="0.6"
        />

        {/* main gold body */}
        <path
          ref={fgPathRef}
          d=""
          stroke="url(#er-snake-body)"
          strokeWidth="8"
          fill="none"
          strokeLinecap="round"
          style={{ transition: 'stroke-dashoffset 0.12s linear' }}
        />

        {/* highlight sheen down the center */}
        <path
          data-snake-body
          d=""
          stroke="url(#er-snake-shine)"
          strokeWidth="2.5"
          fill="none"
          strokeLinecap="round"
          opacity="0.9"
        />

        {/* serpent head — sculpted shape */}
        <g ref={headRef} transform="translate(230, -18)">
          {/* glow halo */}
          <circle r="16" fill="none" stroke="var(--er-gold)" strokeWidth="1" opacity="0.5">
            <animate attributeName="r" values="12;20;12" dur="2.6s" repeatCount="indefinite" />
            <animate attributeName="opacity" values="0.6;0;0.6" dur="2.6s" repeatCount="indefinite" />
          </circle>
          {/* head shadow */}
          <ellipse rx="8" ry="11" fill="#2a1a08" opacity="0.7" />
          {/* head body — teardrop */}
          <path d="M 0 -10 C 7 -10 7 4 4 9 C 2 11 -2 11 -4 9 C -7 4 -7 -10 0 -10 Z"
                fill="url(#er-snake-body)" stroke="#2a1a08" strokeWidth="0.7" />
          {/* scales on head */}
          <path d="M 0 -8 Q 3 -6 0 -4 Q -3 -6 0 -8 M 0 -3 Q 3 -1 0 1 Q -3 -1 0 -3 M 0 2 Q 3 4 0 6 Q -3 4 0 2"
                fill="none" stroke="rgba(40,20,6,0.6)" strokeWidth="0.6" />
          {/* eyes */}
          <circle cx="-2.6" cy="-4" r="1.3" fill="#2a1a08" />
          <circle cx="2.6"  cy="-4" r="1.3" fill="#2a1a08" />
          <circle cx="-2.6" cy="-4.3" r="0.5" fill="#f0d28a" />
          <circle cx="2.6"  cy="-4.3" r="0.5" fill="#f0d28a" />
          {/* forked tongue */}
          <path d="M 0 10 L 0 14 M 0 14 L -1.8 17 M 0 14 L 1.8 17"
                stroke="#a01828" strokeWidth="1" strokeLinecap="round" fill="none" />
        </g>
      </svg>
    </div>
  );
}
