// scenes.jsx — OfferGlow Studio 15s promo. Scene components + helpers.
// Loaded after animations.jsx; uses window globals (Sprite, useSprite, Easing, clamp, interpolate).

// ── Palette ──────────────────────────────────────────────────────────────────
const OG = {
  paper:    '#fcfaf5',
  paper2:   '#f7f1e8',
  charcoal: '#2a2520',
  charcoalSoft: '#6b6358',
  gold:     '#b8924a',
  goldBright:'#d4ad62',
  goldDeep: '#8f6e33',
  sage:     '#5e7a63',
  cream:    '#f8f3ea',
};
const FD = "'Cormorant Garamond', Georgia, serif";   // display
const FB = "'Source Serif 4', Georgia, serif";        // body
const FM = "'JetBrains Mono', ui-monospace, monospace"; // mono

// ── Custom cubic-bezier easing (ease-lux) ───────────────────────────────────
function cubicBezier(x1, y1, x2, y2) {
  const A = (a, b) => 1 - 3 * b + 3 * a;
  const B = (a, b) => 3 * b - 6 * a;
  const C = (a) => 3 * a;
  const calc = (t, a, b) => ((A(a, b) * t + B(a, b)) * t + C(a)) * t;
  const slope = (t, a, b) => 3 * A(a, b) * t * t + 2 * B(a, b) * t + C(a);
  const getT = (x) => {
    let t = x;
    for (let i = 0; i < 6; i++) {
      const s = slope(t, x1, x2);
      if (s === 0) break;
      t -= (calc(t, x1, x2) - x) / s;
    }
    return t;
  };
  return (x) => (x <= 0 ? 0 : x >= 1 ? 1 : calc(getT(x), y1, y2));
}
const easeLux = cubicBezier(0.16, 1, 0.3, 1);

// ── SceneFade: gates content to [start,end] with crossfade in/out ────────────
function SceneFade({ start, end, fadeIn = 0.5, fadeOut = 0.5, z = 1, children }) {
  return (
    <Sprite start={start - 0.01} end={end + 0.5}>
      {({ localTime }) => {
        const d = end - start;
        let o = 1;
        if (localTime < fadeIn) o = clamp(localTime / fadeIn, 0, 1);
        else if (localTime > d - fadeOut) o = clamp((d - localTime) / fadeOut, 0, 1);
        return (
          <div style={{ position: 'absolute', inset: 0, opacity: o, zIndex: z }}>
            {children}
          </div>
        );
      }}
    </Sprite>
  );
}

// ── GoldWipe: before→after reveal driven by `p` (0..1), gold line follows edge ─
function GoldWipe({ before, after, p, width, height, radius = 0, beforeFilter, lineW = 5 }) {
  const linePx = p * width;
  const showLine = p > 0.002 && p < 0.998;
  return (
    <div style={{ position: 'relative', width, height, borderRadius: radius, overflow: 'hidden', background: '#1a1714' }}>
      <img src={before} alt="" style={{
        position: 'absolute', inset: 0, width: '100%', height: '100%',
        objectFit: 'cover', display: 'block', filter: beforeFilter || 'saturate(0.8) brightness(0.96)',
      }} />
      <div style={{ position: 'absolute', inset: 0, clipPath: `inset(0 ${width - linePx}px 0 0)`, willChange: 'clip-path' }}>
        <img src={after} alt="" style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }} />
      </div>
      {showLine && (
        <React.Fragment>
          {/* soft warm glow ahead of the line */}
          <div style={{
            position: 'absolute', top: 0, bottom: 0, left: linePx - 70, width: 140,
            background: 'linear-gradient(90deg, rgba(184,146,74,0) 0%, rgba(212,173,98,0.28) 50%, rgba(184,146,74,0) 100%)',
            pointerEvents: 'none',
          }} />
          {/* the gold line */}
          <div style={{
            position: 'absolute', top: 0, bottom: 0, left: linePx - lineW / 2, width: lineW,
            background: 'linear-gradient(180deg, #e3c074 0%, #b8924a 50%, #e3c074 100%)',
            boxShadow: '0 0 24px 4px rgba(212,173,98,0.55)',
          }} />
        </React.Fragment>
      )}
    </div>
  );
}

// ── Vignette + grain overlay for full-bleed photo scenes ─────────────────────
function PhotoVignette() {
  return (
    <div style={{
      position: 'absolute', inset: 0, pointerEvents: 'none',
      background: 'radial-gradient(120% 100% at 50% 42%, rgba(0,0,0,0) 52%, rgba(20,16,12,0.42) 100%)',
    }} />
  );
}

