// Scene 2: Know your garage door — anatomy diagram with animated callouts (5-15s)

// Dots only — photo already has labels baked in.
// Coords are normalized (0-1) over the image. Tuned to land on the actual
// hardware visible in the photo, not on the overlaid labels.
const ANATOMY_PARTS = [
  { key: 'springs',       dotX: 0.44, dotY: 0.32 }, // spring rod, mid-upper
  { key: 'motorhead',     dotX: 0.76, dotY: 0.08 }, // LiftMaster unit top-right
  { key: 'hockey_stick',  dotX: 0.48, dotY: 0.34 }, // J-arm down from opener
  { key: 'cable_drum',    dotX: 0.84, dotY: 0.23 }, // drum/cable area upper right
  { key: 'rollers',       dotX: 0.20, dotY: 0.52 }, // left track rollers
  { key: 'hinges',        dotX: 0.52, dotY: 0.54 }, // hinge on mid panel
  { key: 'light_sensor',  dotX: 0.85, dotY: 0.82 }, // photo eye bottom right
];

function Scene2_Anatomy({ start = 5, end = 16 }) {
  return (
    <Sprite start={start} end={end}>
      {({ localTime, progress, duration }) => {
        // Image fills the full 1920x1080 frame (object-fit: cover crops the
        // top/bottom since source is 1400x937 ≈ 1.49 vs 16:9 ≈ 1.78).
        const imgW = 1920;
        const imgH = 1080;
        const imgX = 0;
        const imgY = 0;

        // Source aspect vs display aspect — cover crops Y.
        // Source 1400x937 scaled to width 1920 → H = 1920 * 937/1400 = 1285
        // Vertical crop: (1285 - 1080)/2 = 102.5px off each edge
        // So the visible Y range in source-normalized coords is:
        //   yTopNorm = 102.5 / 1285 ≈ 0.0797
        //   yBotNorm = (102.5 + 1080) / 1285 ≈ 0.9203
        // We keep dot coords relative to the FULL source image and map them
        // onto the displayed frame accounting for the crop.
        const srcAspect = 1400 / 937;
        const dispAspect = imgW / imgH;
        let cropX = 0, cropY = 0, visibleW = 1, visibleH = 1;
        if (srcAspect > dispAspect) {
          // source wider — crops X
          visibleW = dispAspect / srcAspect;
          cropX = (1 - visibleW) / 2;
        } else {
          // source taller — crops Y (this case)
          visibleH = srcAspect / dispAspect;
          cropY = (1 - visibleH) / 2;
        }
        // Map normalized source coords → frame pixels
        const mapX = (nx) => imgX + ((nx - cropX) / visibleW) * imgW;
        const mapY = (ny) => imgY + ((ny - cropY) / visibleH) * imgH;

        // Camera: slow ken-burns
        const kbScale = 1 + progress * 0.06;

        // Headline appears first 0-1.2s
        const headT = clamp(localTime / 0.9, 0, 1);
        const headEased = Easing.easeOutCubic(headT);

        // Fade out whole scene in last 0.6s
        const fadeOut = clamp((duration - localTime) / 0.6, 0, 1);

        return (
          <div style={{
            position: 'absolute', inset: 0,
            background: 'oklch(0.96 0.01 70)',
            opacity: fadeOut,
          }}>
            {/* Anatomy image with ken burns */}
            <div style={{
              position: 'absolute',
              left: imgX, top: imgY, width: imgW, height: imgH,
              transform: `scale(${kbScale})`,
              transformOrigin: '50% 50%',
              filter: 'saturate(0.85) brightness(1.02)',
            }}>
              <img src="assets/anatomy.webp" style={{
                width: '100%', height: '100%', objectFit: 'cover',
                borderRadius: 8,
              }}/>
              {/* Warm overlay to unify */}
              <div style={{
                position: 'absolute', inset: 0,
                background: 'linear-gradient(180deg, oklch(0.95 0.02 70 / 0.25) 0%, oklch(0.92 0.03 60 / 0.35) 100%)',
                borderRadius: 8,
                mixBlendMode: 'multiply',
              }}/>
            </div>

            {/* Animated red dots — the speaker points out each part in turn */}
            {ANATOMY_PARTS.map((p, i) => {
              const appearAt = 1.2 + i * 0.55;
              const t = clamp((localTime - appearAt) / 0.5, 0, 1);
              const eased = Easing.easeOutBack(t);
              if (t <= 0) return null;

              const dotPx = { x: mapX(p.dotX), y: mapY(p.dotY) };

              // Continuous breathing pulse after the dot has landed
              const breathT = Math.max(0, localTime - appearAt - 0.5);
              const ringT = (breathT % 1.4) / 1.4;

              return (
                <React.Fragment key={p.key}>
                  {/* Outer breathing ring */}
                  {breathT > 0 && (
                    <div style={{
                      position: 'absolute',
                      left: dotPx.x - 12, top: dotPx.y - 12,
                      width: 24, height: 24,
                      borderRadius: '50%',
                      border: '2px solid oklch(0.58 0.20 30)',
                      opacity: (1 - ringT) * 0.8,
                      transform: `scale(${1 + ringT * 2.4})`,
                    }}/>
                  )}
                  {/* Entry pulse ring */}
                  <div style={{
                    position: 'absolute',
                    left: dotPx.x - 12, top: dotPx.y - 12,
                    width: 24, height: 24,
                    borderRadius: '50%',
                    border: '2px solid oklch(0.58 0.20 30)',
                    opacity: t < 1 ? 1 - t : 0,
                    transform: `scale(${1 + t * 3})`,
                  }}/>
                  {/* Solid red dot */}
                  <div style={{
                    position: 'absolute',
                    left: dotPx.x - 10, top: dotPx.y - 10,
                    width: 20, height: 20,
                    borderRadius: '50%',
                    background: 'oklch(0.58 0.22 28)',
                    transform: `scale(${eased})`,
                    boxShadow: '0 0 0 3px oklch(0.98 0.01 80), 0 4px 14px oklch(0.35 0.18 28 / 0.55)',
                  }}/>
                </React.Fragment>
              );
            })}

            {/* Headline — top left */}
            <div style={{
              position: 'absolute',
              left: 80, top: 72,
              opacity: headEased,
              transform: `translateY(${(1 - headEased) * 20}px)`,
            }}>
              <div style={{
                fontFamily: "'Work Sans', system-ui, sans-serif",
                fontSize: 18, fontWeight: 600,
                color: 'oklch(0.48 0.16 35)',
                letterSpacing: '0.20em',
                textTransform: 'uppercase',
                marginBottom: 14,
              }}>
                Step 01 · Meet your door
              </div>
              <div style={{
                fontFamily: "'Fraunces', 'Work Sans', serif",
                fontSize: 66, fontWeight: 500,
                color: 'oklch(0.22 0.03 50)',
                lineHeight: 1.0,
                letterSpacing: '-0.02em',
                maxWidth: 640,
              }}>
                24 parts.<br/>
                <em style={{ fontStyle: 'italic' }}>One</em> walk‑around.
              </div>
            </div>

            {/* Counter — bottom right */}
            <AnatomyCounter localTime={localTime} />

            {/* GDS wordmark — bottom left, subtle */}
            <div style={{
              position: 'absolute',
              left: 80, bottom: 72,
              display: 'flex', alignItems: 'center', gap: 10,
              opacity: headEased * 0.85,
            }}>
              <img src="assets/gds-icon.png" alt=""
                style={{ width: 28, height: 28, objectFit: 'contain' }}/>
              <div style={{
                fontFamily: "'Work Sans', sans-serif",
                fontSize: 14, fontWeight: 500,
                color: 'oklch(0.45 0.03 50)',
                letterSpacing: '0.02em',
              }}>
                Garage Door <span style={{ color: 'oklch(0.52 0.12 230)', fontWeight: 600 }}>Science</span>
              </div>
            </div>
          </div>
        );
      }}
    </Sprite>
  );
}

