// comet-curling.jsx
// Preschool physics mini-game: push strength + surface drag change how far a comet slides.

const COMET_CURLING_ASSET = "data/generated-assets/physics/comet-curling-puck.png";

const COMET_CURLING_SURFACES = [
  {
    id: "ice",
    label: "Ice lane",
    drag: 0.9,
    icon: "❄",
    line: "Ice has less drag, so the comet slides far.",
  },
  {
    id: "dust",
    label: "Dust lane",
    drag: 0.62,
    icon: "·",
    line: "Dust slows the comet a little.",
  },
  {
    id: "bumps",
    label: "Bumpy moon",
    drag: 0.38,
    icon: "○",
    line: "Bumps add drag, so the comet stops sooner.",
  },
];

const COMET_CURLING_PUSHES = [
  { id: "tap", label: "Tiny push", force: 0.42, icon: "👆" },
  { id: "push", label: "Big push", force: 0.72, icon: "✋" },
  { id: "blast", label: "Rocket push", force: 1, icon: "🚀" },
];

function cometCurlingDistance(surface, push) {
  return Math.round(18 + surface.drag * push.force * 64);
}

function playCometCurlingTone(kind) {
  try {
    const AudioContext = window.AudioContext || window.webkitAudioContext;
    if (!AudioContext) return;
    const context = new AudioContext();
    const oscillator = context.createOscillator();
    const gain = context.createGain();
    const tone =
      kind === "complete"
        ? { start: 420, end: 840, duration: 0.32, volume: 0.12 }
        : { start: 150, end: 250, duration: 0.18, volume: 0.09 };
    oscillator.type = kind === "complete" ? "sine" : "triangle";
    oscillator.frequency.setValueAtTime(tone.start, context.currentTime);
    oscillator.frequency.exponentialRampToValueAtTime(
      tone.end,
      context.currentTime + tone.duration,
    );
    gain.gain.setValueAtTime(0.0001, context.currentTime);
    gain.gain.exponentialRampToValueAtTime(
      tone.volume,
      context.currentTime + 0.02,
    );
    gain.gain.exponentialRampToValueAtTime(
      0.0001,
      context.currentTime + tone.duration,
    );
    oscillator.connect(gain);
    gain.connect(context.destination);
    oscillator.start();
    oscillator.stop(context.currentTime + tone.duration + 0.02);
    window.setTimeout(() => context.close?.(), (tone.duration + 0.08) * 1000);
  } catch {}
}

