// mavin launch — Film composition. One <Film> used by both the 16:9 master
// and the 9:16 cut (pass `vertical`). Drives the phone screen-swaps, camera
// moves, kinetic captions, the parchment cold-open + end card, all off the
// Stage clock via useTime() so it scrubs and exports frame-accurate.

const { useTime: _useTime, clamp: _clamp, Easing: _E } = window;
const eIO = _E.easeInOutCubic, eO = _E.easeOutCubic;

// timing helper → {active, p, opacity} for a window with fades
function seg(t, start, end, fin = 0.22, fout = 0.22) {
  const active = t >= start - fin && t <= end + fout;
  const p = _clamp((t - start) / (end - start), 0, 1);
  let opacity = 1;
  if (t < start) opacity = _clamp((t - (start - fin)) / fin, 0, 1);
  else if (t > end) opacity = 1 - _clamp((t - end) / fout, 0, 1);
  return { active, p, opacity };
}

// ── beat table ────────────────────────────────────────────────────
const BEATS = {
  open:         [0.0, 2.8],
  camera:       [3.1, 6.5],
  agents:       [6.5, 10.2],
  score:        [10.2, 12.8],
  valuation:    [12.8, 15.2],
  vault:        [15.2, 18.0],
  intelligence: [18.0, 20.2],
  end:          [20.0, 23.0],
};

// ════════════════════════════════════════════════════════════════
// PHONE FRAME
// ════════════════════════════════════════════════════════════════
function PhoneFrame({ children }) {
  // logical screen 360×780; bezel 13
  return (
    <div style={{ position: "relative", width: 386, height: 806, borderRadius: 62,
      background: "linear-gradient(155deg,#2a2a2c,#0a0a0a 55%,#1a1a1c)",
      padding: 13, boxShadow: "0 44px 80px -30px rgba(40,28,18,0.46), 0 14px 34px -14px rgba(40,28,18,0.30), 0 0 0 1px rgba(0,0,0,0.18), inset 0 0 0 1px rgba(255,255,255,0.06)" }}>
      <div style={{ position: "relative", width: 360, height: 780, borderRadius: 50, overflow: "hidden", clipPath: "inset(0 round 50px)", background: "#000" }}>
        {children}
        {/* dynamic island */}
        <div style={{ position: "absolute", top: 13, left: "50%", transform: "translateX(-50%)", width: 108, height: 31, background: "#000", borderRadius: 999, zIndex: 60 }} />
      </div>
    </div>
  );
}

// renders the active app screen(s) with cross-fades
function PhoneScreens() {
  const t = _useTime();
  const layers = [
    ["camera", window.ScreenCamera],
    ["agents", window.ScreenAgents],
    ["score", window.ScreenScore],
    ["valuation", window.ScreenValuation],
    ["vault", window.ScreenVault],
    ["intelligence", window.ScreenIntelligence],
  ];
  return (
    <React.Fragment>
      {layers.map(([key, Comp]) => {
        const [s, e] = BEATS[key];
        const { active, p, opacity } = seg(t, s, e, 0.2, 0.2);
        if (!active) return null;
        return <div key={key} style={{ position: "absolute", inset: 0, opacity }}><Comp p={p} /></div>;
      })}
    </React.Fragment>
  );
}

