/* NEKTAR — Section 03 · Notre sélection
   Physique réelle : rebond bulles ↔ bulles, murs, zone CTA
   Photo de vigne en fond, bulles or plus grandes + lisibles */
const { useEffect, useRef, useState } = React;

/* -------------------------------------------------------
   Domaines sélectionnés (les plus connus/chers)
------------------------------------------------------- */
const DOMAINS = [
  'Egly-Ouriet',
  'Leclerc Briant',
  'Jacquesson',
  'Pierre Péters',
  "Cos d'Estournel",
  'Château Climens',
  'Marcel Lapierre',
  'Leflaive',
  'Ramonet',
  'Bonneau du Martray',
  'Jean-Marc Roulot',
  'Domaine des Lambrays',
  'Jacques Prieur',
  'Jean Grivot',
  'Denis Mortet',
  'Rossignol-Trapet',
  "Marquis d'Angerville",
  'Henri Boillot',
  'Auguste Clape',
  'Conterno',
  'Dagueneau',
];

/* Mise en page : max 2 lignes dans le cercle */
function formatName(name) {
  const parts = name.split(' ');
  if (parts.length <= 1) return name;
  if (parts.length === 2) return parts[0] + '\n' + parts[1];
  const mid = Math.ceil(parts.length / 2);
  return parts.slice(0, mid).join(' ') + '\n' + parts.slice(mid).join(' ');
}

/* Pseudo-aléatoire déterministe */
function makeSrand(seed) {
  let s = seed;
  return () => { s = (s * 9301 + 49297) % 233280; return s / 233280; };
}

/* -------------------------------------------------------
   Initialisation physique
   Retourne un tableau de bulles avec cx, cy, vx, vy
------------------------------------------------------- */
function initPhysics({ count, r, w, h }) {
  const rand  = makeSrand(99);
  const gap   = 10;
  const minD  = r * 2 + gap;
  const pad   = r + 8;
  const ctaR  = Math.min(w, h) * 0.17; // zone protégée au centre

  const bubbles = [];
  const shuffled = [...DOMAINS].sort(() => rand() - 0.5);

  for (const name of shuffled) {
    if (bubbles.length >= count) break;

    for (let attempt = 0; attempt < 400; attempt++) {
      const cx = pad + rand() * (w - pad * 2);
      const cy = pad + rand() * (h - pad * 2);

      /* Exclure zone CTA centrale */
      const dx0 = cx - w / 2, dy0 = cy - h / 2;
      if (dx0 * dx0 + dy0 * dy0 < (ctaR + r) * (ctaR + r)) continue;

      /* Exclure chevauchements avec bulles déjà placées */
      const clash = bubbles.some(b => {
        const dx = b.cx - cx, dy = b.cy - cy;
        return dx * dx + dy * dy < minD * minD;
      });
      if (clash) continue;

      /* Vitesse initiale lente et aléatoire */
      const angle = rand() * Math.PI * 2;
      const speed = 0.25 + rand() * 0.35;
      bubbles.push({
        name,
        formatted: formatName(name),
        cx, cy,
        vx: Math.cos(angle) * speed,
        vy: Math.sin(angle) * speed,
        el: null,
      });
      break;
    }
  }
  return bubbles;
}