// ── Mono chip (BEFORE label / tile labels) ───────────────────────────────────
function MonoChip({ text, dark = true, gold = false, style }) {
  return (
    <div style={{
      display: 'inline-flex', alignItems: 'center',
      padding: '9px 16px', borderRadius: 4,
      fontFamily: FM, fontSize: 17, fontWeight: 500, letterSpacing: '0.22em', textTransform: 'uppercase',
      background: gold ? OG.gold : 'rgba(20,16,12,0.5)',
      color: gold ? '#241b0c' : OG.cream,
      border: gold ? 'none' : '1px solid rgba(248,243,234,0.22)',
      backdropFilter: 'blur(8px)', WebkitBackdropFilter: 'blur(8px)',
      boxShadow: gold ? '0 0 26px rgba(184,146,74,0.5)' : 'none',
      whiteSpace: 'nowrap',
      ...style,
    }}>{text}</div>
  );
}

// ═══════════════════════════════════════════════════════════════════════════
// SCENE 1 — Intro [0–3s]: empty living room, "BEFORE", "Empty rooms don't sell."
// ═══════════════════════════════════════════════════════════════════════════
function SceneIntro({ W, H }) {
  const { localTime } = useSprite();
  // slow ken-burns push-in
  const scale = 1.04 + 0.05 * Easing.easeOutSine(clamp(localTime / 3, 0, 1));
  // BEFORE chip fade
  const chipO = clamp((localTime - 0.25) / 0.5, 0, 1);
  // headline rise
  const hP = clamp((localTime - 1.0) / 0.9, 0, 1);
  const hEase = easeLux(hP);
  return (
    <div style={{ position: 'absolute', inset: 0, overflow: 'hidden', background: '#15110d' }}>
      <img src="photos/living-before.jpg" alt="" style={{
        position: 'absolute', inset: 0, width: '100%', height: '100%', objectFit: 'cover',
        transform: `scale(${scale})`, transformOrigin: '60% 50%',
        filter: 'saturate(0.78) brightness(0.95) contrast(0.98)', willChange: 'transform',
      }} />
      <PhotoVignette />
      {/* bottom scrim for text */}
      <div style={{ position: 'absolute', left: 0, right: 0, bottom: 0, height: 460,
        background: 'linear-gradient(0deg, rgba(18,14,10,0.72) 0%, rgba(18,14,10,0) 100%)', pointerEvents: 'none' }} />
      {/* BEFORE chip top-left */}
      <div style={{ position: 'absolute', top: 70, left: 84, opacity: chipO,
        transform: `translateY(${(1 - chipO) * 10}px)` }}>
        <MonoChip text="Before" />
      </div>
      {/* headline */}
      <div style={{ position: 'absolute', left: 84, bottom: 96, opacity: hEase,
        transform: `translateY(${(1 - hEase) * 26}px)` }}>
        <div style={{ fontFamily: FD, fontSize: 92, fontWeight: 500, color: OG.cream, lineHeight: 1.02,
          letterSpacing: '-0.01em', textShadow: '0 2px 30px rgba(0,0,0,0.4)' }}>
          Empty rooms<br/>don't sell.
        </div>
      </div>
    </div>
  );
}

