function PeperBowling({ onClose }) {
  const FIELD_W = 480;
  const FIELD_H = 720;
  const LANE_X = 0;
  const LANE_W = FIELD_W;
  const PIN_ROWS = 4;
  const PIN_R = 14;
  const BALL_R = 22;
  const FRAMES_TOTAL = 10;

  const [phase, setPhase] = React.useState("intro");
  const [score, setScore] = React.useState(0);
  const [best, setBest] = React.useState(() => {
    try { return parseInt(localStorage.getItem("peper-bowling-best") || "0", 10) || 0; }
    catch { return 0; }
  });
  const [frame, setFrame] = React.useState(1);
  const [throwNum, setThrowNum] = React.useState(1);
  const [frameScores, setFrameScores] = React.useState([]);
  const [message, setMessage] = React.useState("");
  const [scale, setScale] = React.useState(1);
  const [narrow, setNarrow] = React.useState(typeof window !== "undefined" && window.innerWidth <= 600);
  const [, forceRender] = React.useReducer(x => x + 1, 0);

  const wrapRef = React.useRef(null);
  const ballRef = React.useRef({ x: FIELD_W / 2, y: FIELD_H - 90, vx: 0, vy: 0, rolling: false, spin: 0 });
  const pinsRef = React.useRef([]);
  const aimRef = React.useRef({ angle: 0, dir: 1, power: 0, powerDir: 1, state: "aim" });
  const lastFrameRef = React.useRef(0);
  const particlesRef = React.useRef([]);
  const idRef = React.useRef(0);
  const standingBeforeThrow = React.useRef(10);

  React.useEffect(() => {
    function measure() {
      setNarrow(window.innerWidth <= 600);
      if (!wrapRef.current) return;
      const r = wrapRef.current.getBoundingClientRect();
      if (r.width > 0 && r.height > 0) {
        setScale(Math.max(0.3, Math.min(r.width / FIELD_W, r.height / FIELD_H)));
      }
    }
    measure();
    let ro;
    if (typeof ResizeObserver !== "undefined" && wrapRef.current) {
      ro = new ResizeObserver(measure);
      ro.observe(wrapRef.current);
    }
    window.addEventListener("resize", measure);
    return () => {
      if (ro) ro.disconnect();
      window.removeEventListener("resize", measure);
    };
  }, []);

  React.useEffect(() => {
    const prev = document.body.style.overflow;
    document.body.style.overflow = "hidden";
    return () => { document.body.style.overflow = prev; };
  }, []);

  function initPins() {
    const pins = [];
    const startY = 120;
    const spacingX = 36;
    const spacingY = 34;
    for (let row = 0; row < PIN_ROWS; row++) {
      const count = row + 1;
      const rowX = FIELD_W / 2 - (count - 1) * spacingX / 2;
      for (let col = 0; col < count; col++) {
        pins.push({
          id: ++idRef.current,
          x: rowX + col * spacingX,
          y: startY + row * spacingY,
          standing: true,
          fallAngle: 0,
          fallDir: 0,
          wobble: 0,
        });
      }
    }
    pinsRef.current = pins;
  }

  function resetBall() {
    ballRef.current = { x: FIELD_W / 2, y: FIELD_H - 90, vx: 0, vy: 0, rolling: false, spin: 0 };
    aimRef.current = { angle: 0, dir: 1, power: 0, powerDir: 1, state: "aim" };
  }

  function startGame() {
    setScore(0);
    setFrame(1);
    setThrowNum(1);
    setFrameScores([]);
    setMessage("");
    initPins();
    resetBall();
    standingBeforeThrow.current = 10;
    setPhase("playing");
  }

  function throwBall() {
    const aim = aimRef.current;
    if (aim.state !== "power") return;
    aim.state = "thrown";
    const b = ballRef.current;
    const speed = 600 + aim.power * 500;
    const ang = -Math.PI / 2 + aim.angle * 0.6;
    b.vx = Math.cos(ang) * speed;
    b.vy = Math.sin(ang) * speed;
    b.rolling = true;
    b.spin = aim.angle * 3;
  }

  React.useEffect(() => {
    function onKey(e) {
      if (e.key === "Escape") { onClose && onClose(); return; }
      if (phase === "intro" && (e.key === " " || e.key === "Enter")) { startGame(); return; }
      if (phase === "result" && (e.key === " " || e.key === "Enter")) { startGame(); return; }
      if (phase !== "playing") return;
      const aim = aimRef.current;
      if (e.key === " " || e.key === "Enter") {
        e.preventDefault();
        if (aim.state === "aim") aim.state = "power";
        else if (aim.state === "power") throwBall();
      }
    }
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [phase]);

  function handleTap() {
    if (phase === "intro") { startGame(); return; }
    if (phase === "result") { startGame(); return; }
    if (phase !== "playing") return;
    const aim = aimRef.current;
    if (aim.state === "aim") aim.state = "power";
    else if (aim.state === "power") throwBall();
  }

  React.useEffect(() => {
    if (phase !== "playing") return;
    let raf = 0;
    lastFrameRef.current = performance.now();
    function tick(ts) {
      const dt = Math.min(0.04, (ts - lastFrameRef.current) / 1000);
      lastFrameRef.current = ts;
      const aim = aimRef.current;
      const b = ballRef.current;

      if (aim.state === "aim") {
        aim.angle += aim.dir * dt * 2.0;
        if (aim.angle > 0.7) { aim.angle = 0.7; aim.dir = -1; }
        if (aim.angle < -0.7) { aim.angle = -0.7; aim.dir = 1; }
      }
      if (aim.state === "power") {
        aim.power += aim.powerDir * dt * 1.8;
        if (aim.power > 1) { aim.power = 1; aim.powerDir = -1; }
        if (aim.power < 0) { aim.power = 0; aim.powerDir = 1; }
      }

      if (b.rolling) {
        b.x += b.vx * dt;
        b.y += b.vy * dt;
        b.vx += b.spin * 40 * dt;
        b.spin *= Math.pow(0.95, dt * 60);

        if (b.x - BALL_R < LANE_X) { b.x = LANE_X + BALL_R; b.vx = Math.abs(b.vx) * 0.3; }
        if (b.x + BALL_R > LANE_X + LANE_W) { b.x = LANE_X + LANE_W - BALL_R; b.vx = -Math.abs(b.vx) * 0.3; }

        for (const pin of pinsRef.current) {
          if (!pin.standing) continue;
          const dx = b.x - pin.x;
          const dy = b.y - pin.y;
          const dist = Math.sqrt(dx * dx + dy * dy);
          if (dist < BALL_R + PIN_R) {
            pin.standing = false;
            pin.fallDir = dx > 0 ? -1 : 1;
            pin.fallAngle = 0;
            b.vx += dx * 0.5;
            b.vy *= 0.92;

            for (let i = 0; i < 6; i++) {
              const ang = Math.random() * Math.PI * 2;
              const v = 100 + Math.random() * 150;
              particlesRef.current.push({
                id: ++idRef.current,
                x: pin.x, y: pin.y,
                vx: Math.cos(ang) * v, vy: Math.sin(ang) * v,
                life: 0.5 + Math.random() * 0.3,
                r: 3 + Math.random() * 3,
                c: ["#FFD23F", "#FF8C1A", "#E63946"][Math.floor(Math.random() * 3)],
              });
            }

            const fallen = [pin];
            let ci = 0;
            while (ci < fallen.length) {
              const src = fallen[ci++];
              for (const other of pinsRef.current) {
                if (!other.standing || fallen.includes(other)) continue;
                const ox = other.x - src.x;
                const oy = other.y - src.y;
                const od = Math.sqrt(ox * ox + oy * oy);
                if (od < PIN_R * 3) {
                  other.standing = false;
                  other.fallDir = ox > 0 ? 1 : -1;
                  other.fallAngle = 0;
                  fallen.push(other);
                }
              }
            }
          }
        }

        for (const pin of pinsRef.current) {
          if (!pin.standing && pin.fallAngle < 1) {
            pin.fallAngle = Math.min(1, pin.fallAngle + dt * 4);
          }
        }

        if (b.y < -50 || (Math.abs(b.vy) < 10 && b.y < 200)) {
          b.rolling = false;
          finishThrow();
        }
      }

      particlesRef.current = particlesRef.current
        .map(d => ({ ...d, x: d.x + d.vx * dt, y: d.y + d.vy * dt, life: d.life - dt }))
        .filter(d => d.life > 0);

      forceRender();
      raf = requestAnimationFrame(tick);
    }
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [phase]);

  function finishThrow() {
    const knocked = pinsRef.current.filter(p => !p.standing).length;
    const knockedThisThrow = standingBeforeThrow.current - pinsRef.current.filter(p => p.standing).length;

    if (throwNum === 1 && knockedThisThrow === 10) {
      setMessage("STRIKE! 🔥");
      setScore(s => s + 20);
      setFrameScores(fs => [...fs, { f: frame, t1: "X", t2: "", total: knockedThisThrow }]);
      nextFrame();
    } else if (throwNum === 1 && pinsRef.current.filter(p => p.standing).length > 0) {
      setMessage(knockedThisThrow > 0 ? `${knockedThisThrow} pins!` : "Mis!");
      setScore(s => s + knockedThisThrow);
      standingBeforeThrow.current = pinsRef.current.filter(p => p.standing).length;
      setThrowNum(2);
      resetBall();
    } else if (throwNum === 1) {
      setMessage("STRIKE! 🔥");
      setScore(s => s + 20);
      setFrameScores(fs => [...fs, { f: frame, t1: "X", t2: "", total: knockedThisThrow }]);
      nextFrame();
    } else {
      if (pinsRef.current.filter(p => p.standing).length === 0) {
        setMessage("SPARE! ⚡");
        setScore(s => s + knockedThisThrow + 5);
        setFrameScores(fs => [...fs, { f: frame, t1: fs.length > 0 ? fs[fs.length - 1]?.total : "", t2: "/", total: knockedThisThrow }]);
      } else {
        setMessage(knockedThisThrow > 0 ? `${knockedThisThrow} pins` : "Mis!");
        setScore(s => s + knockedThisThrow);
        setFrameScores(fs => [...fs, { f: frame, t1: "", t2: knockedThisThrow, total: knockedThisThrow }]);
      }
      nextFrame();
    }
  }

  function nextFrame() {
    if (frame >= FRAMES_TOTAL) {
      setTimeout(() => {
        setBest(prev => {
          const final = score;
          if (final > prev) {
            try { localStorage.setItem("peper-bowling-best", String(final)); } catch {}
            return final;
          }
          return prev;
        });
        setPhase("result");
      }, 1200);
      return;
    }
    setTimeout(() => {
      setFrame(f => f + 1);
      setThrowNum(1);
      initPins();
      resetBall();
      standingBeforeThrow.current = 10;
      setMessage("");
    }, 1200);
  }

  const aim = aimRef.current;
  const b = ballRef.current;

  function Pill({ bg, color, narrow: n, children }) {
    return (
      <span style={{
        background: bg, color, border: "3px solid #1A1A1A",
        boxShadow: "2px 2px 0 #1A1A1A",
        padding: n ? "4px 8px" : "6px 12px",
        fontFamily: "'Bangers', sans-serif",
        fontSize: n ? 16 : 20, letterSpacing: "0.04em",
      }}>{children}</span>
    );
  }

  function Title({ color, children }) {
    return (
      <div style={{
        fontFamily: "'Bangers', sans-serif", fontSize: 44,
        color, WebkitTextStroke: "1.5px #1A1A1A",
        textShadow: "3px 3px 0 #1A1A1A", letterSpacing: "0.05em",
        textAlign: "center", margin: 0,
      }}>{children}</div>
    );
  }

  function Overlay({ children }) {
    return (
      <div style={{
        position: "absolute", inset: 0,
        background: "rgba(15,20,42,0.88)",
        display: "flex", flexDirection: "column",
        alignItems: "center", justifyContent: "center",
        padding: 20, gap: 12, color: "#FFF8EC",
      }}>{children}</div>
    );
  }

  function BigBtn({ onClick, color, children }) {
    return (
      <button onClick={onClick} style={{
        background: color, color: "#FFF",
        border: "4px solid #1A1A1A", boxShadow: "4px 4px 0 #1A1A1A",
        fontFamily: "'Bangers', sans-serif", fontSize: 28,
        padding: "10px 28px", cursor: "pointer", letterSpacing: "0.04em",
        marginTop: 8,
      }}>{children}</button>
    );
  }

  const oText = { fontSize: 18, lineHeight: 1.5, maxWidth: 420, textAlign: "center", color: "#FFF8EC", margin: 0 };

  return (
    <div style={{
      position: "fixed", inset: 0, zIndex: 200,
      background: "#D4956A",
      fontFamily: "'Patrick Hand', cursive",
      color: "#1A1A1A",
      display: "flex", flexDirection: "column",
      overscrollBehavior: "contain",
      touchAction: "none",
    }}>
      <div style={{
        flexShrink: 0,
        display: "flex", alignItems: "center", justifyContent: "space-between",
        padding: narrow ? "8px 10px" : "10px 16px",
        gap: 8,
        background: "rgba(255, 245, 220, 0.96)",
        borderBottom: "3px solid #1A1A1A",
      }}>
        <div style={{
          fontFamily: "'Bangers', sans-serif",
          fontSize: narrow ? 22 : 28, letterSpacing: "0.04em",
          color: "#E63946",
          WebkitTextStroke: "1.2px #1A1A1A",
          textShadow: "2px 2px 0 #1A1A1A",
          display: "flex", alignItems: "center", gap: 6,
          whiteSpace: "nowrap",
        }}>
          <span style={{ fontSize: narrow ? 20 : 24, WebkitTextStroke: 0, textShadow: "none" }}>🎳</span>
          {narrow ? "BOWLING" : "PEPER BOWLING"}
        </div>
        <div style={{ display: "flex", alignItems: "center", gap: narrow ? 6 : 10 }}>
          <Pill bg="#FFD23F" color="#1A1A1A" narrow={narrow}>Frame {frame}/{FRAMES_TOTAL}</Pill>
          <Pill bg="#3FA34D" color="#FFF" narrow={narrow}>⚡ {score}</Pill>
          <Pill bg="#FF8C1A" color="#FFF" narrow={narrow}>🏆 {best}</Pill>
          <button onClick={onClose} aria-label="Sluiten" style={{
            width: 44, height: 44, borderRadius: "50%",
            background: "#1A1A1A", color: "#F0FAE6",
            border: "3px solid #F0FAE6", boxShadow: "2px 2px 0 #1A1A1A",
            fontFamily: "'Bangers', sans-serif", fontSize: 22,
            cursor: "pointer", flexShrink: 0,
          }}>✕</button>
        </div>
      </div>

      <div ref={wrapRef} onPointerDown={handleTap} style={{
        flex: 1, position: "relative",
        display: "flex", alignItems: "center", justifyContent: "center",
        padding: 6, overflow: "hidden", cursor: "pointer",
      }}>
        <div style={{
          width: FIELD_W * scale, height: FIELD_H * scale,
          position: "relative",
        }}>
          <svg viewBox={`0 0 ${FIELD_W} ${FIELD_H}`}
            preserveAspectRatio="none"
            width={FIELD_W * scale} height={FIELD_H * scale}
            style={{
              display: "block",
              touchAction: "none", userSelect: "none",
            }}>
            <defs>
              <linearGradient id="pb-lane" x1="0" y1="0" x2="1" y2="0">
                <stop offset="0%" stopColor="#D4956A" />
                <stop offset="15%" stopColor="#E8B07A" />
                <stop offset="50%" stopColor="#F0C48E" />
                <stop offset="85%" stopColor="#E8B07A" />
                <stop offset="100%" stopColor="#D4956A" />
              </linearGradient>
              <linearGradient id="pb-gutter" x1="0" y1="0" x2="1" y2="0">
                <stop offset="0%" stopColor="#2A2A3A" />
                <stop offset="100%" stopColor="#1A1A2A" />
              </linearGradient>
            </defs>

            {/* baan = volledige breedte */}
            <rect x="0" y="0" width={FIELD_W} height={FIELD_H} fill="url(#pb-lane)" />

            {/* subtiele randen */}
            <rect x="0" y="0" width="6" height={FIELD_H} fill="#C08050" opacity="0.5" />
            <rect x={FIELD_W - 6} y="0" width="6" height={FIELD_H} fill="#C08050" opacity="0.5" />

            {/* baan-strepen */}
            {[0.25, 0.5, 0.75].map(f => (
              <line key={f} x1={LANE_X + LANE_W * f} y1="0" x2={LANE_X + LANE_W * f} y2={FIELD_H}
                stroke="#C9915E" strokeWidth="1" strokeDasharray="8 8" opacity="0.5" />
            ))}

            {/* pijlen op de baan */}
            {[FIELD_H * 0.55, FIELD_H * 0.65].map(ay => (
              <g key={ay}>
                {[-1, 0, 1].map(dx => (
                  <path key={dx}
                    d={`M ${FIELD_W / 2 + dx * 40} ${ay + 12} l 0 -20 l -6 0 l 10 -10 l 10 10 l -6 0 l 0 20 z`}
                    fill="#C9915E" opacity="0.4" />
                ))}
              </g>
            ))}

            {/* pins */}
            {pinsRef.current.map(pin => {
              const angle = pin.standing ? 0 : pin.fallAngle * pin.fallDir * 90;
              const opacity = pin.standing ? 1 : Math.max(0, 1 - pin.fallAngle);
              return (
                <g key={pin.id} transform={`translate(${pin.x} ${pin.y}) rotate(${angle})`} opacity={opacity}>
                  {/* pin body */}
                  <ellipse cx="0" cy="8" rx="7" ry="4" fill="#DDD" stroke="#1A1A1A" strokeWidth="1.5" />
                  <rect x="-5" y="-8" width="10" height="16" rx="4" fill="#F5F5F0" stroke="#1A1A1A" strokeWidth="1.5" />
                  <circle cx="0" cy="-10" r="6" fill="#F5F5F0" stroke="#1A1A1A" strokeWidth="1.5" />
                  {/* rode streep */}
                  <rect x="-5" y="-3" width="10" height="3" fill="#E63946" />
                  <rect x="-5" y="2" width="10" height="3" fill="#E63946" />
                </g>
              );
            })}

            {/* deeltjes */}
            {particlesRef.current.map(d => (
              <circle key={d.id} cx={d.x} cy={d.y} r={d.r}
                fill={d.c} opacity={Math.max(0, d.life * 2)} />
            ))}

            {/* richtpijl */}
            {!b.rolling && phase === "playing" && (() => {
              const ang = aim.angle * 0.6;
              const sinA = Math.sin(ang);
              const cosA = Math.cos(ang);
              const len = 200;
              const tipX = b.x + sinA * len;
              const tipY = b.y - cosA * len;
              const midX = b.x + sinA * (len * 0.7);
              const midY = b.y - cosA * (len * 0.7);
              const perpX = cosA;
              const perpY = sinA;
              return (
                <g>
                  {/* glow achter de pijl */}
                  <line x1={b.x} y1={b.y} x2={tipX} y2={tipY}
                    stroke="#FFD23F" strokeWidth="14" opacity="0.2" strokeLinecap="round" />
                  {/* brede lijn */}
                  <line x1={b.x} y1={b.y - 10} x2={midX} y2={midY}
                    stroke="#FFD23F" strokeWidth="6" opacity="0.9" strokeLinecap="round" />
                  {/* stippels binnenin */}
                  <line x1={b.x} y1={b.y - 10} x2={midX} y2={midY}
                    stroke="#FFF" strokeWidth="2" strokeDasharray="6 8" opacity="0.6" strokeLinecap="round" />
                  {/* grote pijlpunt */}
                  <polygon
                    points={`${tipX},${tipY}
                      ${midX + perpX * 16},${midY + perpY * 16}
                      ${midX - perpX * 16},${midY - perpY * 16}`}
                    fill="#FFD23F" stroke="#1A1A1A" strokeWidth="2" />
                  {/* witte glans op pijlpunt */}
                  <polygon
                    points={`${tipX},${tipY}
                      ${midX + perpX * 6},${midY + perpY * 6}
                      ${midX - perpX * 6},${midY - perpY * 6}`}
                    fill="#FFF" opacity="0.35" />
                  {/* cirkel-stippen langs de lijn */}
                  {[0.2, 0.4, 0.6].map(t => (
                    <circle key={t}
                      cx={b.x + sinA * len * t}
                      cy={b.y - 10 + (-cosA * len * t + 10 * (1 - t))}
                      r={4 - t * 2}
                      fill="#FFD23F" opacity={0.8 - t * 0.3} />
                  ))}
                </g>
              );
            })()}

            {/* bal */}
            <g transform={`translate(${b.x} ${b.y})`}>
              <circle cx="0" cy="4" r={BALL_R + 2} fill="rgba(0,0,0,0.25)" />
              <circle cx="0" cy="0" r={BALL_R} fill="#E63946" stroke="#1A1A1A" strokeWidth="2.5" />
              <circle cx="-5" cy="-5" r="4" fill="#A01B26" />
              <circle cx="4" cy="-8" r="3.5" fill="#A01B26" />
              <circle cx="6" cy="0" r="4" fill="#A01B26" />
              {/* glans */}
              <ellipse cx="-8" cy="-8" rx="6" ry="4" fill="rgba(255,255,255,0.35)" transform="rotate(-30)" />
            </g>

            {/* power meter */}
            {phase === "playing" && aim.state === "power" && (
              <g>
                <rect x={FIELD_W - 40} y={FIELD_H * 0.2} width={20} height={FIELD_H * 0.5}
                  fill="#2A2A3A" stroke="#1A1A1A" strokeWidth="2" rx="4" />
                <rect x={FIELD_W - 38} y={FIELD_H * 0.2 + FIELD_H * 0.5 * (1 - aim.power) + 2}
                  width={16} height={FIELD_H * 0.5 * aim.power - 4}
                  fill={aim.power > 0.7 ? "#E63946" : aim.power > 0.4 ? "#FF8C1A" : "#3FA34D"}
                  rx="3" />
              </g>
            )}

            {/* status tekst */}
            {phase === "playing" && !b.rolling && (
              <text x={FIELD_W / 2} y={FIELD_H - 30}
                textAnchor="middle" fill="#FFF8EC"
                fontFamily="'Bangers', sans-serif" fontSize="22" letterSpacing="0.05em"
                stroke="#1A1A1A" strokeWidth="2" paintOrder="stroke">
                {aim.state === "aim" ? "Tik om te richten" : "Tik om te gooien!"}
              </text>
            )}
          </svg>

          {/* bericht overlay */}
          {message && phase === "playing" && (
            <div style={{
              position: "absolute", top: "40%", left: 0, right: 0,
              textAlign: "center", pointerEvents: "none",
              fontFamily: "'Bangers', sans-serif", fontSize: 48 * scale,
              color: message.includes("STRIKE") ? "#FFD23F" : message.includes("SPARE") ? "#FF8C1A" : "#FFF",
              WebkitTextStroke: `${2 * scale}px #1A1A1A`,
              textShadow: `${3 * scale}px ${3 * scale}px 0 #1A1A1A`,
              animation: "pb-pop 0.5s ease-out",
            }}>
              {message}
              <style>{`@keyframes pb-pop { 0% { transform: scale(0.3); opacity: 0; } 60% { transform: scale(1.2); } 100% { transform: scale(1); opacity: 1; } }`}</style>
            </div>
          )}

          {phase === "intro" && (
            <Overlay>
              <Title color="#FF8C1A">PEPER BOWLING</Title>
              <p style={oText}>
                Gooi de bowlingbal en sla alle pins om!<br />
                <strong>Eerste tik:</strong> stop de richtpijl.<br />
                <strong>Tweede tik:</strong> kies je kracht.<br />
                10 frames, haal jij een strike? 🔥
              </p>
              <BigBtn onClick={startGame} color="#3FA34D">▶ BOWL!</BigBtn>
            </Overlay>
          )}

          {phase === "result" && (
            <Overlay>
              <Title color="#FFD23F">GAME OVER</Title>
              <p style={oText}>
                Je scoorde <strong>{score}</strong> punten in {FRAMES_TOTAL} frames!
                {score >= best && score > 0 && <><br /><span style={{ color: "#FF8C1A", fontWeight: "bold" }}>🏆 NIEUW RECORD!</span></>}
                {score < best && <><br />Beste: <strong>{best}</strong></>}
              </p>
              <BigBtn onClick={startGame} color="#3FA34D">↻ NOG EENS</BigBtn>
            </Overlay>
          )}
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { PeperBowling });
