// scenes.jsx — Plus Migration animation scenes & sprites
// Composes against <Stage>, <Sprite>, useTime, Easing, interpolate from animations.jsx

// ─── Palette ─────────────────────────────────────────────────────────────
const PALETTE = {
  cream: '#f5f0e8',
  creamDeep: '#ede6d8',
  paper: '#faf6ee',
  moss600: '#3f6b54',
  moss500: '#4d7e65',
  moss400: '#6fa37a',
  moss200: '#b8cdbb',
  moss100: '#d7e1d4',
  amber: '#cd8a4b',
  amberSoft: '#e2a568',
  ink: '#0f1713',
  ink70: 'rgba(15,23,19,0.72)',
  ink40: 'rgba(15,23,19,0.40)',
  ink15: 'rgba(15,23,19,0.15)',
};

const FONTS = {
  display: '"Space Grotesk", system-ui, sans-serif',
  serif: '"Instrument Serif", Georgia, serif',
  mono: '"JetBrains Mono", ui-monospace, monospace',
};

// ─── Utility: smooth step ─────────────────────────────────────────────────
const smooth = (t) => t < 0 ? 0 : t > 1 ? 1 : t * t * (3 - 2 * t);
const mix = (a, b, t) => a + (b - a) * t;

// Converts any t to a fade-in/out envelope: rises in `fadeIn`, sits at 1, falls in `fadeOut`.
const envelope = (localT, duration, fadeIn = 0.4, fadeOut = 0.4) => {
  if (localT < 0 || localT > duration) return 0;
  if (localT < fadeIn) return smooth(localT / fadeIn);
  if (localT > duration - fadeOut) return smooth((duration - localT) / fadeOut);
  return 1;
};

// ─── Film grain overlay ───────────────────────────────────────────────────
function FilmGrain() {
  return (
    <div style={{
      position: 'absolute', inset: 0, pointerEvents: 'none',
      opacity: 0.09, mixBlendMode: 'multiply',
      backgroundImage: `url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='200' height='200'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='1.6' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0.15  0 0 0 0 0.13  0 0 0 0 0.08  0 0 0 1 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>")`,
      backgroundSize: '200px 200px',
    }} />
  );
}

// Subtle vignette
function Vignette() {
  return (
    <div style={{
      position: 'absolute', inset: 0, pointerEvents: 'none',
      background: 'radial-gradient(ellipse at center, rgba(0,0,0,0) 55%, rgba(40,30,15,0.10) 100%)',
    }} />
  );
}

// ─── Corner chrome (persistent) ──────────────────────────────────────────
function CornerChrome() {
  const time = useTime();
  const pulse = 0.5 + 0.5 * Math.sin(time * Math.PI * 1.2);
  return (
    <>
      {/* Top-left wordmark */}
      <div style={{
        position: 'absolute', left: 56, top: 52,
        fontFamily: FONTS.display,
        fontWeight: 700,
        fontSize: 20,
        letterSpacing: '-0.03em',
        color: PALETTE.ink,
        opacity: 0.45,
      }}>
        digital.<span style={{ fontFamily: FONTS.serif, fontStyle: 'italic', fontWeight: 400, letterSpacing: '-0.02em' }}>HEROES</span>.
      </div>

      {/* Bottom-right caption + pulse */}
      <div style={{
        position: 'absolute', right: 56, bottom: 52,
        display: 'flex', alignItems: 'center', gap: 12,
        fontFamily: FONTS.mono,
        fontSize: 13,
        letterSpacing: '0.02em',
        color: PALETTE.ink70,
        textTransform: 'uppercase',
      }}>
        <div style={{
          width: 8, height: 8, borderRadius: 4,
          background: PALETTE.moss500,
          opacity: 0.4 + 0.6 * pulse,
          boxShadow: `0 0 ${8 + 12 * pulse}px ${PALETTE.moss400}`,
        }}/>
        <span>§ 06 · plus migration</span>
      </div>

      {/* Top-right edition line */}
      <div style={{
        position: 'absolute', right: 56, top: 52,
        fontFamily: FONTS.mono,
        fontSize: 12,
        letterSpacing: '0.12em',
        color: PALETTE.ink40,
        textTransform: 'uppercase',
      }}>
        vol. 01 — shopify plus · ed. mmxxvi
      </div>

      {/* Bottom-left folio */}
      <div style={{
        position: 'absolute', left: 56, bottom: 52,
        fontFamily: FONTS.mono,
        fontSize: 12,
        letterSpacing: '0.12em',
        color: PALETTE.ink40,
      }}>
        fig.&nbsp;&nbsp;06·ii — the pipeline
      </div>
    </>
  );
}