// ═══════════════════════════════════════════════════════════════════════════
// SCENE 2 — Hero reveal [3–7s]: gold wipe living-before → living-after
// ═══════════════════════════════════════════════════════════════════════════
function SceneHero({ W, H }) {
  const { localTime } = useSprite();
  // wipe runs from t=0.2 to t=1.7 (within this scene), ease-lux
  const wipeP = easeLux(clamp((localTime - 0.2) / 1.5, 0, 1));
  const scale = 1.0 + 0.04 * Easing.easeOutSine(clamp(localTime / 4, 0, 1));
  // BEFORE chip fades out as wipe begins
  const beforeO = clamp(1 - (localTime - 0.15) / 0.5, 0, 1);
  // AFTER pill in after wipe
  const afterP = clamp((localTime - 1.55) / 0.5, 0, 1);
  const afterE = Easing.easeOutCubic(afterP);
  // headline rise after wipe
  const hP = clamp((localTime - 1.85) / 0.8, 0, 1);
  const hE = easeLux(hP);
  return (
    <div style={{ position: 'absolute', inset: 0, overflow: 'hidden', background: '#15110d' }}>
      <div style={{ position: 'absolute', inset: 0, transform: `scale(${scale})`, transformOrigin: '60% 50%', willChange: 'transform' }}>
        <GoldWipe before="photos/living-before.jpg" after="photos/living-after.jpg"
          p={wipeP} width={W} height={H} beforeFilter="saturate(0.78) brightness(0.95)" lineW={6} />
      </div>
      <PhotoVignette />
      <div style={{ position: 'absolute', left: 0, right: 0, bottom: 0, height: 440,
        background: 'linear-gradient(0deg, rgba(18,14,10,0.66) 0%, rgba(18,14,10,0) 100%)', pointerEvents: 'none' }} />
      {/* BEFORE chip fading out */}
      <div style={{ position: 'absolute', top: 70, left: 84, opacity: beforeO }}>
        <MonoChip text="Before" />
      </div>
      {/* AFTER · STAGED gold pill top-right */}
      <div style={{ position: 'absolute', top: 70, right: 84, opacity: afterE,
        transform: `translateY(${(1 - afterE) * 10}px)` }}>
        <MonoChip text="After · Staged" gold />
      </div>
      {/* headline bottom-left */}
      <div style={{ position: 'absolute', left: 84, bottom: 96, opacity: hE,
        transform: `translateY(${(1 - hE) * 26}px)` }}>
        <div style={{ fontFamily: FD, fontSize: 96, fontWeight: 500, color: OG.cream, lineHeight: 1.0,
          letterSpacing: '-0.01em', textShadow: '0 2px 30px rgba(0,0,0,0.45)' }}>
          Staged in <span style={{ fontStyle: 'italic', color: OG.goldBright }}>24 hours.</span>
        </div>
      </div>
    </div>
  );
}

// ═══════════════════════════════════════════════════════════════════════════
// SCENE 3 — Montage [7–11s]: 3 reveals + Glow Score gauge
// ═══════════════════════════════════════════════════════════════════════════
function GaugeRing({ value, size = 232 }) {
  const stroke = 12;
  const R = (size - stroke - 6) / 2;
  const C = 2 * Math.PI * R;
  const off = C - (value / 100) * C;
  return (
    <div style={{ position: 'relative', width: size, height: size }}>
      <svg width={size} height={size} style={{ transform: 'rotate(-90deg)' }}>
        <circle cx={size / 2} cy={size / 2} r={R} fill="none" stroke="rgba(42,37,32,0.12)" strokeWidth={stroke} />
        <circle cx={size / 2} cy={size / 2} r={R} fill="none" stroke={OG.gold} strokeWidth={stroke}
          strokeLinecap="round" strokeDasharray={C} strokeDashoffset={off}
          style={{ filter: 'drop-shadow(0 0 8px rgba(184,146,74,0.45))' }} />
      </svg>
      <div style={{ position: 'absolute', inset: 0, display: 'grid', placeItems: 'center' }}>
        <span style={{ fontFamily: FD, fontSize: size * 0.4, fontWeight: 600, color: OG.charcoal, lineHeight: 1 }}>
          {Math.round(value)}
        </span>
      </div>
    </div>
  );
}

function MontageTile({ before, after, label, x, y, w, h, p }) {
  return (
    <div style={{ position: 'absolute', left: x, top: y }}>
      <div style={{ boxShadow: '0 22px 50px -20px rgba(42,37,32,0.4)', borderRadius: 10, overflow: 'hidden',
        border: '1px solid rgba(42,37,32,0.08)' }}>
        <GoldWipe before={before} after={after} p={p} width={w} height={h} radius={10} lineW={4} />
      </div>
      <div style={{ marginTop: 16, fontFamily: FM, fontSize: 14, fontWeight: 500, letterSpacing: '0.24em',
        textTransform: 'uppercase', color: OG.charcoalSoft }}>{label}</div>
    </div>
  );
}

