const MOON_CONTACT_SIGNALS = [
  {
    id: "welcome",
    label: "Welcome Pulse",
    speaker: "left alien",
    pattern: ["cyan", "cyan", "gold"],
    reply: "They lower the ramp. First contact stays calm.",
    audio: "game_moon_aliens_left_welcome.mp3",
  },
  {
    id: "trade",
    label: "Crystal Trade",
    speaker: "middle alien",
    pattern: ["gold", "cyan", "violet"],
    reply: "The moon visitors offer a glowing mineral sample.",
    audio: "game_moon_aliens_middle_trade.mp3",
  },
  {
    id: "map",
    label: "Star Map",
    speaker: "right alien",
    pattern: ["violet", "gold", "gold"],
    reply: "A hidden route lights up across the lunar sky.",
    audio: "game_moon_aliens_right_map.mp3",
  },
];

const MOON_SIGNAL_COLORS = {
  cyan: 0x77f4ff,
  gold: 0xffd66b,
  violet: 0xc7a2ff,
};

const MOON_SIGNAL_SHORT_LABELS = {
  cyan: "cyan",
  gold: "gold",
  violet: "violet",
};

// Set this to true after the Grok MP3s in GROK_TTS_MOON_ALIENS.md
// have been exported into data/audio/planets/.
const MOON_ALIENS_TTS_READY = true;

function playMoonAlienNarration(file) {
  if (!file || !window.__narration || !window.__narration.isEnabled()) return;
  if (!MOON_ALIENS_TTS_READY) return;
  window.__narration.play(file);
}