// ─── Source platform tile ────────────────────────────────────────────────
// Editorial card showing a source platform wordmark on the left side.
function SourceTile({ x, y, label, caption, start, appearDur = 0.6 }) {
  const time = useTime();
  const localT = time - start;
  const t = smooth(Math.min(1, Math.max(0, localT / appearDur)));

  // Fade out during launch moment (10–13s window)
  const fadeOutStart = 10;
  const fadeOutDur = 2.5;
  let exitOpacity = 1;
  if (time > fadeOutStart) {
    exitOpacity = 1 - smooth(Math.min(1, (time - fadeOutStart) / fadeOutDur));
  }
  // Fade back in during reset 13–15s
  if (time > 13) {
    exitOpacity = smooth(Math.min(1, (time - 13) / 1.8));
  }

  // Gentle drift while alive
  const drift = Math.sin((time + x * 0.01) * 0.5) * 3;

  const opacity = t * exitOpacity;
  const ty = mix(14, 0, t) + drift;

  return (
    <div style={{
      position: 'absolute',
      left: x, top: y,
      width: 260, height: 120,
      transform: `translateY(${ty}px)`,
      opacity,
      willChange: 'transform, opacity',
    }}>
      <div style={{
        width: '100%', height: '100%',
        background: 'rgba(255,253,247,0.6)',
        backdropFilter: 'blur(4px)',
        border: `1px solid ${PALETTE.moss200}`,
        borderRadius: 2,
        padding: '22px 26px',
        display: 'flex', flexDirection: 'column', justifyContent: 'space-between',
        position: 'relative',
      }}>
        {/* tiny corner marks */}
        <div style={{ position: 'absolute', top: 6, left: 6, width: 8, height: 8, borderTop: `1px solid ${PALETTE.moss400}`, borderLeft: `1px solid ${PALETTE.moss400}` }}/>
        <div style={{ position: 'absolute', top: 6, right: 6, width: 8, height: 8, borderTop: `1px solid ${PALETTE.moss400}`, borderRight: `1px solid ${PALETTE.moss400}` }}/>
        <div style={{ position: 'absolute', bottom: 6, left: 6, width: 8, height: 8, borderBottom: `1px solid ${PALETTE.moss400}`, borderLeft: `1px solid ${PALETTE.moss400}` }}/>
        <div style={{ position: 'absolute', bottom: 6, right: 6, width: 8, height: 8, borderBottom: `1px solid ${PALETTE.moss400}`, borderRight: `1px solid ${PALETTE.moss400}` }}/>

        <div style={{
          fontFamily: FONTS.mono,
          fontSize: 11,
          letterSpacing: '0.18em',
          color: PALETTE.moss500,
          textTransform: 'uppercase',
        }}>
          source · {caption}
        </div>

        <div style={{
          fontFamily: FONTS.display,
          fontWeight: 700,
          fontSize: 26,
          letterSpacing: '-0.03em',
          color: PALETTE.ink,
          lineHeight: 1,
        }}>
          {label}
        </div>
      </div>
    </div>
  );
}