function SceneMontage({ W, H }) {
  const { localTime } = useSprite();
  // caption
  const capP = clamp((localTime - 0.2) / 0.6, 0, 1);
  const capE = easeLux(capP);
  // tile wipes staggered
  const tw = (s) => easeLux(clamp((localTime - s) / 0.9, 0, 1));
  const p1 = tw(0.45), p2 = tw(0.8), p3 = tw(1.15);
  // gauge: number 34→94, ring follows
  const gP = clamp((localTime - 1.5) / 1.5, 0, 1);
  const gE = Easing.easeOutCubic(gP);
  const gVal = 34 + (94 - 34) * gE;
  // +60 badge pop
  const bP = clamp((localTime - 3.0) / 0.5, 0, 1);
  const bE = Easing.easeOutBack(bP);
  // tile layout
  const tw_ = 498, th_ = 332, gap = 54;
  const totalW = tw_ * 3 + gap * 2;
  const x0 = (W - totalW) / 2;
  const ty = 218;
  return (
    <div style={{ position: 'absolute', inset: 0, background: OG.paper2, overflow: 'hidden' }}>
      {/* caption */}
      <div style={{ position: 'absolute', top: 96, left: 0, right: 0, textAlign: 'center', opacity: capE,
        transform: `translateY(${(1 - capE) * 12}px)` }}>
        <div style={{ fontFamily: FM, fontSize: 25, fontWeight: 500, letterSpacing: '0.32em', textTransform: 'uppercase',
          color: OG.charcoal }}>Every room. Ready to list.</div>
      </div>
      {/* tiles */}
      <MontageTile before="photos/kitchen-before.jpg" after="photos/kitchen-after.jpg" label="Kitchen"
        x={x0} y={ty} w={tw_} h={th_} p={p1} />
      <MontageTile before="photos/bedroom-before.jpg" after="photos/bedroom-after.jpg" label="Bedroom"
        x={x0 + tw_ + gap} y={ty} w={tw_} h={th_} p={p2} />
      <MontageTile before="photos/frontyard-before.jpg" after="photos/frontyard-after.jpg" label="Exterior"
        x={x0 + (tw_ + gap) * 2} y={ty} w={tw_} h={th_} p={p3} />
      {/* gauge group, centered low */}
      <div style={{ position: 'absolute', left: 0, right: 0, bottom: 96, display: 'flex',
        justifyContent: 'center', alignItems: 'center', gap: 40 }}>
        <GaugeRing value={gVal} />
        <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
          <div style={{ fontFamily: FM, fontSize: 15, fontWeight: 500, letterSpacing: '0.22em',
            textTransform: 'uppercase', color: OG.goldDeep, whiteSpace: 'nowrap' }}>Listing Glow Score</div>
          <div style={{ display: 'flex', alignItems: 'center', gap: 18 }}>
            <span style={{ fontFamily: FB, fontSize: 21, color: OG.charcoalSoft, whiteSpace: 'nowrap' }}>34 &nbsp;→&nbsp; 94</span>
            <div style={{ opacity: clamp(bP, 0, 1), transform: `scale(${0.4 + 0.6 * bE})`, transformOrigin: 'left center' }}>
              <span style={{ display: 'inline-block', padding: '7px 16px', borderRadius: 999,
                background: 'rgba(94,122,99,0.14)', border: `1px solid ${OG.sage}`,
                fontFamily: FM, fontSize: 17, fontWeight: 600, letterSpacing: '0.04em', color: OG.sage }}>+60</span>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

// ═══════════════════════════════════════════════════════════════════════════
// SCENE 4 — End card [11–15s]
// ═══════════════════════════════════════════════════════════════════════════
function GlowMark({ size = 78 }) {
  return (
    <svg width={size} height={size} viewBox="0 0 40 40" fill="none" aria-hidden="true">
      <defs>
        <radialGradient id="ogglow" cx="50%" cy="62%" r="62%">
          <stop offset="0%" stopColor={OG.goldBright} />
          <stop offset="100%" stopColor={OG.goldDeep} />
        </radialGradient>
      </defs>
      <rect x="1.2" y="1.2" width="37.6" height="37.6" rx="11" fill="none" stroke={OG.gold} strokeWidth="1.4" />
      <circle cx="20" cy="22" r="8.4" fill="url(#ogglow)" />
      <path d="M6 27.5h28" stroke={OG.charcoal} strokeWidth="1.6" strokeLinecap="round" opacity="0.85" />
      <g stroke={OG.goldDeep} strokeWidth="1.4" strokeLinecap="round" opacity="0.9">
        <path d="M20 7v3.4" /><path d="M31 12.5l-2.2 2.2" /><path d="M9 12.5l2.2 2.2" />
      </g>
    </svg>
  );
}

function SceneEnd({ W, H }) {
  const { localTime } = useSprite();
  const rise = (s, dur = 0.7) => {
    const p = clamp((localTime - s) / dur, 0, 1);
    const e = easeLux(p);
    return { opacity: e, transform: `translateY(${(1 - e) * 22}px)` };
  };
  // slow continuous push on whole card
  const cardScale = 1.0 + 0.018 * Easing.easeOutSine(clamp(localTime / 4, 0, 1));
  // button glow pulse
  const pulse = 0.5 + 0.5 * Math.sin((localTime) * 1.6);
  const glow = 18 + pulse * 18;
  return (
    <div style={{ position: 'absolute', inset: 0, background: OG.paper, overflow: 'hidden',
      display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
      <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center',
        transform: `scale(${cardScale})`, transformOrigin: 'center' }}>
        {/* monogram */}
        <div style={{ ...rise(0.15, 0.7) }}>
          <GlowMark size={76} />
        </div>
        {/* thin gold rule */}
        <div style={{ width: 64, height: 1, background: OG.gold, margin: '30px 0 30px', opacity: rise(0.3).opacity }} />
        {/* wordmark */}
        <div style={{ ...rise(0.35, 0.75), fontFamily: FD, fontWeight: 600, fontSize: 116, lineHeight: 1,
          color: OG.charcoal, letterSpacing: '-0.005em', whiteSpace: 'nowrap' }}>
          Offer<span style={{ color: OG.goldDeep, fontStyle: 'italic', fontWeight: 500 }}>Glow</span>
          <span style={{ fontFamily: FM, fontSize: 48, letterSpacing: '0.26em', textTransform: 'uppercase',
            color: OG.charcoalSoft, marginLeft: 16, verticalAlign: 'middle', fontWeight: 500 }}>Studio</span>
        </div>
        {/* tagline */}
        <div style={{ ...rise(0.6, 0.75), fontFamily: FB, fontSize: 30, color: OG.charcoalSoft,
          marginTop: 30, letterSpacing: '0.01em', whiteSpace: 'nowrap' }}>
          Staged listing visuals with the original proof still attached.
        </div>
        {/* CTA */}
        <div style={{ ...rise(0.9, 0.7), marginTop: 52 }}>
          <div style={{ display: 'inline-flex', alignItems: 'center', gap: 12, padding: '20px 40px',
            borderRadius: 8, background: OG.gold, color: '#241b0c', fontFamily: FB, fontWeight: 600, fontSize: 25,
            whiteSpace: 'nowrap',
            boxShadow: `0 0 ${glow}px rgba(184,146,74,${0.35 + pulse * 0.25}), 0 14px 30px -12px rgba(184,146,74,0.5)` }}>
            Launch a listing
            <span style={{ fontSize: 26, marginLeft: 4 }}>→</span>
          </div>
        </div>
        {/* URL */}
        <div style={{ ...rise(1.15, 0.7), marginTop: 34, fontFamily: FM, fontSize: 18, letterSpacing: '0.22em',
          textTransform: 'uppercase', color: OG.goldDeep }}>
          offerglowstudio.com
        </div>
      </div>
    </div>
  );
}

// ── Root composition ─────────────────────────────────────────────────────────
function Promo({ W, H }) {
  const t = useTime();
  const tl = useTimeline();
  React.useEffect(() => { window.__ctrl = { setTime: tl.setTime, setPlaying: tl.setPlaying }; }, [tl.setTime, tl.setPlaying]);
  // update screen label each second for commenting
  React.useEffect(() => {
    const root = document.getElementById('promo-root');
    if (root) root.setAttribute('data-screen-label', `t=${Math.floor(t)}s`);
  }, [Math.floor(t)]);
  return (
    <div id="promo-root" style={{ position: 'absolute', inset: 0 }}>
      <SceneFade start={0} end={3.0} fadeIn={0.01} fadeOut={0.5} z={1}>
        <Sprite start={0} end={3.5}><SceneIntro W={W} H={H} /></Sprite>
      </SceneFade>
      <SceneFade start={2.9} end={7.0} fadeIn={0.4} fadeOut={0.5} z={2}>
        <Sprite start={2.9} end={7.5}><SceneHero W={W} H={H} /></Sprite>
      </SceneFade>
      <SceneFade start={6.9} end={11.0} fadeIn={0.45} fadeOut={0.5} z={3}>
        <Sprite start={6.9} end={11.5}><SceneMontage W={W} H={H} /></Sprite>
      </SceneFade>
      <SceneFade start={10.9} end={15.0} fadeIn={0.45} fadeOut={0.01} z={4}>
        <Sprite start={10.9} end={15.2}><SceneEnd W={W} H={H} /></Sprite>
      </SceneFade>
    </div>
  );
}

Object.assign(window, { Promo, OG });
