const METEOR_SHIELD_TYPES = {
  ice: {
    label: "Ice",
    key: "1",
    color: 0x7ee7ff,
    asset: "meteorIce",
    hint: "Ice shield cools blue meteors.",
  },
  rock: {
    label: "Rock",
    key: "2",
    color: 0xffb35c,
    asset: "meteorRock",
    hint: "Rock shield blocks orange meteors.",
  },
  dust: {
    label: "Dust",
    key: "3",
    color: 0xcaa6ff,
    asset: "meteorDust",
    hint: "Dust shield scatters violet meteors.",
  },
};

const METEOR_SHIELD_ROUNDS = [
  { type: "ice", lane: 0 },
  { type: "rock", lane: 2 },
  { type: "dust", lane: 1 },
  { type: "rock", lane: 0 },
  { type: "ice", lane: 2 },
  { type: "dust", lane: 0 },
];

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

  class MeteorShieldScene extends PhaserLib.Scene {
    constructor() {
      super("MeteorShieldScene");
      this.roundIndex = 0;
      this.hearts = 4;
      this.phase = "ready";
      this.activeMeteor = null;
      this.selectedShield = "ice";
    }

    preload() {
      this.load.image(
        "meteorIce",
        "data/generated-assets/meteor-shield/meteor-ice.png",
      );
      this.load.image(
        "meteorRock",
        "data/generated-assets/meteor-shield/meteor-rock.png",
      );
      this.load.image(
        "meteorDust",
        "data/generated-assets/meteor-shield/meteor-dust.png",
      );
    }

    create() {
      const { width, height } = this.scale;
      this.cameras.main.setBackgroundColor("#07101d");
      this.drawBackdrop(width, height);
      this.drawBase(width, height);
      this.createLanes(width, height);
      this.createShieldPads(width, height);
      this.createText(width, height);
      const keys = this.input.keyboard?.addKeys({
        ice: PhaserLib.Input.Keyboard.KeyCodes.ONE,
        rock: PhaserLib.Input.Keyboard.KeyCodes.TWO,
        dust: PhaserLib.Input.Keyboard.KeyCodes.THREE,
        fire: PhaserLib.Input.Keyboard.KeyCodes.SPACE,
      });
      keys?.ice.on("down", () => this.chooseShield("ice"));
      keys?.rock.on("down", () => this.chooseShield("rock"));
      keys?.dust.on("down", () => this.chooseShield("dust"));
      keys?.fire.on("down", () => this.fireShield());
      this.scale.on("resize", this.relayout, this);
      this.events.once("shutdown", () => this.scale.off("resize", this.relayout, this));
      this.startRound();
    }

    relayout() {
      if (!this.sys || !this.sys.isActive()) return;
      const { width, height } = this.scale;
      const compact = width < 640 || height < 700;

      if (this.statusText) {
        this.statusText.setPosition(24, compact ? 162 : 150);
        this.statusText.setStyle({
          wordWrap: { width: Math.min(width - 48, compact ? width - 48 : 560) },
        });
      }
      if (this.promptText) {
        this.promptText.setPosition(24, compact ? 212 : 198);
        this.promptText.setStyle({
          wordWrap: { width: Math.min(width - 48, compact ? width - 48 : 620) },
        });
      }
      if (this.scoreText) this.scoreText.setPosition(width - 24, 24);

      if (Array.isArray(this.lanes) && this.lanes.length === 3) {
        const compactLanes = width < 640;
        const spacing = Math.min(compactLanes ? 112 : 190, width * 0.28);
        const startX = width * 0.5 - spacing;
        for (let i = 0; i < 3; i += 1) this.lanes[i] = startX + i * spacing;
      }

      if (this.shieldBubble) {
        this.drawShieldBubble(METEOR_SHIELD_TYPES[this.selectedShield].color, 0.18);
      }

      if (this.pads && this.pads.length === 3) {
        const padY = compact
          ? Math.min(height * 0.72, height - 210)
          : Math.min(height - 118, height * 0.82);
        const gap = compact ? 108 : 156;
        const xs = [width * 0.5 - gap, width * 0.5, width * 0.5 + gap];
        this.pads.forEach((pad, i) => pad.setPosition(xs[i], padY));
      }
      if (this.fireZone) {
        this.fireZone.setPosition(width * 0.5, height * 0.745);
        this.fireZone.setSize(width < 640 ? 260 : 360, width < 640 ? 130 : 170);
      }

      if (this.activeMeteor && this.activeMeteor.container) {
        const lane = this.lanes[this.activeMeteor.lane];
        if (typeof lane === "number") this.activeMeteor.container.x = lane;
      }
    }

    drawBackdrop(width, height) {
      const stars = this.add.graphics();
      for (let i = 0; i < 130; i += 1) {
        stars.fillStyle(0xffffff, PhaserLib.Math.FloatBetween(0.25, 0.82));
        stars.fillCircle(
          PhaserLib.Math.Between(0, width),
          PhaserLib.Math.Between(0, Math.floor(height * 0.72)),
          PhaserLib.Math.FloatBetween(0.7, 1.8),
        );
      }
      const glow = this.add.graphics();
      glow.fillStyle(0x7ee7ff, 0.1);
      glow.fillEllipse(width * 0.5, height * 0.35, width * 0.7, height * 0.28);
    }

    drawBase(width, height) {
      const base = this.add.graphics();
      base.fillStyle(0xcfd3c4, 1);
      base.fillEllipse(width * 0.5, height * 0.94, width * 1.32, height * 0.34);
      base.fillStyle(0x8f948b, 0.3);
      base.fillEllipse(
        width * 0.22,
        height * 0.9,
        width * 0.18,
        height * 0.035,
      );
      base.fillEllipse(width * 0.78, height * 0.88, width * 0.2, height * 0.04);
      base.fillStyle(0x263140, 1);
      base.fillRoundedRect(width * 0.5 - 92, height * 0.76, 184, 54, 14);
      base.fillStyle(0x7ee7ff, 0.22);
      base.fillRoundedRect(width * 0.5 - 68, height * 0.745, 136, 24, 12);
      base.lineStyle(2, 0xeef7ff, 0.25);
      base.strokeRoundedRect(width * 0.5 - 92, height * 0.76, 184, 54, 14);
    }

    createLanes(width, height) {
      this.lanes = [];
      const compact = width < 640;
      const laneY = height * 0.46;
      const spacing = Math.min(compact ? 112 : 190, width * 0.28);
      const startX = width * 0.5 - spacing;
      const guide = this.add.graphics();
      for (let i = 0; i < 3; i += 1) {
        const x = startX + i * spacing;
        this.lanes.push(x);
        guide.lineStyle(2, 0xeef7ff, 0.12);
        guide.beginPath();
        guide.moveTo(x, height * 0.2);
        guide.lineTo(width * 0.5, height * 0.76);
        guide.strokePath();
        guide.fillStyle(0xffffff, 0.1);
        guide.fillCircle(x, laneY, compact ? 22 : 28);
      }
      this.shieldBubble = this.add.graphics();
      this.drawShieldBubble(0x7ee7ff, 0.15);
    }

    drawShieldBubble(color, alpha) {
      const { width, height } = this.scale;
      this.shieldBubble.clear();
      this.shieldBubble.fillStyle(color, alpha);
      this.shieldBubble.fillEllipse(
        width * 0.5,
        height * 0.745,
        width < 640 ? 260 : 360,
        width < 640 ? 130 : 170,
      );
      this.shieldBubble.lineStyle(3, color, 0.38);
      this.shieldBubble.strokeEllipse(
        width * 0.5,
        height * 0.745,
        width < 640 ? 260 : 360,
        width < 640 ? 130 : 170,
      );
    }

    createShieldPads(width, height) {
      this.pads = [];
      const compact = width < 640 || height < 700;
      const padY = compact
        ? Math.min(height * 0.72, height - 210)
        : Math.min(height - 118, height * 0.82);
      const padW = compact ? 104 : 138;
      const padH = compact ? 74 : 82;
      const gap = compact ? 108 : 156;
      this.fireZone = this.add
        .zone(
          width * 0.5,
          height * 0.745,
          width < 640 ? 260 : 360,
          width < 640 ? 130 : 170,
        )
        .setInteractive({ useHandCursor: true });
      this.fireZone.on("pointerdown", () => this.fireShield());
      const entries = [
        ["ice", width * 0.5 - gap],
        ["rock", width * 0.5],
        ["dust", width * 0.5 + gap],
      ];
      entries.forEach(([key, x]) => {
        const info = METEOR_SHIELD_TYPES[key];
        const pad = this.add.container(x, padY);
        const bg = this.add.graphics();
        bg.fillStyle(info.color, 0.18);
        bg.fillRoundedRect(-padW / 2, -padH / 2, padW, padH, 20);
        bg.lineStyle(2, info.color, 0.78);
        bg.strokeRoundedRect(-padW / 2, -padH / 2, padW, padH, 20);
        const label = this.add
          .text(0, -11, info.key, {
            fontFamily: "Inter, sans-serif",
            fontSize: compact ? "24px" : "30px",
            fontStyle: "900",
            color: "#f7fbff",
          })
          .setOrigin(0.5);
        const name = this.add
          .text(0, 20, info.label, {
            fontFamily: "Inter, sans-serif",
            fontSize: compact ? "12px" : "14px",
            fontStyle: "800",
            color: "#dcecff",
          })
          .setOrigin(0.5);
        pad.add([bg, label, name]);
        pad.shieldKey = key;
        pad.bg = bg;
        pad.setSize(padW, padH);
        pad.setInteractive({ useHandCursor: true });
        pad.on("pointerdown", () => {
          this.chooseShield(key);
          if (this.activeMeteor?.type === key) {
            this.fireShield();
          } else if (this.phase === "falling") {
            const expected = METEOR_SHIELD_TYPES[this.activeMeteor.type];
            this.promptText.setText(
              `That picks ${info.label}. This one needs ${expected.label}.`,
            );
          }
        });
        this.pads.push(pad);
      });
    }

    createText(width, height) {
      const compact = width < 640 || height < 700;
      this.titleText = this.add.text(24, 20, "Meteor Shield", {
        fontFamily: "Inter, sans-serif",
        fontSize: compact ? "16px" : "18px",
        fontStyle: "900",
        color: "#7ee7ff",
      });
      this.statusText = this.add.text(
        24,
        compact ? 162 : 150,
        "Match the shield to the meteor.",
        {
          fontFamily: "Inter, sans-serif",
          fontSize: compact ? "21px" : "30px",
          fontStyle: "900",
          color: "#f7fbff",
          wordWrap: { width: Math.min(width - 48, compact ? width - 48 : 560) },
        },
      );
      this.promptText = this.add.text(24, compact ? 212 : 198, "", {
        fontFamily: "Inter, sans-serif",
        fontSize: compact ? "13px" : "16px",
        color: "#dcecff",
        wordWrap: { width: Math.min(width - 48, compact ? width - 48 : 620) },
      });
      this.scoreText = this.add
        .text(width - 24, 24, "", {
          fontFamily: "Inter, sans-serif",
          fontSize: compact ? "13px" : "16px",
          fontStyle: "900",
          color: "#ffdf7e",
        })
        .setOrigin(1, 0);
    }

    startRound() {
      if (this.hearts <= 0) {
        this.phase = "done";
        this.statusText.setText("Base safe enough");
        this.promptText.setText(
          "The crew repairs the shield generator. Replay to try for a clean defense.",
        );
        callbacks.onComplete?.({ saved: this.roundIndex, hearts: this.hearts });
        return;
      }
      if (this.roundIndex >= METEOR_SHIELD_ROUNDS.length) {
        this.phase = "done";
        this.statusText.setText("Moon base protected");
        this.promptText.setText(
          "Every meteor was handled. The shield crew cheers.",
        );
        this.scoreText.setText(`Hearts: ${this.hearts}`);
        callbacks.onComplete?.({ saved: this.roundIndex, hearts: this.hearts });
        return;
      }
      this.phase = "falling";
      const round = METEOR_SHIELD_ROUNDS[this.roundIndex];
      const info = METEOR_SHIELD_TYPES[round.type];
      this.statusText.setText(`${info.label} meteor incoming`);
      this.promptText.setText(
        `${info.hint} Tap the matching shield, or tap the big shield bubble to fire.`,
      );
      this.scoreText.setText(
        `${this.roundIndex}/${METEOR_SHIELD_ROUNDS.length}  Hearts: ${this.hearts}`,
      );
      callbacks.onRound?.(round, this.roundIndex, this.hearts);
      this.spawnMeteor(round);
      this.updatePadSelection();
    }

    spawnMeteor(round) {
      const { width, height } = this.scale;
      const compact = width < 640 || height < 700;
      const info = METEOR_SHIELD_TYPES[round.type];
      const x = this.lanes[round.lane];
      const meteor = this.add.container(x, compact ? height * 0.3 : height * 0.16);
      const body = this.add
        .image(0, 0, info.asset)
        .setOrigin(0.5)
        .setScale(compact ? 0.15 : 0.18)
        .setAngle(-10);
      meteor.add([body]);
      this.activeMeteor = {
        container: meteor,
        type: round.type,
        lane: round.lane,
      };
      this.tweens.add({
        targets: meteor,
        x: width * 0.5,
        y: height * 0.72,
        duration: Math.max(
          2900,
          (compact ? 3900 : 4400) - this.roundIndex * 130,
        ),
        ease: "Sine.in",
        onComplete: () => this.meteorImpact(),
      });
    }

    chooseShield(key) {
      if (this.phase !== "falling") return;
      this.selectedShield = key;
      this.updatePadSelection();
      this.drawShieldBubble(METEOR_SHIELD_TYPES[key].color, 0.16);
    }

    updatePadSelection() {
      this.pads.forEach((pad) => {
        pad.setAlpha(pad.shieldKey === this.selectedShield ? 1 : 0.72);
        pad.setScale(pad.shieldKey === this.selectedShield ? 1.08 : 1);
      });
    }

    fireShield() {
      if (this.phase !== "falling" || !this.activeMeteor) return;
      const meteor = this.activeMeteor;
      if (this.selectedShield !== meteor.type) {
        const expected = METEOR_SHIELD_TYPES[meteor.type];
        this.promptText.setText(
          `${expected.label} shield needed. Pick ${expected.key}, then fire the shield.`,
        );
        this.cameras.main.shake(80, 0.002);
        return;
      }
      this.phase = "resolved";
      this.tweens.killTweensOf(meteor.container);
      this.burstMeteor(
        meteor.container,
        METEOR_SHIELD_TYPES[meteor.type].color,
      );
      this.roundIndex += 1;
      this.scoreText.setText(
        `${this.roundIndex}/${METEOR_SHIELD_ROUNDS.length}  Hearts: ${this.hearts}`,
      );
      callbacks.onSolved?.(this.roundIndex, this.hearts);
      this.time.delayedCall(560, () => {
        if (!this.sys || !this.sys.isActive()) return;
        this.startRound();
      });
    }

    meteorImpact() {
      if (!this.sys || !this.sys.isActive()) return;
      if (this.phase !== "falling" || !this.activeMeteor) return;
      this.hearts = Math.max(0, this.hearts - 1);
      const meteor = this.activeMeteor.container;
      this.activeMeteor = null;
      this.burstMeteor(meteor, 0xff6b7c);
      this.statusText.setText("Meteor bumped the shield");
      this.promptText.setText(
        "The base is still standing. Match the next shield sooner.",
      );
      this.scoreText.setText(
        `${this.roundIndex}/${METEOR_SHIELD_ROUNDS.length}  Hearts: ${this.hearts}`,
      );
      callbacks.onMiss?.(this.hearts, null);
      this.time.delayedCall(720, () => {
        if (!this.sys || !this.sys.isActive()) return;
        this.startRound();
      });
    }

    burstMeteor(meteor, color) {
      const x = meteor.x;
      const y = meteor.y;
      meteor.destroy();
      this.activeMeteor = null;
      for (let i = 0; i < 14; i += 1) {
        const spark = this.add.graphics();
        spark.fillStyle(color, 1);
        spark.fillCircle(0, 0, PhaserLib.Math.Between(2, 4));
        spark.setPosition(x, y);
        const angle = PhaserLib.Math.FloatBetween(0, Math.PI * 2);
        const distance = PhaserLib.Math.Between(28, 88);
        this.tweens.add({
          targets: spark,
          x: x + Math.cos(angle) * distance,
          y: y + Math.sin(angle) * distance,
          alpha: 0,
          duration: 520,
          onComplete: () => spark.destroy(),
        });
      }
    }
  }

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