// ─── Data stream (flowing dashed lines with labels) ──────────────────────
// Draws an SVG path from source to hub with animated dash offset, plus
// floating data-word labels that drift along the path.
function DataStream({ fromX, fromY, toX, toY, start, end, label, delay = 0 }) {
  const time = useTime();
  const active = time >= start && time <= end;
  if (!active) return null;

  const localT = time - start;
  const appear = smooth(Math.min(1, localT / 0.6));
  const duration = end - start;
  const exit = smooth(Math.min(1, Math.max(0, (time - (end - 0.8)) / 0.8)));
  const opacity = appear * (1 - exit);

  // Path: gentle bezier curve from source to hub
  const midX = (fromX + toX) / 2;
  const midY = (fromY + toY) / 2 - 40;
  const d = `M ${fromX} ${fromY} Q ${midX} ${midY} ${toX} ${toY}`;

  // Animated dash offset
  const dashOffset = -(time * 120);

  // Label position along path (approx at t=0.4 on curve)
  const bezierAt = (t) => {
    const mt = 1 - t;
    return {
      x: mt * mt * fromX + 2 * mt * t * midX + t * t * toX,
      y: mt * mt * fromY + 2 * mt * t * midY + t * t * toY,
    };
  };
  // Label flies along the path
  const labelProgress = ((localT + delay) * 0.35) % 1;
  const labelPos = bezierAt(labelProgress);
  const labelFade = Math.sin(labelProgress * Math.PI); // fade at ends

  return (
    <>
      <svg
        style={{ position: 'absolute', inset: 0, pointerEvents: 'none', opacity }}
        width="1920" height="1080" viewBox="0 0 1920 1080"
      >
        <path
          d={d}
          fill="none"
          stroke={PALETTE.moss400}
          strokeWidth="1.4"
          strokeDasharray="4 8"
          strokeDashoffset={dashOffset}
          opacity="0.85"
        />
        {/* faint guide line */}
        <path d={d} fill="none" stroke={PALETTE.moss200} strokeWidth="1" opacity="0.4" />
      </svg>
      {/* Traveling label */}
      <div style={{
        position: 'absolute',
        left: labelPos.x, top: labelPos.y,
        transform: 'translate(-50%, -50%)',
        opacity: opacity * labelFade * 0.9,
        fontFamily: FONTS.mono,
        fontSize: 11,
        letterSpacing: '0.14em',
        color: PALETTE.moss600,
        textTransform: 'uppercase',
        background: PALETTE.paper,
        padding: '3px 8px',
        border: `1px solid ${PALETTE.moss200}`,
        whiteSpace: 'nowrap',
        willChange: 'transform, opacity',
      }}>
        {label}
      </div>
    </>
  );
}

// ─── Liquid drop hub (organic morphing blob) ─────────────────────────────
function LiquidHub({ cx, cy, start, launchAt }) {
  const time = useTime();
  const localT = time - start;
  const appear = smooth(Math.min(1, localT / 1.2));

  // Launch glow intensity
  const launchT = Math.max(0, time - launchAt);
  const launchGlow = smooth(Math.min(1, launchT / 1.2));
  // Reverse fade at end
  const resetT = Math.max(0, time - 13);
  const resetFade = 1 - smooth(Math.min(1, resetT / 1.6));

  // Morphing border radius — smooth organic
  const w = 3;
  const r1 = 50 + Math.sin(time * w * 0.7) * 14;
  const r2 = 50 + Math.cos(time * w * 0.6 + 1) * 16;
  const r3 = 50 + Math.sin(time * w * 0.9 + 2) * 12;
  const r4 = 50 + Math.cos(time * w * 0.5 + 3) * 18;

  const size = mix(60, 220, appear) * resetFade + (1 - resetFade) * 60;
  const scaleBoost = 1 + launchGlow * 0.12;

  // Text morph: hub text appears only after launchAt
  const textOpacity = smooth(Math.min(1, (time - launchAt) / 0.8)) * resetFade;

  return (
    <div style={{
      position: 'absolute',
      left: cx, top: cy,
      transform: `translate(-50%, -50%) scale(${scaleBoost})`,
      willChange: 'transform',
    }}>
      {/* Amber glow aura — only active at launch */}
      <div style={{
        position: 'absolute',
        left: '50%', top: '50%',
        width: size * 3.5, height: size * 3.5,
        transform: 'translate(-50%, -50%)',
        background: `radial-gradient(circle, ${PALETTE.amberSoft}66 0%, ${PALETTE.amber}22 30%, transparent 65%)`,
        opacity: launchGlow * 0.85,
        filter: 'blur(8px)',
        pointerEvents: 'none',
      }}/>

      {/* The blob */}
      <div style={{
        width: size, height: size,
        background: `radial-gradient(circle at 38% 32%, ${PALETTE.moss400}, ${PALETTE.moss600} 75%)`,
        borderRadius: `${r1}% ${100-r1}% ${r2}% ${100-r2}% / ${r3}% ${r4}% ${100-r4}% ${100-r3}%`,
        transition: 'none',
        boxShadow: `
          inset -10px -14px 28px rgba(15,23,19,0.35),
          inset 8px 10px 24px rgba(255,255,255,0.12),
          0 18px 42px rgba(63,107,84,0.28)
        `,
        position: 'relative',
      }}>
        {/* Highlight */}
        <div style={{
          position: 'absolute', left: '22%', top: '18%',
          width: '28%', height: '20%',
          background: 'radial-gradient(ellipse, rgba(255,255,255,0.5), transparent 70%)',
          borderRadius: '50%',
          filter: 'blur(4px)',
        }}/>
      </div>

      {/* Center label (appears at launch) */}
      {textOpacity > 0.01 && (
        <div style={{
          position: 'absolute',
          left: '50%', top: '50%',
          transform: 'translate(-50%, -50%)',
          opacity: textOpacity,
          textAlign: 'center',
          whiteSpace: 'nowrap',
          fontFamily: FONTS.display,
          fontWeight: 700,
          fontSize: 56,
          letterSpacing: '-0.04em',
          color: PALETTE.ink,
          mixBlendMode: 'normal',
          textShadow: '0 2px 6px rgba(245,240,232,0.8)',
        }}>
          Shopify <span style={{ fontFamily: FONTS.serif, fontStyle: 'italic', fontWeight: 400, color: PALETTE.moss600, letterSpacing: '-0.02em' }}>Plus</span>
        </div>
      )}
    </div>
  );
}