function CometCurlingLevel({ onExit }) {
  const [surfaceId, setSurfaceId] = React.useState("ice");
  const [pushId, setPushId] = React.useState("push");
  const [slides, setSlides] = React.useState([]);
  const [message, setMessage] = React.useState(
    "Pick a surface, then push the comet. Less drag slides farther.",
  );
  const [puckMood, setPuckMood] = React.useState("");
  const [farSparkleKey, setFarSparkleKey] = React.useState(null);
  const puckTimerRef = React.useRef(null);
  const puckFrameRef = React.useRef(null);
  const farSparkleTimerRef = React.useRef(null);
  const celebrationShownRef = React.useRef(false);
  const surface =
    COMET_CURLING_SURFACES.find((item) => item.id === surfaceId) ||
    COMET_CURLING_SURFACES[0];
  const push =
    COMET_CURLING_PUSHES.find((item) => item.id === pushId) ||
    COMET_CURLING_PUSHES[1];
  const distance = cometCurlingDistance(surface, push);
  const complete = slides.length >= 5;
  const slideStatus = complete
    ? "Five slides tested. Change a lane or push and slide again."
    : `Slide ${slides.length + 1}/5 ready: ${surface.label} + ${push.label}.`;
  const previewResult =
    distance > 70 ? "far slide" : distance > 48 ? "medium slide" : "short slide";
  const previewHelp =
    distance > 70
      ? "This combo should reach the far zone."
      : distance > 48
        ? "This combo should stop in the middle."
        : "This combo should stop early.";

  React.useEffect(
    () => () => {
      if (puckFrameRef.current) window.cancelAnimationFrame(puckFrameRef.current);
      if (puckTimerRef.current) window.clearTimeout(puckTimerRef.current);
      if (farSparkleTimerRef.current) {
        window.clearTimeout(farSparkleTimerRef.current);
      }
    },
    [],
  );

  const showPuckMood = (mood, duration = 560) => {
    if (puckFrameRef.current) window.cancelAnimationFrame(puckFrameRef.current);
    if (puckTimerRef.current) window.clearTimeout(puckTimerRef.current);
    setPuckMood("");
    puckFrameRef.current = window.requestAnimationFrame(() => {
      puckFrameRef.current = null;
      setPuckMood(mood);
    });
    puckTimerRef.current = window.setTimeout(() => {
      setPuckMood("");
      puckTimerRef.current = null;
    }, duration);
  };

  const runSlide = () => {
    const nextDistance = cometCurlingDistance(surface, push);
    const result =
      nextDistance > 70
        ? "far slide"
        : nextDistance > 48
          ? "medium slide"
          : "short slide";
    const nextSlides = [
      ...slides,
      {
        id: `${Date.now()}-${surface.id}-${push.id}`,
        surfaceId: surface.id,
        pushId: push.id,
        distance: nextDistance,
      },
    ].slice(-5);
    setSlides(nextSlides);
    setMessage(`${surface.line} ${push.label} made a ${result}.`);
    if (result === "far slide") {
      setFarSparkleKey(`${Date.now()}-far`);
      if (farSparkleTimerRef.current) {
        window.clearTimeout(farSparkleTimerRef.current);
      }
      farSparkleTimerRef.current = window.setTimeout(() => {
        setFarSparkleKey(null);
        farSparkleTimerRef.current = null;
      }, 1100);
    }
    playCometCurlingTone(nextSlides.length >= 5 ? "complete" : "slide");
    showPuckMood(
      nextSlides.length >= 5 ? "celebrate" : "slide",
      nextSlides.length >= 5 ? 900 : 560,
    );
    playKidSound("chime");
    if (nextSlides.length >= 5 && !celebrationShownRef.current) {
      celebrationShownRef.current = true;
      window.SpaceExplorerFoundation?.celebrateGameFinish?.({
        gameId: "comet-curling",
        emoji: "☄",
        title: "Comet slide scientist!",
        message: "You tested push force and surface drag.",
      });
    }
  };

  const reset = () => {
    setSlides([]);
    celebrationShownRef.current = false;
    setPuckMood("");
    setFarSparkleKey(null);
    if (farSparkleTimerRef.current) {
      window.clearTimeout(farSparkleTimerRef.current);
      farSparkleTimerRef.current = null;
    }
    setMessage("Try again. Change the surface or push to compare slides.");
    playKidSound("pop");
  };

  return (
    <section className="comet-curling-level" aria-label="Comet Curling physics game">
      <button type="button" className="comet-curling-back" onClick={onExit}>
        Back
      </button>
      <div className="comet-curling-shell">
        <div className="comet-curling-copy">
          <span>Push + Drag</span>
          <h1>Comet Curling</h1>
          <p>
            Push the comet across space lanes. Smooth ice slides far. Bumps slow it down.
          </p>
          <div className="comet-curling-message" role="status" aria-live="polite">
            {message}
          </div>
          <div className="comet-curling-status" aria-live="polite">
            {slideStatus}
          </div>
          <div className="comet-curling-preview" aria-label="Slide preview">
            <span>Slide preview</span>
            <strong>{previewResult}</strong>
            <small>{previewHelp}</small>
          </div>
          <div className="comet-curling-chooser" aria-label="Choose surface">
            {COMET_CURLING_SURFACES.map((option) => (
              <button
                key={option.id}
                type="button"
                className={surface.id === option.id ? "on" : ""}
                onClick={() => {
                  setSurfaceId(option.id);
                  setMessage(`${option.label}: ${option.line}`);
                  playKidSound("boop");
                }}
                aria-pressed={surface.id === option.id ? "true" : "false"}
              >
                <span aria-hidden="true">{option.icon}</span>
                <strong>{option.label}</strong>
              </button>
            ))}
          </div>
          <div className="comet-curling-chooser" aria-label="Choose push">
            {COMET_CURLING_PUSHES.map((option) => (
              <button
                key={option.id}
                type="button"
                className={push.id === option.id ? "on" : ""}
                onClick={() => {
                  setPushId(option.id);
                  setMessage(`${option.label} ready. Tap Slide.`);
                  playKidSound("boop");
                }}
                aria-pressed={push.id === option.id ? "true" : "false"}
              >
                <span aria-hidden="true">{option.icon}</span>
                <strong>{option.label}</strong>
              </button>
            ))}
          </div>
          <div className="comet-curling-actions">
            <button type="button" onClick={runSlide}>
              {complete ? "Slide again" : "Slide"}
            </button>
            <button type="button" onClick={reset}>
              Reset
            </button>
          </div>
        </div>
        <div className={`comet-curling-stage surface-${surface.id}`}>
          <div className="comet-curling-lane" aria-hidden="true">
            <i />
            <i />
            <i />
          </div>
          <img
            className={
              puckMood
                ? `comet-curling-puck ${puckMood}`
                : "comet-curling-puck"
            }
            src={COMET_CURLING_ASSET}
            alt="Smiling comet puck"
            style={{
              "--comet-left": `${12 + distance * 0.74}%`,
              "--comet-distance": `${distance}%`,
              "--comet-spin": `${Math.round(distance * 3)}deg`,
            }}
            draggable="false"
          />
          <div className="comet-curling-target" aria-hidden="true">
            Far zone
          </div>
          {farSparkleKey ? (
            <div
              key={farSparkleKey}
              className="comet-curling-far-sparkles"
              aria-hidden="true"
            >
              {[0, 1, 2].map((index) => (
                <SafeAssetImage
                  key={index}
                  className={`comet-curling-far-sparkle sparkle-${index + 1}`}
                  src={GENERATED_ASSETS.sparkleStar}
                  alt=""
                  context={`CometCurling:farSparkle:${index}`}
                  fallbackText=""
                />
              ))}
            </div>
          ) : null}
          <div className="comet-curling-score" aria-label="Slide history">
            {slides.map((slide, index) => (
              <span key={slide.id} style={{ width: `${slide.distance}%` }}>
                {index + 1}
              </span>
            ))}
          </div>
        </div>
      </div>
    </section>
  );
}

window.CometCurlingLevel = CometCurlingLevel;