// ════════════════════════════════════════════════════════════════
// COLD OPEN  +  END CARD  (parchment brand world)
// ════════════════════════════════════════════════════════════════
function ColdOpen({ W, H, vertical }) {
  const t = _useTime();
  const [s, e] = BEATS.open;
  if (t > e + 0.5) return null;
  // parchment irises away 2.3 → 3.05 to reveal the app
  const iris = _clamp((t - 2.3) / 0.75, 0, 1);
  const r = (1 - eIO(iris)) * 160;
  const lineP = _clamp((t - 0.45) / 0.6, 0, 1);
  const subP = _clamp((t - 1.15) / 0.6, 0, 1);
  const ruleP = _clamp((t - 0.95) / 0.9, 0, 1);
  const big = vertical ? 96 : 118;
  return (
    <div className="grain" style={{ position: "absolute", inset: 0, background: "var(--p-parchment)", zIndex: 80,
      clipPath: `circle(${r}% at 50% 44%)`, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center" }}>
      <div style={{ fontFamily: "var(--font-mono)", fontSize: vertical ? 14 : 13, letterSpacing: "0.26em", color: "var(--p-brass)",
        opacity: _clamp(t / 0.5, 0, 1), marginBottom: vertical ? 30 : 26 }}>mavin · EARLY ACCESS</div>
      <div style={{ fontFamily: "var(--font-display)", fontWeight: 600, fontSize: big, lineHeight: 0.98, letterSpacing: "-0.03em",
        color: "var(--p-ink)", textAlign: "center", opacity: lineP, transform: `translateY(${(1 - eO(lineP)) * 18}px)` }}>
        personal intelligence for
      </div>
      <div style={{ width: ruleP * (vertical ? 260 : 320), height: 2, background: "var(--p-brass)", margin: vertical ? "34px 0" : "30px 0" }} />
      <div style={{ fontFamily: "var(--font-display)", fontWeight: 300, fontSize: big * 0.62, lineHeight: 1, letterSpacing: "-0.02em",
        color: "var(--p-walnut)", textAlign: "center", opacity: subP, transform: `translateY(${(1 - eO(subP)) * 14}px)` }}>
        the objects you love.
      </div>
    </div>
  );
}

function EndCard({ W, H, vertical }) {
  const t = _useTime();
  const [s] = BEATS.end;
  if (t < s - 0.3) return null;
  const iris = _clamp((t - s) / 0.55, 0, 1);
  const r = eIO(iris) * 160;
  const markP = _clamp((t - s - 0.45) / 0.6, 0, 1);
  const lineP = _clamp((t - s - 0.8) / 0.6, 0, 1);
  const ctaP = _clamp((t - s - 1.2) / 0.6, 0, 1);
  return (
    <div className="grain" style={{ position: "absolute", inset: 0, background: "var(--p-parchment)", zIndex: 80,
      clipPath: `circle(${r}% at 50% 50%)`, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center" }}>
      <div style={{ opacity: markP, transform: `translateY(${(1 - eO(markP)) * 14}px) scale(${0.9 + markP * 0.1})`, display: "flex", flexDirection: "column", alignItems: "center" }}>
        <img src="../assets/brand/mavin-wordmark--charcoal.png" alt="mavin" style={{ height: vertical ? 60 : 52 }} />
      </div>
      <div style={{ fontFamily: "var(--font-display)", fontWeight: 600, fontSize: vertical ? 64 : 74, letterSpacing: "-0.03em", color: "var(--p-ink)",
        marginTop: vertical ? 44 : 38, opacity: lineP, transform: `translateY(${(1 - eO(lineP)) * 14}px)` }}>
        build the record.
      </div>
      <div style={{ marginTop: vertical ? 40 : 34, display: "flex", flexDirection: "column", alignItems: "center", gap: 16, opacity: ctaP, transform: `translateY(${(1 - eO(ctaP)) * 12}px)` }}>
        <div style={{ background: "var(--p-ink)", color: "var(--p-parchment)", fontFamily: "var(--font-display)", fontWeight: 600,
          fontSize: vertical ? 21 : 19, letterSpacing: "0.02em", padding: vertical ? "17px 38px" : "15px 34px", borderRadius: 3 }}>
          register for early access
        </div>
        <div style={{ fontFamily: "var(--font-mono)", fontSize: 11, letterSpacing: "0.2em", color: "var(--p-brass)" }}>mavin · V1 · WORKING</div>
      </div>
    </div>
  );
}

// ════════════════════════════════════════════════════════════════
// KINETIC CAPTIONS  (per beat)
// ════════════════════════════════════════════════════════════════
const CAPTIONS = [
  ["camera",       "01 · CAPTURE",         "add an object."],
  ["agents",       "02 · INTELLIGENCE",    "specialized agents.\none verdict."],
  ["score",        "03 · THE VAULT SCORE", "build the\nrecord."],
  ["valuation",    "04 · VALUE",           "worth, in\ncontext."],
  ["vault",        "05 · THE VAULT",       "everything\nyou own."],
  ["intelligence", "06 · THE DAILY BRIEF", "personal\nintelligence."],
];
function Captions({ W, H, vertical, phone }) {
  const t = _useTime();
  // caption anchor
  const style = vertical
    ? { left: 0, right: 0, top: phone.cy + phone.h / 2 + 64, textAlign: "center", align: "center" }
    : { left: phone.cx + phone.w / 2 + 56, right: 80, top: H * 0.30, textAlign: "left", align: "left" };
  return (
    <React.Fragment>
      {CAPTIONS.map(([key, eyebrow, line]) => {
        const [s, e] = BEATS[key];
        const { active, opacity, p } = seg(t, s + 0.15, e - 0.05, 0.3, 0.3);
        if (!active) return null;
        const slide = (1 - eO(_clamp(p / 0.12, 0, 1))) * 22;
        return (
          <div key={key} style={{ position: "absolute", left: style.left, right: style.right, top: style.top, textAlign: style.textAlign, opacity }}>
            <div style={{ fontFamily: "var(--font-mono)", fontSize: vertical ? 15 : 14, letterSpacing: "0.22em", color: "var(--p-brass)", marginBottom: vertical ? 16 : 18, transform: `translateX(${style.align === "left" ? slide : 0}px)` }}>{eyebrow}</div>
            <div style={{ fontFamily: "var(--font-display)", fontWeight: 600, fontSize: vertical ? 60 : 76, lineHeight: 0.98, letterSpacing: "-0.03em", color: "var(--p-ink)", whiteSpace: "pre-line", transform: `translateY(${slide}px)` }}>{line}</div>
          </div>
        );
      })}
    </React.Fragment>
  );
}

// ════════════════════════════════════════════════════════════════
// AMBIENT (dark stage chrome + glow)
// ════════════════════════════════════════════════════════════════
function Ambient({ W, H, vertical, phone }) {
  const t = _useTime();
  const on = _clamp((t - 2.7) / 0.6, 0, 1) * (1 - _clamp((t - 19.9) / 0.4, 0, 1));
  // gold glow pulses subtly through the energy beats
  const energy = _clamp((t - 5.0) / 1.0, 0, 1) * (1 - _clamp((t - 11.5) / 1.0, 0, 1));
  return (
    <div style={{ position: "absolute", inset: 0, opacity: on, pointerEvents: "none" }}>
      {/* soft warm halo seating the phone on the parchment canvas */}
      <div style={{ position: "absolute", left: phone.cx, top: phone.cy + phone.h * 0.10, width: phone.w * 2.1, height: phone.w * 2.1,
        transform: "translate(-50%,-50%)", borderRadius: "50%",
        background: `radial-gradient(circle, rgba(58,40,24,${0.06 + energy * 0.04}) 0%, transparent 60%)` }} />
      {/* corner chrome */}
      {!vertical && <React.Fragment>
        <div style={{ position: "absolute", top: 46, left: 56, fontFamily: "var(--font-mono)", fontSize: 12, letterSpacing: "0.2em", color: "rgba(162,125,75,0.9)" }}>RUNDA LAB · mavin</div>
        <div style={{ position: "absolute", top: 46, right: 56, fontFamily: "var(--font-mono)", fontSize: 12, letterSpacing: "0.2em", color: "rgba(21,20,20,0.42)" }}>ARCHIVE Nº 00271</div>
        <div style={{ position: "absolute", bottom: 46, left: 56, fontFamily: "var(--font-mono)", fontSize: 12, letterSpacing: "0.2em", color: "rgba(21,20,20,0.42)" }}>PERSONAL INTELLIGENCE</div>
        <div style={{ position: "absolute", bottom: 46, right: 56, fontFamily: "var(--font-mono)", fontSize: 12, letterSpacing: "0.2em", color: "rgba(21,20,20,0.42)" }}>v1 · working</div>
      </React.Fragment>}
    </div>
  );
}

// ════════════════════════════════════════════════════════════════
// FILM
// ════════════════════════════════════════════════════════════════
function Film({ W, H, vertical }) {
  const t = _useTime();
  const tl = window.useTimeline();
  React.useEffect(() => {
    window.__seek = (sec) => { tl.setPlaying(false); tl.setTime(sec); };
    window.__play = () => tl.setPlaying(true);
  }, [tl]);

  // phone geometry (logical outer 386×806)
  const targetH = vertical ? H * 0.66 : H * 0.86;
  const scale = targetH / 806;
  const w = 386 * scale, h = 806 * scale;
  const cx = vertical ? W / 2 : W * 0.355;
  const cy = vertical ? H * 0.40 : H * 0.5;
  const phone = { cx, cy, w, h, scale };

  // phone entry (dive) 2.75 → 3.35 : rise + scale + fade
  const enter = _clamp((t - 2.75) / 0.7, 0, 1);
  const eE = eO(enter);
  // gentle ken-burns camera drift through the film
  const drift = Math.sin(_clamp((t - 3) / 11, 0, 1) * Math.PI); // 0→1→0
  const camScale = 1 + drift * (vertical ? 0.03 : 0.045);
  const phoneVisible = t > 2.6 && t < 20.1;

  return (
    <div data-film-root style={{ position: "absolute", inset: 0, background: "var(--p-parchment)", overflow: "hidden" }}>
      <Ambient W={W} H={H} vertical={vertical} phone={phone} />

      {/* phone */}
      {phoneVisible && (
        <div style={{ position: "absolute", left: cx, top: cy,
          transform: `translate(-50%,-50%) translateY(${(1 - eE) * 80}px) scale(${scale * camScale})`,
          opacity: enter, transformOrigin: "center" }}>
          <PhoneFrame><PhoneScreens /></PhoneFrame>
        </div>
      )}

      <Captions W={W} H={H} vertical={vertical} phone={phone} />
      <ColdOpen W={W} H={H} vertical={vertical} />
      <EndCard W={W} H={H} vertical={vertical} />

      {/* second-by-second label for comments */}
      <TimeLabel />
    </div>
  );
}

function TimeLabel() {
  const t = _useTime();
  React.useEffect(() => {
    const root = document.querySelector("[data-film-root]");
    if (root) root.setAttribute("data-screen-label", "t=" + t.toFixed(0) + "s");
  }, [Math.floor(t)]);
  return null;
}

Object.assign(window, { Film, PhoneFrame, BEATS });