// ─── Orbit feature card (8 Plus features that assemble around hub) ───────
function OrbitFeature({ cx, cy, index, total, radius, start, end, label, italicize = false }) {
  const time = useTime();
  const localT = time - start;
  if (localT < 0 || time > end) return null;

  const appear = smooth(Math.min(1, localT / 0.5));
  const exit = smooth(Math.min(1, Math.max(0, (time - (end - 0.9)) / 0.9)));
  const opacity = appear * (1 - exit);

  // Base angle (evenly distributed). Small slow rotation.
  const rotSpeed = 0.08;
  const baseAngle = (index / total) * Math.PI * 2 - Math.PI / 2;
  const angle = baseAngle + time * rotSpeed;

  // Radius ramps in
  const r = mix(radius * 0.6, radius, appear);
  const x = cx + Math.cos(angle) * r;
  const y = cy + Math.sin(angle) * r;

  return (
    <div style={{
      position: 'absolute',
      left: x, top: y,
      transform: 'translate(-50%, -50%)',
      opacity,
      willChange: 'transform, opacity',
    }}>
      <div style={{
        padding: '10px 18px',
        background: PALETTE.paper,
        border: `1px solid ${PALETTE.moss200}`,
        borderRadius: 2,
        fontFamily: italicize ? FONTS.serif : FONTS.display,
        fontStyle: italicize ? 'italic' : 'normal',
        fontWeight: italicize ? 400 : 600,
        fontSize: italicize ? 22 : 16,
        letterSpacing: italicize ? '-0.01em' : '-0.02em',
        color: italicize ? PALETTE.moss600 : PALETTE.ink,
        whiteSpace: 'nowrap',
        boxShadow: '0 4px 14px rgba(63,107,84,0.12)',
        position: 'relative',
      }}>
        {label}
        {/* tick */}
        <div style={{
          position: 'absolute', left: -6, top: '50%',
          width: 6, height: 1,
          background: PALETTE.moss400,
          transform: 'translateY(-50%)',
        }}/>
      </div>
    </div>
  );
}