function AnatomyCounter({ localTime }) {
  // Count from 0 -> 24 between 1.5s and 7s
  const t = clamp((localTime - 1.5) / 5.5, 0, 1);
  const count = Math.floor(Easing.easeOutCubic(t) * 24);
  const appear = clamp((localTime - 1.2) / 0.5, 0, 1);
  return (
    <div style={{
      position: 'absolute',
      right: 80, bottom: 72,
      textAlign: 'right',
      opacity: appear,
      transform: `translateY(${(1 - appear) * 14}px)`,
    }}>
      <div style={{
        fontFamily: "'JetBrains Mono', ui-monospace, monospace",
        fontSize: 15, fontWeight: 500,
        color: 'oklch(0.45 0.03 50)',
        letterSpacing: '0.14em',
        textTransform: 'uppercase',
        marginBottom: 8,
      }}>
        Checklist size
      </div>
      <div style={{
        fontFamily: "'Fraunces', serif",
        fontSize: 140, fontWeight: 500,
        color: 'oklch(0.22 0.03 50)',
        lineHeight: 0.9,
        fontVariantNumeric: 'tabular-nums',
      }}>
        {String(count).padStart(2, '0')}
        <span style={{ color: 'oklch(0.58 0.17 35)' }}>.</span>
      </div>
    </div>
  );
}

window.Scene2_Anatomy = Scene2_Anatomy;