function createMoonAliensPhaserGame(mount, callbacks = {}, options = {}) {
  const PhaserLib = window.Phaser;
  if (!PhaserLib) return null;
  const skipCinematic = !!options.skipCinematic;

  class MoonContactScene extends PhaserLib.Scene {
    constructor() {
      super("MoonContactScene");
      this.phase = "cinematic";
      this.sequence = [];
      this.caseIndex = 0;
      this.hintTimer = null;
    }

    clearHintTimer() {
      if (this.hintTimer) {
        this.hintTimer.remove(false);
        this.hintTimer = null;
      }
    }

    scheduleInactivityHint() {
      this.clearHintTimer();
      this.hintTimer = this.time.delayedCall(8000, () => {
        if (!this.sys || !this.sys.isActive()) return;
        if (this.phase !== "play") return;
        const signal = MOON_CONTACT_SIGNALS[this.caseIndex];
        if (!signal) return;
        const expected = signal.pattern[this.sequence.length];
        const pad = this.pads.find((item) => item.signalKey === expected);
        if (!pad) return;
        this.pulsePad(pad, expected);
        this.scheduleInactivityHint();
      });
    }

    preload() {
      this.load.image(
        "moon-aliens",
        "data/generated-assets/moon-aliens/aliens.png",
      );
      this.load.image(
        "moon-ship",
        "data/generated-assets/moon-aliens/ship.png",
      );
      this.load.image(
        "moon-earth",
        "data/generated-assets/moon-aliens/earth.png",
      );
      const seen = new Set();
      this.load.on("loaderror", (file) => {
        const key = file && file.key;
        if (!key || seen.has(key)) return;
        seen.add(key);
        if (typeof reportSpaceError === "function") {
          reportSpaceError("Phaser image failed to load.", {
            source: "MoonAliensScene",
            asset: file && file.src ? file.src : key,
          });
        }
      });
    }

    create() {
      const { width, height } = this.scale;
      this.cameras.main.setBackgroundColor("#050714");
      this.drawBackdrop(width, height);
      this.drawMoon(width, height);
      this.drawEarth(width);
      this.createShip(width, height);
      this.createAliens(width, height);
      this.createSignalPads(width, height);
      this.createHud(width, height);
      this.input.keyboard?.on("keydown-C", () => this.addSignalByKey("cyan"));
      this.input.keyboard?.on("keydown-G", () => this.addSignalByKey("gold"));
      this.input.keyboard?.on("keydown-V", () => this.addSignalByKey("violet"));
      this.scale.on("resize", this.relayout, this);
      this.events.once("shutdown", () =>
        this.scale.off("resize", this.relayout, this),
      );
      this.playCinematic(width, height);
    }

    relayout() {
      if (!this.sys || !this.sys.isActive()) return;
      const { width, height } = this.scale;
      const short = height < 700;
      const compact = width < 560;
      const baseY = short ? height * 0.64 : height * 0.66;

      if (this.statusText) {
        this.statusText.setStyle({
          wordWrap: { width: Math.min(560, width - 56) },
        });
      }
      if (this.promptText) {
        this.promptText.setPosition(28, height - 92);
        this.promptText.setStyle({
          wordWrap: { width: Math.min(620, width - 56) },
        });
      }
      if (this.sequenceText) this.sequenceText.setPosition(width - 28, 26);
      if (this.recDot) this.recDot.setPosition(width - 34, 76);

      if (this.earth) {
        this.earth.setPosition(
          compact ? width - 48 : width - 92,
          compact ? 148 : 88,
        );
        const earthSize = compact ? 58 : 96;
        this.earth.setDisplaySize(earthSize, earthSize);
      }

      if (this.ship) {
        this.ship.x = width * 0.5;
        if (this.phase !== "cinematic") {
          this.ship.y = height * 0.31;
        }
      }

      if (this.alienGroup) {
        this.alienGroup.x = width * 0.5;
        this.alienGroup.setDisplaySize(
          Math.min(short ? 360 : 520, width * (short ? 0.38 : 0.46)),
          Math.min(short ? 250 : 330, height * (short ? 0.29 : 0.34)),
        );
      }

      if (this.pads && this.pads.length === 3) {
        const padY = Math.min(
          short ? height * 0.74 : height * 0.82,
          height - (short ? 184 : 148),
        );
        const xs = [width * 0.34, width * 0.5, width * 0.66];
        this.pads.forEach((pad, i) => pad.setPosition(xs[i], padY));
        const guideY = padY - (short ? 44 : 58);
        if (this.patternMarkers) {
          this.patternMarkers.forEach((entry, i) => {
            entry.marker.setPosition(width * 0.5 - 70 + i * 70, guideY);
          });
        }
      }

      if (this.phase === "play" || this.phase === "resolved") {
        const signal = MOON_CONTACT_SIGNALS[this.caseIndex];
        if (signal) this.updateSpeakerGlow(signal);
      }
    }

    drawBackdrop(width, height) {
      const stars = this.add.graphics();
      for (let i = 0; i < 140; i += 1) {
        const x = PhaserLib.Math.Between(0, width);
        const y = PhaserLib.Math.Between(0, Math.floor(height * 0.72));
        const alpha = PhaserLib.Math.FloatBetween(0.35, 0.92);
        stars.fillStyle(0xffffff, alpha);
        stars.fillCircle(x, y, PhaserLib.Math.FloatBetween(0.6, 1.8));
      }

      const nebula = this.add.graphics();
      nebula.fillStyle(0x1f6f90, 0.14);
      nebula.fillEllipse(
        width * 0.18,
        height * 0.2,
        width * 0.56,
        height * 0.26,
      );
      nebula.fillStyle(0x8c5bd6, 0.1);
      nebula.fillEllipse(
        width * 0.82,
        height * 0.32,
        width * 0.42,
        height * 0.22,
      );
    }

    drawMoon(width, height) {
      const moon = this.add.graphics();
      moon.fillStyle(0xd9d8ca, 1);
      moon.fillEllipse(width * 0.5, height * 0.92, width * 1.3, height * 0.42);
      moon.fillStyle(0x9d9b8e, 0.35);
      moon.fillEllipse(
        width * 0.22,
        height * 0.83,
        width * 0.16,
        height * 0.035,
      );
      moon.fillEllipse(
        width * 0.62,
        height * 0.88,
        width * 0.22,
        height * 0.045,
      );
      moon.fillEllipse(width * 0.82, height * 0.8, width * 0.13, height * 0.03);
      moon.lineStyle(2, 0xffffff, 0.16);
      moon.strokeEllipse(
        width * 0.5,
        height * 0.93,
        width * 1.34,
        height * 0.46,
      );
    }

    drawEarth(width) {
      const compact = width < 560;
      this.earth = this.add.image(
        compact ? width - 48 : width - 92,
        compact ? 148 : 88,
        "moon-earth",
      );
      const earthSize = compact ? 58 : 96;
      this.earth.setDisplaySize(earthSize, earthSize);
      this.tweens.add({
        targets: this.earth,
        angle: 360,
        duration: 80000,
        repeat: -1,
        ease: "Linear",
      });
    }

    createShip(width, height) {
      this.ship = this.add.container(width * 0.5, -120);
      this.beam = this.add.graphics();
      this.beam.fillStyle(0x77f4ff, 0.12);
      this.beam.fillTriangle(-48, 20, 48, 20, 0, height * 0.58);
      const shipArt = this.add.image(0, -6, "moon-ship");
      const shipWidth = height < 700 ? 222 : 255;
      shipArt.setDisplaySize(shipWidth, shipWidth * 0.67);
      this.ship.add([this.beam, shipArt]);
    }

    createAliens(width, height) {
      const short = height < 700;
      const baseY = short ? height * 0.64 : height * 0.66;
      this.speakerGlow = this.add.graphics();
      this.speakerGlow.fillStyle(0x77f4ff, 0.16);
      this.speakerGlow.fillEllipse(
        width * 0.36,
        baseY - 42,
        short ? 108 : 126,
        short ? 154 : 184,
      );
      this.speakerGlow.lineStyle(2, 0x77f4ff, 0.42);
      this.speakerGlow.strokeEllipse(
        width * 0.36,
        baseY - 42,
        short ? 108 : 126,
        short ? 154 : 184,
      );
      this.alienGroup = this.add.image(width * 0.5, baseY - 26, "moon-aliens");
      this.alienGroup.setDisplaySize(
        Math.min(short ? 360 : 520, width * (short ? 0.38 : 0.46)),
        Math.min(short ? 250 : 330, height * (short ? 0.29 : 0.34)),
      );
      this.tweens.add({
        targets: this.alienGroup,
        y: this.alienGroup.y - 10,
        duration: 1350,
        yoyo: true,
        repeat: -1,
        ease: "Sine.inOut",
      });
      this.aliens = [this.alienGroup];
    }

    createSignalPads(width, height) {
      this.pads = [];
      this.patternMarkers = [];
      const short = height < 700;
      const padY = Math.min(
        short ? height * 0.74 : height * 0.82,
        height - (short ? 184 : 148),
      );
      const entries = [
        ["cyan", width * 0.34],
        ["gold", width * 0.5],
        ["violet", width * 0.66],
      ];
      entries.forEach(([key, x]) => {
        const pad = this.add.container(x, padY);
        const g = this.add.graphics();
        g.fillStyle(MOON_SIGNAL_COLORS[key], 0.2);
        const padW = short ? 72 : 84;
        const padH = short ? 48 : 56;
        g.fillRoundedRect(-padW / 2, -padH / 2, padW, padH, 16);
        g.lineStyle(2, MOON_SIGNAL_COLORS[key], 0.78);
        g.strokeRoundedRect(-padW / 2, -padH / 2, padW, padH, 16);
        const icon = this.add
          .text(0, 0, key === "cyan" ? "◊" : key === "gold" ? "●" : "✦", {
            fontFamily: "Inter, sans-serif",
            fontSize: "28px",
            fontStyle: "700",
            color: "#eef7ff",
          })
          .setOrigin(0.5);
        pad.add([g, icon]);
        pad.setSize(padW, padH);
        pad.signalKey = key;
        pad.setInteractive({ useHandCursor: true });
        pad.on("pointerdown", () => this.addSignal(key, pad));
        this.pads.push(pad);
      });
      const guideY = padY - (short ? 44 : 58);
      [0, 1, 2].forEach((index) => {
        const marker = this.add.container(
          width * 0.5 - 70 + index * 70,
          guideY,
        );
        const bg = this.add.graphics();
        bg.fillStyle(0x10192b, 0.78);
        bg.fillRoundedRect(-27, -17, 54, 34, 12);
        bg.lineStyle(1, 0xffffff, 0.18);
        bg.strokeRoundedRect(-27, -17, 54, 34, 12);
        const dot = this.add.graphics();
        dot.fillStyle(0xffffff, 0.3);
        dot.fillCircle(0, 0, 8);
        const label = this.add
          .text(0, 22, "", {
            fontFamily: "Inter, sans-serif",
            fontSize: "10px",
            fontStyle: "700",
            color: "#eef7ff",
          })
          .setOrigin(0.5);
        marker.add([bg, dot, label]);
        this.patternMarkers.push({ marker, bg, dot, label });
      });
    }

    createHud(width, height) {
      this.titleText = this.add.text(28, 24, "Moon Contact Reel", {
        fontFamily: "Inter, sans-serif",
        fontSize: "18px",
        fontStyle: "700",
        color: "#8feaff",
      });
      this.statusText = this.add.text(28, 52, "Recording lunar arrival...", {
        fontFamily: "Inter, sans-serif",
        fontSize: "32px",
        fontStyle: "700",
        color: "#eef7ff",
        wordWrap: { width: Math.min(560, width - 56) },
      });
      this.promptText = this.add.text(28, height - 92, "", {
        fontFamily: "Inter, sans-serif",
        fontSize: "17px",
        color: "#d6e3f0",
        wordWrap: { width: Math.min(620, width - 56) },
      });
      this.sequenceText = this.add
        .text(width - 28, 26, "", {
          fontFamily: "Inter, sans-serif",
          fontSize: "17px",
          fontStyle: "700",
          color: "#ffd66b",
        })
        .setOrigin(1, 0);
      this.recDot = this.add.graphics();
      this.recDot.fillStyle(0xff5a77, 1);
      this.recDot.fillCircle(0, 0, 5);
      this.recDot.setPosition(width - 34, 76);
      this.tweens.add({
        targets: this.recDot,
        alpha: 0.2,
        duration: 620,
        yoyo: true,
        repeat: -1,
      });
    }

    playCinematic(width, height) {
      this.pads.forEach((pad) => pad.disableInteractive());
      if (skipCinematic) {
        this.ship.y = height * 0.31;
        this.beam.alpha = 0.34;
        this.startRound();
        return;
      }
      this.tweens.add({
        targets: this.ship,
        y: height * 0.31,
        duration: 2200,
        ease: "Sine.out",
        onComplete: () => {
          if (!this.sys || !this.sys.isActive()) return;
          this.cameras.main.flash(220, 119, 244, 255, false);
          this.startRound();
        },
      });
      this.tweens.add({
        targets: this.beam,
        alpha: 0.34,
        duration: 520,
        yoyo: true,
        repeat: 3,
      });
    }

    startRound() {
      this.phase = "play";
      this.sequence = [];
      const signal = MOON_CONTACT_SIGNALS[this.caseIndex];
      this.statusText.setText(signal.label);
      this.promptText.setText(
        `The ${signal.speaker} talks. Tap the pads in this order: ${signal.pattern.join(" / ")}.`,
      );
      this.sequenceText.setText("Reply: --");
      this.updateSpeakerGlow(signal);
      this.updatePatternGuide(signal);
      this.pads.forEach((pad) => pad.setInteractive({ useHandCursor: true }));
      this.scheduleInactivityHint();
      callbacks.onRound?.(signal);
    }

    updateSpeakerGlow(signal) {
      if (!this.speakerGlow) return;
      const { width, height } = this.scale;
      const short = height < 700;
      const baseY = short ? height * 0.64 : height * 0.66;
      const speakerX =
        {
          welcome: width * 0.39,
          trade: width * 0.5,
          map: width * 0.61,
        }[signal.id] || width * 0.5;
      this.speakerGlow.clear();
      this.speakerGlow.fillStyle(MOON_SIGNAL_COLORS[signal.pattern[0]], 0.16);
      this.speakerGlow.fillEllipse(
        speakerX,
        baseY - 42,
        short ? 108 : 126,
        short ? 154 : 184,
      );
      this.speakerGlow.lineStyle(
        3,
        MOON_SIGNAL_COLORS[signal.pattern[0]],
        0.48,
      );
      this.speakerGlow.strokeEllipse(
        speakerX,
        baseY - 42,
        short ? 108 : 126,
        short ? 154 : 184,
      );
      this.tweens.add({
        targets: this.speakerGlow,
        alpha: 0.55,
        duration: 420,
        yoyo: true,
        repeat: 1,
      });
    }

    updatePatternGuide(signal) {
      this.patternMarkers.forEach((entry, index) => {
        const key = signal.pattern[index];
        entry.dot.clear();
        entry.dot.fillStyle(MOON_SIGNAL_COLORS[key], 0.92);
        entry.dot.fillCircle(0, 0, 9);
        entry.label.setText(MOON_SIGNAL_SHORT_LABELS[key]);
        entry.marker.setAlpha(1);
      });
    }

    addSignal(key, pad) {
      if (this.phase !== "play") return;
      const signal = MOON_CONTACT_SIGNALS[this.caseIndex];
      const expected = signal.pattern[this.sequence.length];
      this.pulsePad(pad, key);
      this.scheduleInactivityHint();
      if (key !== expected) {
        this.sequence = [];
        this.sequenceText.setText("Reply: reset");
        this.promptText.setText(
          `The aliens tilt their heads. Try again: ${signal.pattern.join(" / ")}.`,
        );
        this.patternMarkers.forEach((entry) => entry.marker.setAlpha(1));
        this.cameras.main.shake(120, 0.006);
        callbacks.onMiss?.(signal);
        return;
      }

      this.sequence.push(key);
      this.sequenceText.setText(`Reply: ${this.sequence.join(" / ")}`);
      const marker = this.patternMarkers[this.sequence.length - 1];
      if (marker) {
        marker.marker.setAlpha(0.36);
      }
      if (this.sequence.length === signal.pattern.length) {
        this.completeRound(signal);
      }
    }

    addSignalByKey(key) {
      const pad = this.pads.find((item) => item.signalKey === key) || null;
      this.addSignal(key, pad);
    }

    pulsePad(pad, key) {
      if (!pad) return;
      const glow = this.add.graphics();
      glow.fillStyle(MOON_SIGNAL_COLORS[key], 0.32);
      glow.fillCircle(pad.x, pad.y, 44);
      this.tweens.add({
        targets: glow,
        alpha: 0,
        scale: 2,
        duration: 420,
        onComplete: () => glow.destroy(),
      });
      this.tweens.add({ targets: pad, scale: 1.08, yoyo: true, duration: 110 });
    }

    completeRound(signal) {
      this.phase = "resolved";
      this.clearHintTimer();
      this.promptText.setText(signal.reply);
      this.statusText.setText("Contact stable");
      callbacks.onSolved?.(signal);
      this.aliens.forEach((alien, index) => {
        this.tweens.add({
          targets: alien,
          angle: index % 2 === 0 ? -8 : 8,
          duration: 140,
          yoyo: true,
          repeat: 5,
        });
      });
      this.time.delayedCall(1350, () => {
        if (!this.sys || !this.sys.isActive()) return;
        this.caseIndex += 1;
        if (this.caseIndex >= MOON_CONTACT_SIGNALS.length) {
          this.phase = "complete";
          this.statusText.setText("Lunar alliance formed");
          this.promptText.setText(
            "The video reel ends with three alien diplomats waving under Earthrise.",
          );
          this.sequenceText.setText("Archive saved");
          if (this.speakerGlow) this.speakerGlow.clear();
          callbacks.onComplete?.();
          return;
        }
        this.startRound();
      });
    }
  }

  return new PhaserLib.Game({
    type: PhaserLib.AUTO,
    parent: mount,
    width: mount.clientWidth || 960,
    height: mount.clientHeight || 620,
    backgroundColor: "#050714",
    scale: {
      mode: PhaserLib.Scale.RESIZE,
      autoCenter: PhaserLib.Scale.CENTER_BOTH,
    },
    scene: MoonContactScene,
  });
}

