/* Alpine Hero — scène animée avec parallax + easter egg militaire suisse */
const { useEffect, useRef, useState, useMemo, useCallback } = React;

/* ═══════════════════ MOUNTAINS — design poussé ═══════════════════ */
const MountainsFar = ({ fill = 'var(--mt-far)' }) => (
  <svg viewBox="0 0 1920 400" preserveAspectRatio="none">
    <defs>
      <linearGradient id="far-grad" x1="0" y1="0" x2="0" y2="1">
        <stop offset="0%"   stopColor={fill} stopOpacity="0.7"/>
        <stop offset="100%" stopColor={fill} stopOpacity="1"/>
      </linearGradient>
    </defs>
    <path d="M0,400 L0,260 L120,210 L260,250 L380,180 L520,230 L680,170
             L820,220 L980,150 L1140,210 L1300,140 L1460,200 L1620,160
             L1780,220 L1920,180 L1920,400 Z" fill="url(#far-grad)"/>
    {/* fines petites taches blanches sur les sommets très lointains */}
    <g fill="rgba(255,255,255,.35)">
      <ellipse cx="380" cy="184" rx="14" ry="4"/>
      <ellipse cx="680" cy="174" rx="16" ry="4"/>
      <ellipse cx="980" cy="154" rx="20" ry="5"/>
      <ellipse cx="1300" cy="144" rx="18" ry="4"/>
      <ellipse cx="1620" cy="164" rx="14" ry="4"/>
    </g>
  </svg>
);

const MountainsMid = ({ fill = 'var(--mt-mid)', snow = '#fefdfa' }) => (
  <svg viewBox="0 0 1920 500" preserveAspectRatio="none">
    <defs>
      <linearGradient id="mid-grad" x1="0" y1="0" x2="0" y2="1">
        <stop offset="0%"   stopColor={fill} stopOpacity="1"/>
        <stop offset="55%"  stopColor={fill} stopOpacity="0.92"/>
        <stop offset="100%" stopColor={fill} stopOpacity="0.78"/>
      </linearGradient>
      <linearGradient id="mid-shade" x1="0" y1="0" x2="1" y2="0">
        <stop offset="0%"   stopColor="rgba(0,0,0,.18)"/>
        <stop offset="50%"  stopColor="rgba(0,0,0,0)"/>
        <stop offset="100%" stopColor="rgba(0,0,0,.12)"/>
      </linearGradient>
    </defs>
    {/* main rock mass */}
    <path d="M0,500 L0,360 L160,300 L320,340 L460,260 L580,310 L740,180 L820,260
             L960,220 L1100,80 L1240,250 L1380,200 L1520,290 L1680,210 L1820,280
             L1920,250 L1920,500 Z" fill="url(#mid-grad)"/>

    {/* RIDGE LINES — falettes verticales subtiles pour donner du relief */}
    <g stroke="rgba(0,0,0,.13)" strokeWidth="1" fill="none">
      <path d="M1100,80 L1130,260 L1170,500"/>
      <path d="M1100,80 L1075,200 L1040,500"/>
      <path d="M740,180 L780,500"/>
      <path d="M740,180 L710,260 L680,500"/>
      <path d="M1380,200 L1410,500"/>
      <path d="M1680,210 L1700,500"/>
    </g>

    {/* LIGHT SIDE — ouest de chaque pic */}
    <g fill="rgba(255,255,255,.08)">
      <path d="M1100,80 L1075,200 L1040,500 L990,500 L1000,300 L1075,140 Z"/>
      <path d="M740,180 L710,260 L680,500 L640,500 L660,330 L720,210 Z"/>
      <path d="M1380,200 L1360,500 L1330,500 L1355,290 Z"/>
    </g>

    {/* SHADOW SIDE — est de chaque pic */}
    <g fill="rgba(0,0,0,.14)">
      <path d="M1100,80 L1130,260 L1170,500 L1240,500 L1240,250 Z"/>
      <path d="M740,180 L780,500 L820,500 L820,260 Z"/>
      <path d="M1380,200 L1410,500 L1450,500 L1430,310 Z"/>
    </g>

    {/* SNOW CAPS — généreuses avec ombres bleutées */}
    {/* Matterhorn */}
    <path d="M1058,140 L1080,110 L1100,80 L1120,108 L1145,160 L1130,165 L1115,148 L1100,158 L1085,142 L1075,158 Z" fill={snow}/>
    <path d="M1100,80 L1122,125 L1100,138 L1085,122 Z" fill="rgba(255,255,255,.6)"/>
    <path d="M1058,140 L1075,158 L1085,142 L1100,158 L1115,148 L1130,165 L1145,160 L1140,170 L1102,168 L1062,150 Z" fill="rgba(170,200,220,.45)"/>
    {/* Peak A */}
    <path d="M712,222 L740,180 L772,225 L755,234 L740,218 L728,232 Z" fill={snow}/>
    <path d="M740,180 L757,212 L740,220 L727,205 Z" fill="rgba(255,255,255,.5)"/>
    <path d="M712,222 L728,232 L740,218 L755,234 L772,225 L770,232 L740,228 L716,228 Z" fill="rgba(170,200,220,.4)"/>
    {/* Peak B */}
    <path d="M1358,228 L1380,200 L1405,232 L1392,238 L1380,222 L1370,236 Z" fill={snow}/>
    <path d="M1358,228 L1370,236 L1380,222 L1392,238 L1405,232 L1402,238 L1380,234 L1362,235 Z" fill="rgba(170,200,220,.4)"/>
    {/* Peak C */}
    <path d="M1660,238 L1680,210 L1702,240 L1690,246 L1680,232 L1670,244 Z" fill={snow}/>

    {/* CRACKS — petites failles sombres */}
    <g stroke="rgba(0,0,0,.18)" strokeWidth="0.8" fill="none">
      <path d="M1100,140 Q1095,180 1090,210 T1080,290"/>
      <path d="M1110,150 Q1115,200 1112,260"/>
      <path d="M740,210 Q738,260 742,310"/>
    </g>

    {/* OVERLAY — fine bande d'ombre globale gauche/droite */}
    <rect x="0" y="0" width="1920" height="500" fill="url(#mid-shade)" opacity="0.6"/>
  </svg>
);

const MountainsNear = ({ fill = 'var(--mt-near)' }) => (
  <svg viewBox="0 0 1920 300" preserveAspectRatio="none">
    <defs>
      <linearGradient id="near-grad" x1="0" y1="0" x2="0" y2="1">
        <stop offset="0%"   stopColor={fill} stopOpacity="0.95"/>
        <stop offset="100%" stopColor={fill} stopOpacity="1"/>
      </linearGradient>
    </defs>
    <path d="M0,300 L0,200 L120,160 L260,220 L400,150 L540,210 L660,140 L800,200
             L940,130 L1080,200 L1220,160 L1360,210 L1520,150 L1680,210 L1820,170
             L1920,210 L1920,300 Z" fill="url(#near-grad)"/>

    {/* base sombre */}
    <path d="M0,300 L0,255 L1920,255 L1920,300 Z" fill="rgba(0,0,0,.22)"/>

    {/* Forêt de sapins — silhouettes triangulaires variées */}
    {Array.from({length: 38}).map((_, i) => {
      const x = 30 + i * 50 + (i % 3) * 12;
      const baseY = 252 + (i % 4) * 3;
      const h = 12 + (i % 5) * 3;
      const w = 5 + (i % 3) * 1.5;
      return (
        <g key={`tree-${i}`}>
          <path
            d={`M${x},${baseY} L${x - w},${baseY} L${x},${baseY - h} L${x + w},${baseY} Z`}
            fill="rgba(0,0,0,.32)"
          />
          {/* tiny snow tip on some */}
          {i % 6 === 0 && (
            <path
              d={`M${x},${baseY - h} L${x - 1.5},${baseY - h + 3} L${x + 1.5},${baseY - h + 3} Z`}
              fill="rgba(255,255,255,.5)"
            />
          )}
        </g>
      );
    })}

    {/* Petit chalet en bas à droite */}
    <g transform="translate(1680, 244)">
      <path d="M0,0 L20,0 L20,-10 L10,-18 L0,-10 Z" fill="#5a3a28"/>
      <path d="M10,-18 L20,-10 L18,-10 L10,-16 Z" fill="#3a2418"/>
      <rect x="8" y="-7" width="4" height="6" fill="#f5c66b"/>
      <line x1="0" y1="-10" x2="20" y2="-10" stroke="rgba(0,0,0,.4)" strokeWidth="0.5"/>
    </g>

    {/* Téléphérique — câble + petite cabine entre deux pics */}
    <g>
      <line x1="940" y1="130" x2="1220" y2="160" stroke="rgba(40,40,50,.5)" strokeWidth="0.8"/>
      <g transform="translate(1080, 145)">
        <rect x="-5" y="-2" width="10" height="6" fill="var(--accent)" stroke="rgba(0,0,0,.5)" strokeWidth="0.4"/>
        <line x1="-5" y1="-2" x2="-7" y2="-6" stroke="rgba(40,40,50,.7)" strokeWidth="0.6"/>
        <line x1="5"  y1="-2" x2="7"  y2="-6" stroke="rgba(40,40,50,.7)" strokeWidth="0.6"/>
      </g>
    </g>
  </svg>
);

/* ═══════════════════ BOAT ═══════════════════ */
const Boat = ({ sailColor = '#fbfaf7', hullColor = '#3a3530', accentColor = 'var(--accent)' }) => (
  <svg viewBox="0 0 46 38">
    <path d="M23,4 L23,24 L40,24 Z" fill={sailColor} stroke="#c8bfa9" strokeWidth=".5"/>
    <path d="M23,8 L23,24 L13,24 Z" fill={sailColor} stroke="#c8bfa9" strokeWidth=".5" opacity=".95"/>
    <rect x="33" y="20" width="6" height="2" fill={accentColor} opacity=".7"/>
    <line x1="23" y1="4" x2="23" y2="28" stroke="#5a4a3a" strokeWidth="1"/>
    <path d="M6,28 L40,28 L34,34 L12,34 Z" fill={hullColor}/>
    <path d="M6,28 L40,28" stroke="#1f1a14" strokeWidth=".6"/>
  </svg>
);

const Bird = () => (
  <svg viewBox="0 0 22 10">
    <path d="M1,8 Q5,1 11,5 Q17,1 21,8" fill="none" stroke="#3a3a48" strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round"/>
  </svg>
);

/* ═══════════════════ CLOUD SHAPES (SVG paths lisses) ═══════════════════ */
const cloudBody = (op) => `rgba(252,253,255,${op})`;
const cloudHi   = (op) => `rgba(255,255,255,${Math.min(1, op + 0.12)})`;
const cloudShade = (op) => `rgba(90,110,140,${op * 0.10})`;

const CloudShapes = [
  // 0 — Cumulus 4 bumps, ratio 2.2:1
  ({ op = 0.9 }) => (
    <svg viewBox="0 0 220 100" preserveAspectRatio="xMidYMid meet">
      <ellipse cx="110" cy="92" rx="98" ry="6" fill={cloudShade(op)}/>
      <path d="M 25 80
               Q 0 80, 5 60
               Q -5 32, 28 30
               Q 32 6, 62 18
               Q 82 -2, 105 20
               Q 125 0, 148 22
               Q 175 12, 178 40
               Q 208 42, 198 64
               Q 218 82, 178 80
               L 25 80 Z" fill={cloudBody(op)}/>
      <ellipse cx="62"  cy="20" rx="14" ry="4.5" fill={cloudHi(op)}/>
      <ellipse cx="105" cy="12" rx="20" ry="5"  fill={cloudHi(op)}/>
      <ellipse cx="148" cy="20" rx="13" ry="4"  fill={cloudHi(op)}/>
    </svg>
  ),
  // 1 — Stratocumulus long, ratio 5:1
  ({ op = 0.85 }) => (
    <svg viewBox="0 0 300 60" preserveAspectRatio="xMidYMid meet">
      <ellipse cx="150" cy="55" rx="138" ry="3" fill={cloudShade(op)}/>
      <path d="M 20 48
               Q 0 48, 4 36
               Q 4 22, 28 22
               Q 32 10, 58 16
               Q 70 4, 95 14
               Q 110 2, 138 12
               Q 158 0, 182 12
               Q 208 4, 228 16
               Q 252 10, 270 20
               Q 290 22, 285 38
               Q 298 50, 260 48
               L 20 48 Z" fill={cloudBody(op)}/>
      <ellipse cx="60"  cy="12" rx="14" ry="3" fill={cloudHi(op)}/>
      <ellipse cx="135" cy="10" rx="18" ry="3.5" fill={cloudHi(op)}/>
      <ellipse cx="210" cy="12" rx="14" ry="3" fill={cloudHi(op)}/>
    </svg>
  ),
  // 2 — Cumulus haut compact, ratio 1.4:1
  ({ op = 0.9 }) => (
    <svg viewBox="0 0 150 105" preserveAspectRatio="xMidYMid meet">
      <ellipse cx="75" cy="98" rx="68" ry="5" fill={cloudShade(op)}/>
      <path d="M 22 84
               Q 0 84, 6 60
               Q -8 28, 28 25
               Q 30 -2, 70 12
               Q 100 -8, 118 24
               Q 145 22, 138 56
               Q 158 70, 130 80
               Q 142 92, 110 88
               L 22 84 Z" fill={cloudBody(op)}/>
      <ellipse cx="55"  cy="18" rx="12" ry="4" fill={cloudHi(op)}/>
      <ellipse cx="95"  cy="14" rx="16" ry="5" fill={cloudHi(op)}/>
      <ellipse cx="120" cy="26" rx="10" ry="3.5" fill={cloudHi(op)}/>
    </svg>
  ),
  // 3 — Petit puff, ratio 1.6:1
  ({ op = 0.8 }) => (
    <svg viewBox="0 0 110 70" preserveAspectRatio="xMidYMid meet">
      <ellipse cx="55" cy="64" rx="48" ry="4" fill={cloudShade(op)}/>
      <path d="M 18 56
               Q 0 56, 4 40
               Q -4 22, 22 22
               Q 26 4, 50 14
               Q 68 -2, 82 20
               Q 102 20, 96 42
               Q 112 56, 80 56
               L 18 56 Z" fill={cloudBody(op)}/>
      <ellipse cx="50" cy="12" rx="12" ry="3.5" fill={cloudHi(op)}/>
      <ellipse cx="78" cy="18" rx="9"  ry="3"   fill={cloudHi(op)}/>
    </svg>
  ),
  // 4 — Grand cumulus 5 lobes, ratio 2.3:1
  ({ op = 0.95 }) => (
    <svg viewBox="0 0 260 115" preserveAspectRatio="xMidYMid meet">
      <ellipse cx="130" cy="108" rx="118" ry="6" fill={cloudShade(op)}/>
      <path d="M 30 92
               Q 0 92, 8 68
               Q -10 32, 30 28
               Q 35 0, 70 18
               Q 85 -10, 115 16
               Q 138 -12, 162 18
               Q 188 -6, 205 30
               Q 240 26, 232 62
               Q 258 70, 240 88
               Q 252 100, 215 96
               Q 220 110, 188 100
               L 30 92 Z" fill={cloudBody(op)}/>
      <ellipse cx="62"  cy="22" rx="14" ry="4.5" fill={cloudHi(op)}/>
      <ellipse cx="110" cy="10" rx="20" ry="5"   fill={cloudHi(op)}/>
      <ellipse cx="158" cy="12" rx="18" ry="4.5" fill={cloudHi(op)}/>
      <ellipse cx="200" cy="26" rx="12" ry="4"   fill={cloudHi(op)}/>
    </svg>
  ),
  // 5 — Wispy fin et étiré, ratio 6:1
  ({ op = 0.7 }) => (
    <svg viewBox="0 0 280 50" preserveAspectRatio="xMidYMid meet">
      <ellipse cx="140" cy="46" rx="128" ry="2.5" fill={cloudShade(op)}/>
      <path d="M 18 40
               Q 0 40, 5 30
               Q 6 18, 28 18
               Q 35 8, 60 12
               Q 75 2, 100 10
               Q 130 0, 158 10
               Q 188 2, 210 12
               Q 240 6, 258 18
               Q 280 22, 270 36
               Q 280 44, 248 42
               L 18 40 Z" fill={cloudBody(op)}/>
      <ellipse cx="65"  cy="10" rx="14" ry="2.5" fill={cloudHi(op)}/>
      <ellipse cx="160" cy="8"  rx="20" ry="3"   fill={cloudHi(op)}/>
      <ellipse cx="225" cy="12" rx="14" ry="2.5" fill={cloudHi(op)}/>
    </svg>
  ),
];

/* ═══════════════════ BAT ═══════════════════ */
const Bat = () => (
  <svg viewBox="0 0 28 12" preserveAspectRatio="xMidYMid meet">
    <path d="M14,5
             L11,3 L8,6 L5,2 L2,8 L6,8 L10,7 L13,9
             L14,10
             L15,9 L18,7 L22,8 L26,8 L23,2 L20,6 L17,3 Z" fill="#1a1a22"/>
    <path d="M14,4.5 L13.4,3 L13.7,4.8 Z M14,4.5 L14.6,3 L14.3,4.8 Z" fill="#1a1a22"/>
  </svg>
);

/* ═══════════════════ Random generators ═══════════════════ */
// Seeded random so the scene is stable per session (no flicker on rerender)
const mulberry32 = (seed) => () => {
  let t = (seed += 0x6D2B79F5);
  t = Math.imul(t ^ (t >>> 15), t | 1);
  t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
  return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
};

const generateClouds = (count, seed = 42) => {
  const rand = mulberry32(seed);
  const shapeCount = 6;
  // Use a shuffled deck so we don't repeat the same shape twice in a row
  const deck = Array.from({length: shapeCount}, (_, i) => i);
  for (let i = deck.length - 1; i > 0; i--) {
    const j = Math.floor(rand() * (i + 1));
    [deck[i], deck[j]] = [deck[j], deck[i]];
  }
  return Array.from({length: count}).map((_, i) => {
    const top = 4 + rand() * 36;                      // 4-40%
    const baseW = 110 + rand() * 220;                 // 110-330
    const shape = deck[i % shapeCount];
    return {
      top, w: baseW, shape,
      opacity: 0.55 + rand() * 0.4,
      duration: 60 + rand() * 70,
      delay: -rand() * 130,
    };
  });
};

const generateBoats = (count, seed = 7) => {
  const rand = mulberry32(seed);
  // distribute boats across lake depth (top of lake = far, bottom = near)
  // lake is 30% of viewport; bottom values are % of .lake's height
  const slots = [
    { bottom: 78, scale: 0.32, z: 6 },  // far
    { bottom: 62, scale: 0.45, z: 6 },
    { bottom: 44, scale: 0.62, z: 7 },
    { bottom: 28, scale: 0.82, z: 7 },
    { bottom: 12, scale: 1.05, z: 8 },  // near
    { bottom:  4, scale: 1.18, z: 8 },  // foreground
  ];
  const palette = [
    { sail:'#fbfaf7', accent:'var(--accent)' },
    { sail:'#f6dcb0', accent:'var(--alpine)' },
    { sail:'#fbfaf7', accent:'var(--moss)' },
    { sail:'#ead8b8', accent:'var(--accent)' },
    { sail:'#f8e8d2', accent:'var(--alpine)' },
  ];
  return slots.slice(0, count).map((s, i) => {
    const goLeft = rand() > 0.5;
    // duration scales inversely with size — bigger/closer boats appear to move faster across the screen
    const dur = (140 - s.scale * 60) + rand() * 30;
    return {
      ...s,
      anim: goLeft ? 'sail-left' : 'sail-right',
      flip: goLeft ? -1 : 1,
      dur,
      delay: -rand() * dur,
      bob: -rand() * 3,
      color: palette[i % palette.length],
    };
  });
};

/* ═══════════════════ Bunker ═══════════════════ */
const Bunker = ({ x, y, tilt, aim, open, firing, label, bunkerRef }) => (
  <div
    ref={bunkerRef}
    className="bunker"
    style={{ left:`${x}%`, top:`${y}%`, '--tilt': `${tilt}deg`, '--aim': `${aim}deg` }}
  >
    <div className="concrete"/>
    <div className="interior">
      <div className="soldier" style={{ bottom: open ? 2 : -14 }}>
        <div className="helmet"/>
        <div className="face"/>
        <div className="body"/>
        <div className={`rifle ${firing?'firing':''}`}/>
      </div>
    </div>
    <div className="doors">
      <div className="door door-l" style={{ transform: open ? 'translateX(-92%)' : 'translateX(0)' }}/>
      <div className="door door-r" style={{ transform: open ? 'translateX(92%)'  : 'translateX(0)' }}/>
    </div>
    <div className={`flash ${firing?'firing':''}`}/>
    <div className="bunker-tip">{label}</div>
  </div>
);

/* ═══════════════════ Bird & bunker generators ═══════════════════ */
const generateBirds = (count, seed) => {
  const rand = mulberry32(seed);
  return Array.from({length: count}).map((_, i) => {
    const direction = rand() < 0.45 ? -1 : 1;   // ~45% des oiseaux viennent de la droite
    return {
      id: `b-${seed}-${i}-${Math.floor(rand() * 1e9)}`,
      top: 6 + rand() * 30,
      duration: 24 + rand() * 22,
      delay: -rand() * 40,
      flapSpeed: 0.34 + rand() * 0.22,
      flapDelay: rand() * 0.5,
      amp1: -8  - rand() * 28,
      amp2:  8  + rand() * 24,
      amp3: -8  - rand() * 20,
      scale: 0.7 + rand() * 0.55,
      direction,
    };
  });
};

const generateBunkers = (count, seed) => {
  // x range 18-82% with spacing; y range 64-86% (always inside the mountain mass, lower half)
  const xs = [];
  const rand = mulberry32(seed);
  for (let i = 0; i < count; i++) {
    let x;
    for (let attempt = 0; attempt < 12; attempt++) {
      x = 18 + rand() * 64;
      if (xs.every(prev => Math.abs(prev - x) > 24)) break;
    }
    xs.push(x);
  }
  return xs.map((x, i) => {
    const r2 = mulberry32(seed + i * 31);
    return {
      x,
      y: 66 + r2() * 18,                   // 66-84% — always in the lower mountain
      tilt: -6 + r2() * 12,
      aim: -16 + r2() * 12,
    };
  });
};

/* ═══════════════════ Bird-hit "oh no" sound ═══════════════════ */
let ohNoAudio = null;
const playOhNo = () => {
  try {
    if (!ohNoAudio) {
      ohNoAudio = new Audio('assets/beta/ohno.mp3');
      ohNoAudio.volume = 0.7;
      ohNoAudio.preload = 'auto';
    }
    // restart from beginning even if still playing
    const clone = ohNoAudio.cloneNode(true);
    clone.volume = 0.7;
    clone.play().catch(() => {});
  } catch(e) {}
};

/* ═══════════════════ Gun shot sound (Web Audio) ═══════════════════ */
let audioCtx = null;
const playGunShot = () => {
  try {
    if (!audioCtx) audioCtx = new (window.AudioContext || window.webkitAudioContext)();
    if (audioCtx.state === 'suspended') audioCtx.resume();
    const t0 = audioCtx.currentTime;

    // Noise burst — the "bang"
    const bufSize = Math.floor(audioCtx.sampleRate * 0.18);
    const buffer = audioCtx.createBuffer(1, bufSize, audioCtx.sampleRate);
    const data = buffer.getChannelData(0);
    for (let i = 0; i < bufSize; i++) {
      data[i] = (Math.random() * 2 - 1) * Math.pow(1 - i / bufSize, 2.2);
    }
    const noise = audioCtx.createBufferSource();
    noise.buffer = buffer;
    const noiseGain = audioCtx.createGain();
    noiseGain.gain.setValueAtTime(0.0, t0);
    noiseGain.gain.linearRampToValueAtTime(0.5, t0 + 0.004);
    noiseGain.gain.exponentialRampToValueAtTime(0.001, t0 + 0.18);
    const filter = audioCtx.createBiquadFilter();
    filter.type = 'lowpass';
    filter.frequency.value = 2000;
    noise.connect(filter).connect(noiseGain).connect(audioCtx.destination);
    noise.start(t0);
    noise.stop(t0 + 0.22);

    // Sub thump
    const osc = audioCtx.createOscillator();
    osc.type = 'sine';
    osc.frequency.setValueAtTime(160, t0);
    osc.frequency.exponentialRampToValueAtTime(38, t0 + 0.16);
    const oscGain = audioCtx.createGain();
    oscGain.gain.setValueAtTime(0.4, t0);
    oscGain.gain.exponentialRampToValueAtTime(0.001, t0 + 0.18);
    osc.connect(oscGain).connect(audioCtx.destination);
    osc.start(t0);
    osc.stop(t0 + 0.2);
  } catch (e) {}
};

/* ═══════════════════ MAIN HERO ═══════════════════ */
const AlpineHero = ({ onGenerate, onLogin, onAffiliate, showBats = false }) => {
  const heroRef = useRef(null);
  const farRef = useRef(null);
  const midRef = useRef(null);
  const nearRef = useRef(null);
  const sunRef = useRef(null);
  const textRef = useRef(null);
  const lakeRef = useRef(null);

  // viewport-aware counts (computed once)
  const counts = useMemo(() => {
    if (typeof window === 'undefined') return { clouds: 5, boats: 5 };
    const w = window.innerWidth;
    if (w < 560) return { clouds: 2, boats: 2 };
    if (w < 900) return { clouds: 3, boats: 3 };
    return { clouds: 6, boats: 5 };
  }, []);

  const clouds = useMemo(() => generateClouds(counts.clouds, Date.now() & 0xffff), [counts.clouds]);
  const boats  = useMemo(() => generateBoats(counts.boats, (Date.now() >> 4) & 0xffff), [counts.boats]);
  const initialBirds   = useMemo(() => generateBirds(6, (Date.now() >> 8) & 0xffff), []);
  const bunkerPositions = useMemo(() => generateBunkers(2, (Date.now() >> 12) & 0xffff), []);

  // Birds live in state so they can be removed when shot and respawned
  const [birds, setBirds] = useState(initialBirds);
  const respawnSeedRef = useRef(0);

  // Bunker DOM refs — rifles will track the mouse via direct style updates
  const bunkerRefs = useRef([]);
  const crosshairRef = useRef(null);

  // ───── Parallax scroll ─────
  useEffect(() => {
    let raf;
    const onScroll = () => {
      cancelAnimationFrame(raf);
      raf = requestAnimationFrame(() => {
        const y = window.scrollY;
        const max = window.innerHeight;
        const t = Math.min(1, y / max);
        if (sunRef.current)  sunRef.current.style.transform  = `translateY(${y * 0.12}px)`;
        if (farRef.current)  farRef.current.style.transform  = `translateY(${y * 0.04}px)`;
        if (midRef.current)  midRef.current.style.transform  = `translateY(${y * 0.07}px)`;
        if (nearRef.current) nearRef.current.style.transform = `translateY(${y * 0.11}px)`;
        if (lakeRef.current) lakeRef.current.style.transform = `translateY(${y * 0.16}px)`;
        if (textRef.current) {
          textRef.current.style.transform = `translateY(${y * 0.30}px)`;
          textRef.current.style.opacity = `${Math.max(0, 1 - t * 1.5)}`;
        }
      });
    };
    window.addEventListener('scroll', onScroll, { passive: true });
    return () => { window.removeEventListener('scroll', onScroll); cancelAnimationFrame(raf); };
  }, []);

  // ───── Easter egg state ─────
  const [proximate, setProximate] = useState(false);
  const [bunkersOpen, setBunkersOpen] = useState(false);
  const [firing, setFiring] = useState({ a: false, b: false });
  const [downBirdIds, setDownBirdIds] = useState(() => new Set());  // birds in falling animation
  const [score, setScore] = useState(0);

  // Detect proximity to any flying bird (or bat), AND make rifles track the mouse, AND move crosshair
  const checkProximity = useCallback((e) => {
    if (!heroRef.current) return;
    const mx = e.clientX, my = e.clientY;

    // Move crosshair
    if (crosshairRef.current) {
      crosshairRef.current.style.left = `${mx}px`;
      crosshairRef.current.style.top  = `${my}px`;
    }

    // Proximity check
    const targets = heroRef.current.querySelectorAll('.bird:not(.falling), .bat');
    const radius = 180;
    let near = false;
    for (const t of targets) {
      const r = t.getBoundingClientRect();
      if (r.width === 0 || r.height === 0) continue;
      const cs = getComputedStyle(t);
      if (cs.display === 'none' || cs.visibility === 'hidden') continue;
      const dx = mx - (r.left + r.width/2);
      const dy = my - (r.top + r.height/2);
      if (dx*dx + dy*dy < radius * radius) { near = true; break; }
    }
    setProximate(prev => prev === near ? prev : near);

    // Update rifle aim for each bunker — angle from bunker center toward mouse
    bunkerRefs.current.forEach((bk) => {
      if (!bk) return;
      const r = bk.getBoundingClientRect();
      const bx = r.left + r.width/2;
      const by = r.top  + r.height/2;
      // Tilt of the whole bunker is applied as rotate() — we need to subtract it
      const tiltDeg = parseFloat(bk.style.getPropertyValue('--tilt') || '0');
      // Angle in screen space, in degrees, where 0 = pointing right
      const screenAngle = Math.atan2(my - by, mx - bx) * 180 / Math.PI;
      // Local rifle angle = screen angle minus bunker tilt
      let aim = screenAngle - tiltDeg;
      // Clamp to plausible range (don't have soldiers shooting backwards)
      if (aim > 30) aim = 30;
      if (aim < -90) aim = -90;
      bk.style.setProperty('--aim', `${aim}deg`);
    });
  }, []);

  const onLeaveHero = useCallback(() => setProximate(false), []);

  useEffect(() => {
    if (!proximate) {
      const t = setTimeout(() => setBunkersOpen(false), 600);
      return () => clearTimeout(t);
    }
    // Open near-instantly when player approaches a bird
    setBunkersOpen(true);
  }, [proximate]);

  // Soldiers fire occasionally while bunkers open — visual only, no sound (sound = player feedback)
  useEffect(() => {
    if (!bunkersOpen) return;
    let alive = true;
    const tick = () => {
      if (!alive) return;
      const which = Math.random() < 0.5 ? 'a' : 'b';
      setFiring(f => ({ ...f, [which]: true }));
      setTimeout(() => alive && setFiring(f => ({ ...f, [which]: false })), 220);
    };
    const id = setInterval(tick, 2200 + Math.random() * 1800);
    return () => { alive = false; clearInterval(id); };
  }, [bunkersOpen]);

  // Click anywhere in the hero while aiming → shoot the closest live bird within range
  const onHeroClick = useCallback((e) => {
    if (!heroRef.current) return;
    const mx = e.clientX, my = e.clientY;
    const targets = heroRef.current.querySelectorAll('.bird:not(.falling)');
    let bestDist = 200 * 200;
    let bestId = null;
    targets.forEach(t => {
      const r = t.getBoundingClientRect();
      const cs = getComputedStyle(t);
      if (cs.display === 'none' || cs.visibility === 'hidden') return;
      const cx = r.left + r.width/2;
      const cy = r.top  + r.height/2;
      const d = (mx - cx) ** 2 + (my - cy) ** 2;
      if (d < bestDist) {
        bestDist = d;
        bestId = t.dataset.birdId;
      }
    });
    if (bestId) shootBird(bestId);
  }, []);

  // Player shoots a bird → fall animation → after 2.7s remove + respawn fresh bird with new trajectory
  const shootBird = useCallback((id) => {
    // Pin the bird's current screen position BEFORE the animation switches to .falling,
    // so we actually see it fall from where it was — not teleport back to left:-10%.
    const el = heroRef.current?.querySelector(`[data-bird-id="${id}"]`);
    if (el && heroRef.current) {
      const heroRect = heroRef.current.getBoundingClientRect();
      const r = el.getBoundingClientRect();
      // Pin in pixel coords so the flying %-based `left` keyframe no longer governs
      el.style.left = (r.left - heroRect.left) + 'px';
      el.style.top  = (r.top  - heroRect.top)  + 'px';
    }
    setDownBirdIds(prev => {
      if (prev.has(id)) return prev;
      const next = new Set(prev);
      next.add(id);
      return next;
    });
    playGunShot();
    // "Oh no!" reaction from the hit bird — short delay so it lands after the shot
    setTimeout(playOhNo, 120);
    setScore(s => s + 1);

    // After fall animation, remove the dead bird and spawn a fresh one
    setTimeout(() => {
      setBirds(prev => {
        const seed = (Date.now() ^ (++respawnSeedRef.current)) & 0xffff;
        const [newBird] = generateBirds(1, seed);
        return prev.filter(b => b.id !== id).concat(newBird);
      });
      setDownBirdIds(prev => {
        if (!prev.has(id)) return prev;
        const next = new Set(prev);
        next.delete(id);
        return next;
      });
    }, 2700);
  }, []);

  // contextual badge message based on score
  const scoreMessage = useMemo(() => {
    if (score === 0) return null;
    if (score === 1) return <>👀 Premier oiseau touché.<br/>Vraiment&nbsp;? On vous regarde.</>;
    if (score === 2) return <>🇨🇭 La défense aérienne approuve.</>;
    if (score < 5)  return <>L'armée fédérale enregistre vos performances.</>;
    if (score < 8)  return <>Permis de chasse virtuel délivré.<br/>(validé par personne)</>;
    if (score < 12) return <>Les oiseaux suisses se mettent en grève.</>;
    return <>OK ça suffit, on n'a plus d'oiseaux.</>;
  }, [score]);

  const bunkerLabels = [
    "🇨🇭 Neutralité armée. Mais surveillance active.",
    "Bunker fédéral n°428 — service en cours.",
  ];

  return (
    <section
      className={`hero ${proximate ? 'aiming' : ''}`}
      ref={heroRef}
      data-screen-label="01 Hero alpin"
      onMouseMove={checkProximity}
      onMouseLeave={onLeaveHero}
      onClick={proximate ? onHeroClick : undefined}
    >
      {/* stars (nuit) */}
      <div className="stars" aria-hidden="true"/>

      {/* sun / moon */}
      <div className="sun" ref={sunRef}/>

      {/* clouds — vraies formes SVG */}
      {clouds.map((c, i) => {
        const Shape = CloudShapes[c.shape] || CloudShapes[0];
        return (
          <div
            key={`cloud-${i}`}
            className="cloud"
            style={{
              top: `${c.top}%`,
              width: c.w,
              '--dur': `${c.duration}s`,
              '--delay': `${c.delay}s`,
            }}
          >
            <Shape op={c.opacity}/>
          </div>
        );
      })}

      {/* bats — visible en crépuscule/nuit */}
      <div className="bats" aria-hidden="true" style={{'--bats-opacity': showBats ? 1 : 0}}>
        <div className="bat" style={{'--bat-top':'14%', '--bat-dur':'32s', '--bat-delay':'-3s', '--bat-flap-delay':'0s'}}><Bat/></div>
        <div className="bat" style={{'--bat-top':'22%', '--bat-dur':'26s', '--bat-delay':'-12s', '--bat-flap-delay':'.05s'}}><Bat/></div>
        <div className="bat" style={{'--bat-top':'30%', '--bat-dur':'38s', '--bat-delay':'-20s', '--bat-flap-delay':'.1s'}}><Bat/></div>
        <div className="bat" style={{'--bat-top':'18%', '--bat-dur':'30s', '--bat-delay':'-8s', '--bat-flap-delay':'.03s', transform:'scale(0.7)'}}><Bat/></div>
      </div>

      {/* birds — chacun avec sa trajectoire indépendante, dans les deux sens */}
      {birds.map((b) => (
        <div
          key={b.id}
          data-bird-id={b.id}
          className={`bird ${downBirdIds.has(b.id) ? 'falling':''}`}
          onClick={(e) => { e.stopPropagation(); if (!downBirdIds.has(b.id)) shootBird(b.id); }}
          title={downBirdIds.has(b.id) ? '' : 'Tirer'}
          style={{
            '--bird-top': `${b.top}%`,
            '--bird-dur': `${b.duration}s`,
            '--bird-delay': `${b.delay}s`,
            '--bird-flap': `${b.flapSpeed}s`,
            '--bird-flap-delay': `${b.flapDelay}s`,
            '--bird-amp1': `${b.amp1}px`,
            '--bird-amp2': `${b.amp2}px`,
            '--bird-amp3': `${b.amp3}px`,
            '--bird-anim': b.direction === -1 ? 'bird-fly-rtl' : 'bird-fly-ltr',
          }}
        >
          <div style={{transform: `scale(${b.scale})`, width:'100%', height:'100%'}}>
            <Bird/>
          </div>
        </div>
      ))}

      {/* mountains — back to front */}
      <div className="mt mt-far"  ref={farRef}>  <MountainsFar/>  </div>
      <div className="mt mt-mid"  ref={midRef}>
        <MountainsMid/>
        {/* drapeau suisse — enfant du layer mid pour suivre le parallax */}
        <div className="flag" aria-hidden="true">
          <div className="pole"/><div className="cloth"/>
        </div>
        {/* Bunkers — positions randomisées à chaque chargement, toujours bas dans la montagne */}
        {proximate && bunkerPositions.map((bk, i) => (
          <Bunker
            key={i}
            x={bk.x} y={bk.y} tilt={bk.tilt} aim={bk.aim}
            open={bunkersOpen}
            firing={i === 0 ? firing.a : firing.b}
            label={bunkerLabels[i % bunkerLabels.length]}
            bunkerRef={(el) => { bunkerRefs.current[i] = el; }}
          />
        ))}
      </div>
      {/* brume d'horizon */}
      <div className="haze" aria-hidden="true"/>
      <div className="mt mt-near" ref={nearRef}> <MountainsNear/> </div>

      {/* lake */}
      <div className="lake" ref={lakeRef}>
        {/* reflection */}
        <div className="reflection" aria-hidden="true">
          <MountainsMid fill="rgba(80,95,120,.55)" snow="rgba(255,255,255,.4)"/>
        </div>
        {/* boats — répartis en profondeur */}
        {boats.map((b, i) => (
          <div
            key={`boat-${i}`}
            className="boat"
            style={{
              '--bottom': `${b.bottom}%`,
              '--scale': b.scale,
              '--flip': b.flip,
              '--anim': b.anim,
              '--dur': `${b.dur}s`,
              '--delay': `${b.delay}s`,
              '--bob': `${b.bob}s`,
              '--z': b.z,
            }}
          >
            <div className="hull">
              <Boat sailColor={b.color.sail} accentColor={b.color.accent}/>
            </div>
          </div>
        ))}
      </div>

      {/* grain */}
      <div className="hero-grain"/>

      {/* score badge (easter egg) */}
      <div className={`score-badge ${scoreMessage ? 'show':''}`} aria-live="polite">
        {scoreMessage && (
          <>
            <div className="count">🐦 {score} touché{score>1?'s':''}</div>
            <div style={{marginTop:6}}>{scoreMessage}</div>
          </>
        )}
      </div>

      {/* text */}
      <div className="hero-text" ref={textRef}>
        <div className="hero-kicker">
          <span className="dot"/>
          <span>Société suisse · Cybersécurité · 🇨🇭 Zürich</span>
          <span className="hero-kicker-sep"/>
          <span className="hero-kicker-ai">
            <span className="hk-ai-dot"/>
            + Garde IA souverain
          </span>
        </div>
        <h1 className="hero-h1">
          Le VPN qui<br/>
          <span className="it accent">ne sait rien</span><br/>
          de vous.
        </h1>
        <div className="hero-sub">
          <p className="lead">
            Sans email. Sans mot de passe. Sans carte bancaire.<br/>
            Un identifiant à 16 chiffres et votre vie privée <em>redevient privée.</em>
          </p>
          <div className="hero-cta">
            <div className="cta-row">
              <button className="btn btn-accent" onClick={onGenerate}>
                Générer mon identifiant →
              </button>
              <button className="btn btn-ghost" onClick={onLogin}>
                J'ai déjà un identifiant
              </button>
            </div>
            <button className="btn-affiliate" onClick={onAffiliate}>
              <span className="ba-label">
                <span>J'ai un code parrain</span>
                <span className="ba-sub">+30 jours offerts</span>
              </span>
              <span className="arrow">→</span>
            </button>
          </div>
        </div>
      </div>

      <div className="scroll-tip" aria-hidden="true">
        <span>Descendez · Faites défiler</span>
        <span className="line"/>
      </div>

      {/* crosshair — apparaît quand on s'approche d'un oiseau */}
      <div ref={crosshairRef} className={`crosshair ${proximate ? 'show' : ''}`} aria-hidden="true">
        <div className="ring"/>
        <div className="dot"/>
      </div>
    </section>
  );
};

Object.assign(window, { AlpineHero, MountainsFar, MountainsMid, MountainsNear, Boat, Bird });