// ─── Caption bar (bottom-center running caption that describes what's happening) ───
function Caption({ start, end, eyebrow, text }) {
  const time = useTime();
  if (time < start || time > end) return null;
  const localT = time - start;
  const dur = end - start;
  const opacity = envelope(localT, dur, 0.35, 0.45);

  return (
    <div style={{
      position: 'absolute',
      left: '50%',
      bottom: 120,
      transform: 'translateX(-50%)',
      opacity,
      textAlign: 'center',
      willChange: 'opacity',
    }}>
      <div style={{
        fontFamily: FONTS.mono,
        fontSize: 12,
        letterSpacing: '0.24em',
        color: PALETTE.moss500,
        textTransform: 'uppercase',
        marginBottom: 10,
      }}>
        — {eyebrow} —
      </div>
      <div style={{
        fontFamily: FONTS.display,
        fontWeight: 500,
        fontSize: 22,
        letterSpacing: '-0.02em',
        color: PALETTE.ink70,
      }}>
        {text}
      </div>
    </div>
  );
}

// ─── Launch burst (amber ring that expands at launch moment) ─────────────
function LaunchBurst({ cx, cy, start }) {
  const time = useTime();
  const localT = time - start;
  if (localT < 0 || localT > 3) return null;

  const t = smooth(Math.min(1, localT / 2.4));
  const size = mix(280, 900, t);
  const opacity = (1 - t) * 0.55;

  return (
    <div style={{
      position: 'absolute',
      left: cx, top: cy,
      width: size, height: size,
      transform: 'translate(-50%, -50%)',
      borderRadius: '50%',
      border: `1.5px solid ${PALETTE.amber}`,
      opacity,
      pointerEvents: 'none',
    }}/>
  );
}

// ─── Rules / editorial frame ─────────────────────────────────────────────
function EditorialFrame() {
  return (
    <>
      {/* top rule */}
      <div style={{ position: 'absolute', left: 56, right: 56, top: 90, height: 1, background: PALETTE.ink15 }}/>
      {/* bottom rule */}
      <div style={{ position: 'absolute', left: 56, right: 56, bottom: 90, height: 1, background: PALETTE.ink15 }}/>
    </>
  );
}