function MoonAliensPhaserLevel({ onExit }) {
  const gameRef = useRef(null);
  const mountRef = useRef(null);
  const [runKey, setRunKey] = useState(0);
  const [status, setStatus] = useState("Watch the moon arrival reel, then answer the aliens with signal pads.");
  const [solved, setSolved] = useState(0);
  const [complete, setComplete] = useState(false);

  useEffect(() => {
    if (!mountRef.current) return undefined;
    if (!window.Phaser) {
      setStatus(
        "Phaser did not load. Check the network and refresh this level.",
      );
      return undefined;
    }
    gameRef.current = createMoonAliensPhaserGame(
      mountRef.current,
      {
        onRound: (signal) => {
          setComplete(false);
          setStatus(
            `${signal.speaker} says ${signal.label}. Match the light pattern to answer kindly.`,
          );
          playMoonAlienNarration(signal.audio);
        },
        onMiss: () => {
          setStatus("Signal mismatch. The reply buffer reset.");
          playMoonAlienNarration("game_moon_aliens_try_again.mp3");
        },
        onSolved: (signal) => {
          setSolved((count) => count + 1);
          setStatus(signal.reply);
          playKidSound("chime");
        },
        onComplete: () => {
          setStatus("The moon visitors trust your crew. Archive complete.");
          setComplete(true);
          playKidSound("whoosh");
          playMoonAlienNarration("game_moon_aliens_done.mp3");
        },
      },
      { skipCinematic: runKey > 0 },
    );
    playMoonAlienNarration("game_moon_aliens_start.mp3");
    return () => {
      if (gameRef.current) {
        gameRef.current.destroy(true);
        gameRef.current = null;
      }
      if (window.__narration) window.__narration.stop();
    };
  }, [runKey]);

  const restart = () => {
    setStatus(
      "Watch the moon arrival reel, then answer the aliens with signal pads.",
    );
    setSolved(0);
    setComplete(false);
    setRunKey((key) => key + 1);
  };

  return (
    <section className="moon-aliens-level" aria-label="Aliens on the moon Phaser game">
      <button className="planet-sort-back" onClick={onExit}>
        ← Back to planets
      </button>
      <div className="moon-aliens-frame">
        <div ref={mountRef} className="moon-aliens-game" />
        <div className="moon-aliens-hud">
          <span>Phaser Moon Contact</span>
          <strong>{status}</strong>
          <div className="moon-aliens-progress" aria-label="Signals solved">
            {MOON_CONTACT_SIGNALS.map((signal, index) => (
              <i key={signal.id} className={index < solved ? "on" : ""} />
            ))}
          </div>
          {complete ? (
            <button className="moon-aliens-replay" onClick={restart}>
              Replay
            </button>
          ) : null}
        </div>
      </div>
    </section>
  );
}