function MeteorShieldPhaserLevel({ onExit }) {
  const gameRef = useRef(null);
  const mountRef = useRef(null);
  const [runKey, setRunKey] = useState(0);
  const [status, setStatus] = useState("Match each meteor with the right shield color.");
  const [saved, setSaved] = useState(0);
  const [hearts, setHearts] = useState(4);
  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 = createMeteorShieldGame(mountRef.current, {
      onRound: (round, index, nextHearts) => {
        const info = METEOR_SHIELD_TYPES[round.type];
        setComplete(false);
        setHearts(nextHearts);
        setStatus(
          `${info.label} meteor in lane ${round.lane + 1}. Choose ${info.label} shield.`,
        );
      },
      onMiss: (nextHearts, expectedType) => {
        setHearts(nextHearts);
        setStatus(
          expectedType
            ? `${METEOR_SHIELD_TYPES[expectedType].label} shield needed. Hearts left: ${nextHearts}.`
            : `Meteor impact. Hearts left: ${nextHearts}.`,
        );
        playKidSound("boop");
      },
      onSolved: (count, nextHearts) => {
        setSaved(count);
        setHearts(nextHearts);
        setStatus(`Meteor ${count} blocked. Shields holding.`);
        playKidSound("chime");
      },
      onComplete: (result) => {
        setSaved(result.saved);
        setHearts(result.hearts);
        setComplete(true);
        setStatus(
          result.hearts > 0
            ? `Moon base protected with ${result.hearts} hearts left.`
            : "Base survived, but the crew wants a cleaner replay.",
        );
        playKidSound("whoosh");
      },
    });
    return () => {
      if (gameRef.current) {
        gameRef.current.destroy(true);
        gameRef.current = null;
      }
      if (window.__narration) window.__narration.stop();
    };
  }, [runKey]);

  const restart = () => {
    setStatus("Match each meteor with the right shield color.");
    setSaved(0);
    setHearts(4);
    setComplete(false);
    setRunKey((key) => key + 1);
  };

  return (
    <section className="meteor-shield-level" aria-label="Meteor Shield Phaser game">
      <button className="planet-sort-back" onClick={onExit}>
        Back to planets
      </button>
      <div className="meteor-shield-frame">
        <div ref={mountRef} className="meteor-shield-game" />
        <div className="meteor-shield-hud">
          <span>Phaser Meteor Shield</span>
          <strong>{status}</strong>
          <div className="meteor-shield-progress" aria-label="Meteors blocked">
            {METEOR_SHIELD_ROUNDS.map((round, index) => (
              <i key={`${round.type}-${index}`} className={index < saved ? "on" : ""} />
            ))}
          </div>
          <em aria-label="Shield hearts">Hearts: {hearts}</em>
          {complete ? (
            <button className="meteor-shield-replay" onClick={restart}>
              Replay
            </button>
          ) : null}
        </div>
      </div>
    </section>
  );
}