// ─── Static section title (top of frame during sequence) ────────────────
function SectionTitle() {
  const time = useTime();
  // Always visible; fades during launch moment for cleanliness
  const launchFade = 1 - smooth(Math.min(1, Math.max(0, (time - 10.2) / 1.0))) * 0.6;
  const resetFade = smooth(Math.min(1, Math.max(0, (time - 13.2) / 1.2)));
  const opacity = Math.max(launchFade, resetFade);

  return (
    <div style={{
      position: 'absolute',
      left: '50%', top: 120,
      transform: 'translateX(-50%)',
      textAlign: 'center',
      opacity,
    }}>
      <div style={{
        fontFamily: FONTS.mono,
        fontSize: 12,
        letterSpacing: '0.28em',
        color: PALETTE.moss500,
        textTransform: 'uppercase',
        marginBottom: 14,
      }}>
        the pipeline ⸺ sources &nbsp;·&nbsp; hub &nbsp;·&nbsp; launch
      </div>
      <div style={{
        fontFamily: FONTS.display,
        fontWeight: 700,
        fontSize: 48,
        letterSpacing: '-0.04em',
        color: PALETTE.ink,
        lineHeight: 1,
      }}>
        Migrate <span style={{ fontFamily: FONTS.serif, fontStyle: 'italic', fontWeight: 400, color: PALETTE.moss600 }}>anything</span> to Plus.
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────────────────
// Main scene composition
// ─────────────────────────────────────────────────────────────────────────

function PlusMigrationScene() {
  const time = useTime();

  // Hub at right-center of frame (sources on left)
  const hubX = 1280;
  const hubY = 560;

  // Source tiles on the left
  const sources = [
    { label: 'Magento',                       caption: 'adobe · legacy',      y: 290 },
    { label: 'BigCommerce',                   caption: 'saas',                y: 480 },
    { label: 'Salesforce\nCommerce Cloud',    caption: 'enterprise',          y: 670 },
  ];

  // 8 features orbiting hub
  const features = [
    { label: 'Checkout Extensions',   italicize: false },
    { label: 'Functions',              italicize: true  },
    { label: 'Flow',                   italicize: true  },
    { label: 'Launchpad',              italicize: false },
    { label: 'B2B',                    italicize: true  },
    { label: 'Markets',                italicize: false },
    { label: 'Hydrogen',               italicize: true  },
    { label: 'OS 2.0',                 italicize: false },
  ];

  // Stream data-words
  const streams = [
    { from: 0, to: 0, delay: 0.0, label: 'products' },
    { from: 0, to: 0, delay: 0.4, label: 'metafields' },
    { from: 1, to: 0, delay: 0.1, label: 'customers' },
    { from: 1, to: 0, delay: 0.6, label: 'orders' },
    { from: 2, to: 0, delay: 0.2, label: 'metaobjects' },
    { from: 2, to: 0, delay: 0.7, label: 'redirects' },
  ];

  const sourceCenters = sources.map((_, i) => ({
    x: 260 + 260,  // tile left x + width
    y: 290 + i * 190 + 60, // tile y + half height
  }));

  // Feature appearance: each appears at 5 + i*0.6 s, exits at 13s
  const featureStart = 5.0;
  const featureStagger = 0.55;
  const featureEnd = 13.2;

  // Streams: live 2–10s
  const streamStart = 2.0;
  const streamEnd = 10.2;

  return (
    <>
      <EditorialFrame />
      <CornerChrome />
      <SectionTitle />

      {/* Source tiles (2–10s active, then fade) */}
      {sources.map((s, i) => (
        <SourceTile
          key={s.label}
          x={200}
          y={290 + i * 190}
          label={s.label}
          caption={s.caption}
          start={0.15 + i * 0.25}
        />
      ))}

      {/* Flow labels (source-side column header) */}
      <div style={{
        position: 'absolute', left: 200, top: 220,
        fontFamily: FONTS.mono,
        fontSize: 11,
        letterSpacing: '0.28em',
        color: PALETTE.moss500,
        textTransform: 'uppercase',
        opacity: envelope(time - 0.2, 13.0, 0.5, 1.2),
      }}>
        ◍ &nbsp; sources (3)
      </div>

      {/* Data streams (curves + traveling labels) */}
      {streams.map((st, i) => (
        <DataStream
          key={i}
          fromX={sourceCenters[st.from].x}
          fromY={sourceCenters[st.from].y}
          toX={hubX - 60}
          toY={hubY}
          label={st.label}
          start={streamStart + i * 0.18}
          end={streamEnd}
          delay={st.delay}
        />
      ))}

      {/* Hub label (top of hub area) */}
      <div style={{
        position: 'absolute', left: hubX, top: hubY - 230,
        transform: 'translateX(-50%)',
        fontFamily: FONTS.mono,
        fontSize: 11,
        letterSpacing: '0.28em',
        color: PALETTE.moss500,
        textTransform: 'uppercase',
        textAlign: 'center',
        opacity: envelope(time - 1.2, 12.0, 0.6, 1.0),
      }}>
        ◍ &nbsp; the hub
      </div>

      {/* Launch burst (behind hub) */}
      <LaunchBurst cx={hubX} cy={hubY} start={10.2} />

      {/* Liquid hub */}
      <LiquidHub cx={hubX} cy={hubY} start={1.2} launchAt={10.2} />

      {/* 8 orbiting feature cards (5–13s) */}
      {features.map((f, i) => (
        <OrbitFeature
          key={f.label}
          cx={hubX}
          cy={hubY}
          index={i}
          total={features.length}
          radius={250}
          start={featureStart + i * featureStagger}
          end={featureEnd}
          label={f.label}
          italicize={f.italicize}
        />
      ))}

      {/* Running captions synced to the arc */}
      <Caption start={0.4}  end={2.1}  eyebrow="step 01" text="Three legacy storefronts." />
      <Caption start={2.3}  end={4.9}  eyebrow="step 02" text="Products, customers, orders — every record flows." />
      <Caption start={5.1}  end={10.0} eyebrow="step 03" text="Plus features assemble around the new core." />
      <Caption start={10.4} end={13.0} eyebrow="launch"  text="One platform. Built for scale." />

      <Vignette />
      <FilmGrain />
    </>
  );
}

Object.assign(window, {
  PlusMigrationScene, PALETTE, FONTS,
  SourceTile, DataStream, LiquidHub, OrbitFeature, CornerChrome,
  LaunchBurst, FilmGrain, Vignette, EditorialFrame, SectionTitle, Caption,
  smooth, mix, envelope,
});