/* -------------------------------------------------------
   Tick physique — appelé à chaque frame
------------------------------------------------------- */
function tick(bubbles, r, w, h) {
  const ctaR = Math.min(w, h) * 0.17;
  const cx0  = w / 2, cy0 = h / 2;

  for (const b of bubbles) {
    b.cx += b.vx;
    b.cy += b.vy;

    /* Rebond sur les murs */
    if (b.cx - r < 0)  { b.cx = r;     b.vx =  Math.abs(b.vx); }
    if (b.cx + r > w)  { b.cx = w - r; b.vx = -Math.abs(b.vx); }
    if (b.cy - r < 0)  { b.cy = r;     b.vy =  Math.abs(b.vy); }
    if (b.cy + r > h)  { b.cy = h - r; b.vy = -Math.abs(b.vy); }

    /* Rebond sur la zone CTA centrale (obstacle fixe) */
    const dxC = b.cx - cx0, dyC = b.cy - cy0;
    const distC = Math.sqrt(dxC * dxC + dyC * dyC);
    const minC  = ctaR + r + 6;
    if (distC < minC) {
      const nx = dxC / (distC || 1), ny = dyC / (distC || 1);
      const dot = b.vx * nx + b.vy * ny;
      if (dot < 0) { b.vx -= 2 * dot * nx; b.vy -= 2 * dot * ny; }
      b.cx += nx * (minC - distC);
      b.cy += ny * (minC - distC);
    }
  }

  /* Rebonds entre bulles (O(n²) — acceptable pour n ≤ 15) */
  for (let i = 0; i < bubbles.length; i++) {
    for (let j = i + 1; j < bubbles.length; j++) {
      const a = bubbles[i], b = bubbles[j];
      const dx = b.cx - a.cx, dy = b.cy - a.cy;
      const dist = Math.sqrt(dx * dx + dy * dy);
      const minD = r * 2 + 4;
      if (dist < minD && dist > 0) {
        const nx = dx / dist, ny = dy / dist;
        /* Impulsion (masse égale → échange composantes normales) */
        const dvx = a.vx - b.vx, dvy = a.vy - b.vy;
        const dot = dvx * nx + dvy * ny;
        if (dot > 0) {
          a.vx -= dot * nx; a.vy -= dot * ny;
          b.vx += dot * nx; b.vy += dot * ny;
        }
        /* Séparation */
        const push = (minD - dist) / 2;
        a.cx -= nx * push; a.cy -= ny * push;
        b.cx += nx * push; b.cy += ny * push;
      }
    }
  }
}

/* -------------------------------------------------------
   Paramètres selon la taille d'écran
------------------------------------------------------- */
function getParams(w) {
  if (w >= 1200) return { size: 138, count: 12 };
  if (w >= 768)  return { size: 116, count: 8  };
  return             { size: 96,  count: 6  };
}

/* -------------------------------------------------------
   App
------------------------------------------------------- */
function App() {
  const physRef  = useRef(null);
  const animRef  = useRef(null);
  const [ready, setReady] = useState(false);

  useEffect(() => {
    const w = window.innerWidth;
    const h = window.innerHeight;
    const { size, count } = getParams(w);
    const r = size / 2;

    const bubbles = initPhysics({ count, r, w, h });
    physRef.current = { bubbles, r, w, h };
    setReady(true);

    const loop = () => {
      const { bubbles, r, w, h } = physRef.current;
      tick(bubbles, r, w, h);
      for (const b of bubbles) {
        if (b.el) {
          b.el.style.left = (b.cx - r).toFixed(1) + 'px';
          b.el.style.top  = (b.cy - r).toFixed(1) + 'px';
        }
      }
      animRef.current = requestAnimationFrame(loop);
    };
    animRef.current = requestAnimationFrame(loop);

    return () => cancelAnimationFrame(animRef.current);
  }, []);

  const { bubbles = [], r = 69 } = physRef.current || {};

  return (
    <section className="selection" aria-label="Notre sélection">

      {ready && bubbles.map(b => (
        <div
          key={b.name}
          className="bubble"
          ref={el => { b.el = el; }}
          aria-hidden="true"
          style={{
            left:   (b.cx - r).toFixed(1) + 'px',
            top:    (b.cy - r).toFixed(1) + 'px',
            width:  r * 2 + 'px',
            height: r * 2 + 'px',
          }}
        >
          {b.formatted}
        </div>
      ))}

      <nav className="selection__center" aria-label="Carte des vins">
        <a className="selection__cta" href="#"
          aria-label="Consulter la carte des vins">
          Carte des vins
        </a>
      </nav>

    </section>
  );
}

ReactDOM.createRoot(document.getElementById('root')).render(<App />);
