"use strict";

const DEBUG_HITBOX = false;

const bgmList = [
  { normal: "music/Scary.mp3", gameover: "music/ScaryGO.mp3" },
  { normal: "music/Fear.mp3", gameover: "music/FearGO.mp3" },
  { normal: "music/Chill.mp3", gameover: "music/ChillGO.mp3" },
];

let currentBGM = new Audio();
let gameOverBGM = new Audio();
currentBGM.loop = true;
gameOverBGM.loop = true;

function pickRandomBGM() {
  const bgm = bgmList[Math.floor(Math.random() * bgmList.length)];
  currentBGM.src = bgm.normal;
  gameOverBGM.src = bgm.gameover;
}

var canvasWidth = 1280;
var canvasHeight = 720;
var worldHeight = 900;
var c, ctx;
var gameStarted = false;
var musicMuted = false;

let vignetteCanvas = null;

let lastFrameTime = 0;
const frameInterval = 1000 / 90;

let cameraY = 0;

let respawnCounter = 0;
let damageFlash = 0;

let currentWave = null;
let waveCooldown = 0;

let abilityCharges = 0;
let missileAmmo = 0;

var game = {
  level: 1,
  speed: 1,
  gameOver: false,
  frames: 0,
  timer: 0,
  surge: 1.0,
  surgePhase: 0,
  surgeTimer: 0,
  surgeCooldown: 2400, // Start with 40s cooldown
};

var keys = {
  up: false,
  down: false,
  left: false,
  right: false,
  fire: false,
};

// --- LOAD IMAGES ---
var playerShipImg = new Image();
playerShipImg.src = "img/Player/pesawat22.png";

// --- GAMBAR PICKUP SKILLS ---
var missilePickupImg = new Image();
missilePickupImg.src = "img/Skills/missile.png";

var laserPickupImg = new Image();
laserPickupImg.src = "img/Skills/double-missile.png";

// *** GAMBAR BARU UNTUK PICKUP BOMB ***
var bombPickupImg = new Image();
// Pastikan file gambar bom clay Anda disimpan di sini
bombPickupImg.src = "img/Skills/bomb.png";

var livesImg = new Image();
livesImg.src = "img/Player/lives.png";

var bg0 = new Image();
bg0.src = "img/bg_0.png";
var bg1 = new Image();
bg1.src = "img/bg_1.png";
var bg2 = new Image();
bg2.src = "img/bg_2.png";

var enemyImgArray = [];
enemyImgArray.length = 4;

let audioStarted = false;

window.addEventListener("keydown", () => {
  if (!audioStarted) {
    currentBGM.play().catch(() => { });
    audioStarted = true;
  }
});

window.addEventListener("click", () => {
  if (!audioStarted) {
    currentBGM.play().catch(() => { });
    audioStarted = true;
  }
});

for (var i = 0; i < enemyImgArray.length; i++) {
  enemyImgArray[i] = new Image();
  enemyImgArray[i].src = "img/alien_" + [i] + ".png";
}

var missilesArray = [];
var playerMissilesArray = [];
var enemyShipArray = [];
var enemyBulletsArray = [];
var explosions = [];
var abilityTokens = [];
var particles = [];

var laser = document.createElement("audio");
laser.src = "music/laser2.mp3";

var explosion_enemy = document.createElement("audio");
explosion_enemy.src = "music/explosion-small.mp3";

var planetImages = [];
for (let i = 1; i <= 4; i++) {
  let img = new Image();
  img.src = `img/SpritesPlanet/planet_${i}.png`;
  planetImages.push(img);
}

let currentPlanet = null;

let laserSprite, enemyBulletSprite, missileSprite;

function preRenderAssets() {
  // 1. CACHE LASER BULLET
  // Padding for shadowBlur (15px)
  const lPad = 20;
  const lW = 13 + lPad * 2;
  const lH = 4 + lPad * 2;
  laserSprite = document.createElement("canvas");
  laserSprite.width = lW;
  laserSprite.height = lH;
  const lCtx = laserSprite.getContext("2d");

  let lg = lCtx.createLinearGradient(lPad, lPad, lPad + 13, lPad);
  lg.addColorStop(0, "#00e1ff");
  lg.addColorStop(0.5, "#ffffff");
  lg.addColorStop(1, "#00e1ff");

  lCtx.fillStyle = lg;
  lCtx.shadowColor = "#00ffff";
  lCtx.shadowBlur = 15;
  lCtx.fillRect(lPad, lPad, 13, 4);


  // 2. CACHE ENEMY BULLET
  const ePad = 15;
  const eW = 10 + ePad * 2;
  const eH = 4 + ePad * 2;
  enemyBulletSprite = document.createElement("canvas");
  enemyBulletSprite.width = eW;
  enemyBulletSprite.height = eH;
  const eCtx = enemyBulletSprite.getContext("2d");

  let eg = eCtx.createLinearGradient(ePad + 10, ePad, ePad, ePad); // Right to Left
  eg.addColorStop(0, "#ff9900");
  eg.addColorStop(0.5, "#ffffff");
  eg.addColorStop(1, "#ff3300");

  eCtx.fillStyle = eg;
  eCtx.shadowColor = "#ff6600";
  eCtx.shadowBlur = 10;
  eCtx.fillRect(ePad, ePad, 10, 4);


  // 3. CACHE PLAYER MISSILE (Body Only)
  const mPad = 5;
  const mW = 30 + mPad * 2;
  const mH = 12 + mPad * 2;
  missileSprite = document.createElement("canvas");
  missileSprite.width = mW;
  missileSprite.height = mH;
  const mCtx = missileSprite.getContext("2d");

  let mg = mCtx.createLinearGradient(mPad, mPad, mPad + 30, mPad);
  mg.addColorStop(0, "#00008b");
  mg.addColorStop(0.5, "#4169e1");
  mg.addColorStop(1, "#ffffff");

  mCtx.fillStyle = mg;
  mCtx.beginPath();
  mCtx.moveTo(mPad, mPad);
  mCtx.lineTo(mPad + 30, mPad + 6); // height/2
  mCtx.lineTo(mPad, mPad + 12);     // height
  mCtx.fill();
}

window.onload = function () {
  init();
};

function init() {
  preRenderAssets(); // Generate sprites before game starts
  c = document.getElementById("canvas");

  ctx = c.getContext("2d", { alpha: false });

  c.width = canvasWidth;
  c.height = canvasHeight;

  document.addEventListener("keydown", keyDownPressed, false);
  document.addEventListener("keyup", keyUpPressed, false);

  document.addEventListener("contextmenu", (event) => event.preventDefault());

  gameStarted = true;
  pickRandomBGM();
  currentBGM.volume = 1;

  requestAnimationFrame(gameLoop);
}

function gameLoop(timestamp) {
  if (!gameStarted) return;

  if (game.gameOver) {
    clearGame();
    drawGameOver();
    return;
  }

  if (timestamp - lastFrameTime >= frameInterval) {
    lastFrameTime = timestamp;

    if (!gamePaused) {
      clearGame();
      updateGame();
      drawGame();
    } else {
      drawPauseOverlay();
    }
  }

  requestAnimationFrame(gameLoop);
}

let gamePaused = false;

function keyDownPressed(e) {
  if (e.keyCode === 87 || e.keyCode === 38) keys.up = true;
  else if (e.keyCode === 83 || e.keyCode === 40) keys.down = true;
  if (e.keyCode === 65 || e.keyCode === 37) keys.left = true;
  if (e.keyCode === 68 || e.keyCode === 39) keys.right = true;

  if (e.keyCode === 32) {
    keys.fire = true;
    if (!player1.dead) {
      fireBullet();
    }
  }

  if (e.keyCode === 80) togglePause();

  if (e.keyCode === 16) {
    if (abilityCharges > 0 && !game.gameOver && !gamePaused && !player1.dead) {
      useAbility();
      abilityCharges--;
    }
  }

  if (e.keyCode === 81) {
    // Q
    if (!game.gameOver && !gamePaused && !player1.dead) {
      firePlayerMissile();
    }
  }
}

function keyUpPressed(e) {
  if (e.keyCode === 87 || e.keyCode === 38) keys.up = false;
  else if (e.keyCode === 83 || e.keyCode === 40) keys.down = false;
  if (e.keyCode === 65 || e.keyCode === 37) keys.left = false;
  if (e.keyCode === 68 || e.keyCode === 39) keys.right = false;
  if (e.keyCode === 32) keys.fire = false;
}

function fireBullet() {
  if (player1.doubleLaserTimer > 0) {
    missilesArray.push(
      new LaserBullet(
        player1.x + player1.width,
        player1.y + player1.height / 2 - 15
      )
    );
    missilesArray.push(
      new LaserBullet(
        player1.x + player1.width,
        player1.y + player1.height / 2 + 15
      )
    );
  } else {
    missilesArray.push(
      new LaserBullet(player1.x + player1.width, player1.y + player1.height / 2)
    );
  }

  laser.currentTime = 0;
  // IMPORTANT!! EXPERIMENT WITH THIS VALUE
  laser.volume = 0.2;
  laser.play();
  createParticles(
    player1.x + player1.width,
    player1.y + player1.height / 2,
    5,
    "#00e1ff"
  );
}

function firePlayerMissile() {
  if (missileAmmo > 0) {
    missileAmmo--;
    playerMissilesArray.push(
      new PlayerMissile(
        player1.x + player1.width,
        player1.y + player1.height / 2 - 10
      )
    );

    let sfx = explosion_enemy.cloneNode();
    sfx.volume = 0.5;
    sfx.playbackRate = 2.0;
    sfx.play();
  }
}

function clearGame() {
  ctx.clearRect(0, 0, canvasWidth, canvasHeight);
}

function updateGame() {
  game.frames++;

  updateSurge();

  // Base speed + Surge
  game.level = 1 + Math.floor(player1.score / 500);
  let baseSpeed = 1 + game.level * 0.1;
  game.speed = baseSpeed * game.surge;

  updateStarField();

  addShips();
  maybeSpawnAbilityToken();

  if (keys.fire && !player1.dead && game.frames % 8 === 0) {
    fireBullet();
  }

  if (!player1.dead) {
    player1.update();
    if (player1.invincible > 0) player1.invincible--;
    updateCamera();
  } else {
    if (respawnCounter > 0) {
      respawnCounter--;
      if (respawnCounter <= 0 && player1.lives > 0) {
        player1.dead = false;
        player1.invincible = 120;
        player1.x = 100;
        player1.y = canvasHeight / 2 - player1.height / 2;
        player1.vx = 0;
        player1.vy = 0;
        player1.doubleLaserTimer = 0;
      }
    }
  }

  spawnPlanet();
  if (currentPlanet) currentPlanet.update();

  updateParticles();
}

function drawGame() {
  ctx.save();



  ctx.translate(0, cameraY);

  drawStarField();

  if (currentPlanet) currentPlanet.draw();

  drawParticles();

  for (let i = 0; i < abilityTokens.length; i++) {
    const t = abilityTokens[i];
    t.draw();
    t.update();

    if (
      !player1.dead &&
      Tabrakan(player1.getHitbox(), {
        x: t.x,
        y: t.y,
        width: t.width,
        height: t.height,
      })
    ) {
      if (t.type === "bomb") {
        abilityCharges++;
        createParticles(t.x, t.y, 15, "#ffff00");
      } else if (t.type === "double") {
        player1.doubleLaserTimer = 600;
        createParticles(t.x, t.y, 15, "#ff0000");
      } else if (t.type === "missile") {
        missileAmmo += 3;
        createParticles(t.x, t.y, 15, "#0000ff");
      }

      abilityTokens.splice(i, 1);
      i--;
      continue;
    }

    if (t.x + t.width < 0) {
      abilityTokens.splice(i, 1);
      i--;
    }
  }

  if (!player1.dead) {
    player1.draw();
    if (DEBUG_HITBOX) drawDebugHitbox(player1.getHitbox(), "lime");
  }

  for (let i = 0; i < enemyShipArray.length; i++) {
    let s = enemyShipArray[i];
    s.draw();
    s.update();

    if (DEBUG_HITBOX) drawDebugHitbox(s.getHitbox(), "red");

    if (s.x < -200) {
      enemyShipArray.splice(i, 1);
      i--;
      continue;
    }

    let shootChance = 0.005 + game.level * 0.0012;
    if (shootChance > 0.04) shootChance = 0.04;

    if (!player1.dead && Math.random() < shootChance && s.x > player1.x + 50) {
      const ex = s.x;
      const ey = s.y + s.height / 2;

      const px = player1.x + player1.width / 2;
      const py = player1.y + player1.height / 2;
      enemyBulletsArray.push(new EnemyBullet(ex, ey, px, py));
    }

    if (!player1.dead && Tabrakan(player1.getHitbox(), s.getHitbox())) {
      explosions.push(new Explosion(s.x + s.width / 2, s.y + s.height / 2));
      createParticles(s.x + s.width / 2, s.y + s.height / 2, 20, "#ff6600");
      enemyShipArray.splice(i, 1);
      i--;
      handlePlayerHit();
      continue;
    }
  }

  for (let i = 0; i < missilesArray.length; i++) {
    let m = missilesArray[i];
    m.draw();
    m.update();

    if (DEBUG_HITBOX) drawDebugHitbox(m.getHitbox(), "cyan");

    let hit = false;
    for (let j = 0; j < enemyShipArray.length; j++) {
      let en = enemyShipArray[j];

      if (Tabrakan(m.getHitbox(), en.getHitbox())) {
        let playerDamage = 100 + game.level * 5;
        en.health -= playerDamage;

        createParticles(
          en.x + en.width / 2,
          en.y + en.height / 2,
          5,
          "#ff9900"
        );
        missilesArray.splice(i, 1);
        hit = true;

        if (en.health <= 0) {
          player1.score += 100 + game.level * 10;
          explosion_enemy.currentTime = 0;
          explosion_enemy.play();
          explosions.push(
            new Explosion(en.x + en.width / 2, en.y + en.height / 2)
          );
          enemyShipArray.splice(j, 1);
        }
        break;
      }
    }

    if (hit) {
      i--;
      continue;
    }

    if (m.x > canvasWidth + 50) {
      missilesArray.splice(i, 1);
      i--;
    }
  }

  for (let i = 0; i < playerMissilesArray.length; i++) {
    let pm = playerMissilesArray[i];
    pm.draw();
    pm.update();

    let hit = false;
    for (let j = 0; j < enemyShipArray.length; j++) {
      let en = enemyShipArray[j];

      if (Tabrakan(pm.getHitbox(), en.getHitbox())) {
        let missileDmg = 400 + game.level * 20;
        en.health -= missileDmg;

        createParticles(pm.x + pm.width, pm.y, 20, "#0000ff");
        explosions.push(new Explosion(pm.x + pm.width, pm.y, 0.5));

        playerMissilesArray.splice(i, 1);
        hit = true;

        if (en.health <= 0) {
          player1.score += 100 + game.level * 10;
          explosion_enemy.currentTime = 0;
          explosion_enemy.play();
          explosions.push(
            new Explosion(en.x + en.width / 2, en.y + en.height / 2)
          );
          enemyShipArray.splice(j, 1);
        }
        break;
      }
    }

    if (hit) {
      i--;
      continue;
    }

    if (pm.x > canvasWidth + 200 || pm.y < -200 || pm.y > worldHeight + 200) {
      playerMissilesArray.splice(i, 1);
      i--;
    }
  }

  for (let i = 0; i < enemyBulletsArray.length; i++) {
    let b = enemyBulletsArray[i];
    b.draw();
    b.update();

    if (DEBUG_HITBOX) drawDebugHitbox(b.getHitbox(), "orange");

    if (!player1.dead && Tabrakan(b.getHitbox(), player1.getHitbox())) {
      explosions.push(
        new Explosion(
          player1.x + player1.width / 2,
          player1.y + player1.height / 2
        )
      );
      createParticles(
        player1.x + player1.width / 2,
        player1.y + player1.height / 2,
        12,
        "#ff3300"
      );
      enemyBulletsArray.splice(i, 1);
      i--;
      handlePlayerHit();
      continue;
    }

    if (
      b.x + b.width < -100 ||
      b.x > canvasWidth + 100 ||
      b.y + b.height < -100 ||
      b.y > worldHeight + 100
    ) {
      enemyBulletsArray.splice(i, 1);
      i--;
    }
  }

  for (let i = 0; i < explosions.length; i++) {
    let ex = explosions[i];
    ex.draw();
    ex.update();
    if (ex.done) {
      explosions.splice(i, 1);
      i--;
    }
  }

  ctx.restore();

  drawScreenShading();
  drawUI();
}

function drawDebugHitbox(rect, color) {
  ctx.save();
  ctx.strokeStyle = color;
  ctx.lineWidth = 2;
  ctx.strokeRect(rect.x, rect.y, rect.width, rect.height);
  ctx.restore();
}

function drawUI() {
  drawNewText(
    player1.score,
    canvasWidth - 140,
    canvasHeight - 50,
    "white",
    "30px"
  );
  drawNewText(game.level, canvasWidth - 140, 50, "#00ff00", "30px");

  // Lives (Stacked Icons)
  const lifeSize = 40; // Scaled down from 104px source
  const lifePadding = 5;

  if (livesImg.complete) {
    for (let i = 0; i < player1.lives; i++) {
      ctx.drawImage(livesImg, 30 + i * (lifeSize + lifePadding), canvasHeight - 60, lifeSize, lifeSize);
    }
  } else {
    // Fallback if image not loaded
    let livesText = "Lives:  ";
    for (let i = 0; i < player1.lives; i++) {
      livesText += "♥ ";
    }
    drawNewText(livesText, 30, canvasHeight - 50, "#ff3366");
  }

  // Bombs (Shift)
  const iconSize = 32;
  const padding = 10;

  if (bombPickupImg.complete) {
    ctx.drawImage(bombPickupImg, 30, 30, iconSize, iconSize);
    drawNewText("x " + abilityCharges, 30 + iconSize + padding, 30 + 24, "#ffff00");
  } else {
    drawNewText("Bombs: " + abilityCharges, 30, 50, "#ffff00");
  }

  // Missiles (Q)
  if (missilePickupImg.complete) {
    ctx.drawImage(missilePickupImg, 30, 70, iconSize, iconSize);
    drawNewText("x " + missileAmmo, 30 + iconSize + padding, 70 + 24, "#00ccff");
  } else {
    drawNewText("Missiles: " + missileAmmo, 30, 85, "#00ccff");
  }
}

class PlayerObject {
  constructor(x, y) {
    this.x = x;
    this.y = y;
    this.width = 100;
    this.height = 64;
    this.image = playerShipImg;

    this.vx = 0;
    this.vy = 0;
    this.acceleration = 0.8;
    this.friction = 0.92;
    this.maxSpeed = 10;

    this.lives = 6;
    this.score = 0;
    this.health = 100;
    this.invincible = 0;
    this.dead = false;

    this.doubleLaserTimer = 0;

    this.totalFrames = 5;
    this.frameIndex = 2;
    this.spriteWidth = 0;
    this.sourceHeight = 0;
    this.scale = 1.0;

    this.image.onload = () => {
      this.spriteWidth = this.image.width / this.totalFrames;
      this.sourceHeight = this.image.height;
      this.width = this.spriteWidth * this.scale;
      this.height = this.sourceHeight * this.scale;
      this.y = canvasHeight / 2 - this.height / 2;
    };
  }

  getHitbox() {
    const h = this.height * 0.05;

    const w = this.width * 0.8;

    const x = this.x + (this.width - w) / 2;
    const y = this.y + (this.height - h) / 2;

    return { x, y, width: w, height: h };
  }
  draw() {
    if (this.invincible > 0 && game.frames % 10 < 5) {
      return;
    }

    ctx.save();

    if (this.spriteWidth > 0) {
      ctx.drawImage(
        this.image,
        this.frameIndex * this.spriteWidth,
        0,
        this.spriteWidth,
        this.sourceHeight,
        this.x,
        this.y,
        this.width,
        this.height
      );
    } else {
      ctx.fillStyle = "red";
      ctx.fillRect(this.x, this.y, 50, 50);
    }

    ctx.restore();
  }

  update() {
    if (keys.up) this.vy -= this.acceleration;
    if (keys.down) this.vy += this.acceleration;
    if (keys.left) this.vx -= this.acceleration;
    if (keys.right) this.vx += this.acceleration;

    this.vx *= this.friction;
    this.vy *= this.friction;

    const speed = Math.sqrt(this.vx * this.vx + this.vy * this.vy);
    if (speed > this.maxSpeed) {
      const scale = this.maxSpeed / speed;
      this.vx *= scale;
      this.vy *= scale;
    }

    this.x += this.vx;
    this.y += this.vy;

    const bleedY = this.height * 0.4;
    const bleedX = this.width * 0.4;

    if (this.y < -bleedY) {
      this.y = -bleedY;
      if (this.vy < 0) this.vy = 0;
    }
    if (this.y > worldHeight - this.height + bleedY) {
      this.y = worldHeight - this.height + bleedY;
      if (this.vy > 0) this.vy = 0;
    }

    if (this.x < -bleedX) {
      this.x = -bleedX;
      if (this.vx < 0) this.vx = 0;
    }
    if (this.x > canvasWidth - this.width + bleedX) {
      this.x = canvasWidth - this.width + bleedX;
      if (this.vx > 0) this.vx = 0;
    }

    if (this.vy < -2.5) {
      this.frameIndex = 4;
    } else if (this.vy < -0.5) {
      this.frameIndex = 3;
    } else if (this.vy > 2.5) {
      this.frameIndex = 0;
    } else if (this.vy > 0.5) {
      this.frameIndex = 1;
    } else {
      this.frameIndex = 2;
    }

    if (this.doubleLaserTimer > 0) {
      this.doubleLaserTimer--;
    }
  }
}

let player1 = new PlayerObject(100, 300);

function handlePlayerHit() {
  if (player1.invincible > 0 || player1.dead || game.gameOver) return;

  explosion_enemy.currentTime = 0;
  explosion_enemy.play();
  damageFlash = 20;

  player1.lives--;

  if (player1.lives <= 0) {
    game.gameOver = true;
    crossfadeToGameOver();
    return;
  }

  player1.dead = true;
  respawnCounter = 80 * 3;
}

function drawNewText(txt, x, y, color, fontSize = "20px") {
  ctx.font = fontSize + " 'Orbitron', sans-serif";
  ctx.fillStyle = color;
  ctx.textAlign = "left";
  ctx.fillText(txt, x, y);
}

class backgroundObj {
  constructor(img, x, y, speed) {
    this.x = x;
    this.y = y;
    this.width = 2000;
    this.height = 900;
    this.img = img;
    this.img = img;
    this.factor = speed; // Rename speed to factor for parallax
  }
  draw() {
    ctx.save();
    ctx.drawImage(this.img, this.x, this.y, this.width, this.height);
    ctx.restore();
  }

  update() {
    this.x -= this.factor * game.speed;
    if (this.x < -2000) {
      this.x = 2000;
    }
  }
}

let background1 = new backgroundObj(bg0, 0, 0, 3);
let background1a = new backgroundObj(bg0, 2000, 0, 3);
let background2 = new backgroundObj(bg1, 0, 0, 2);
let background2a = new backgroundObj(bg1, 2000, 0, 2);
let background3 = new backgroundObj(bg2, 0, 0, 1);
let background3a = new backgroundObj(bg2, 2000, 0, 1);

function updateStarField() {
  background3.update();
  background3a.update();
  background2.update();
  background2a.update();
  background1.update();
  background1a.update();
}

function drawStarField() {
  background3.draw();
  background3a.draw();
  background2.draw();
  background2a.draw();
  background1.draw();
  background1a.draw();
}

function updateCamera() {
  const offset = player1.y + player1.height / 2 - canvasHeight / 2;
  const target = -offset * 0.7;
  const bgHeight = worldHeight;
  const minY = canvasHeight - bgHeight;
  const maxY = 0;

  const clamped = Math.max(minY, Math.min(maxY, target));
  cameraY += (clamped - cameraY) * 0.1;
}

class LaserBullet {
  constructor(x, y) {
    this.x = x;
    this.y = y;
    this.width = 13;
    this.height = 4;
    this.speed = 16;
  }

  getHitbox() {
    return { x: this.x, y: this.y, width: this.width, height: this.height };
  }

  draw() {
    const padding = 20;
    ctx.drawImage(laserSprite, this.x - padding, this.y - padding);
  }

  update() {
    this.x += this.speed;
  }
}

class PlayerMissile {
  constructor(x, y) {
    this.x = x;
    this.y = y;
    this.width = 30;
    this.height = 12;
    this.speed = 2;
    this.maxSpeed = 18;
    this.vx = 2;
    this.vy = 0;
    this.target = null;
  }

  getHitbox() {
    return { x: this.x, y: this.y, width: this.width, height: this.height };
  }

  draw() {
    ctx.save();

    // Draw Cached Missile Body
    const padding = 5;
    ctx.drawImage(missileSprite, this.x - padding, this.y - padding);

    // TRAIL BIRU LANGIT
    if (Math.random() < 0.5) {
      createParticles(this.x, this.y + this.height / 2, 2, "#00bfff");
    }
    ctx.restore();
  }

  update() {
    this.speed *= 1.08;
    if (this.speed > this.maxSpeed) this.speed = this.maxSpeed;

    if (!this.target || !enemyShipArray.includes(this.target)) {
      let minDist = 100000;
      let closest = null;
      for (let e of enemyShipArray) {
        let dx = e.x - this.x;
        let dy = e.y - this.y;
        let d = Math.sqrt(dx * dx + dy * dy);
        if (d < minDist) {
          minDist = d;
          closest = e;
        }
      }
      this.target = closest;
    }

    if (this.target) {
      let tx = this.target.x + this.target.width / 2;
      let ty = this.target.y + this.target.height / 2;
      let dx = tx - this.x;
      let dy = ty - this.y;
      let angle = Math.atan2(dy, dx);

      this.vx = Math.cos(angle) * this.speed;
      this.vy = Math.sin(angle) * this.speed;
    } else {
      this.vx = this.speed;
      this.vy = 0;
    }

    this.x += this.vx;
    this.y += this.vy;
  }
}

class EnemyObj {
  constructor(x, y, speed, img, pattern = "straight") {
    this.x = x;
    this.y = y;
    this.width = 145;
    this.height = 90;
    this.image = img;
    this.speed = speed;
    this.health = 100;
    this.damage = 10;
    this.pattern = pattern;
    this.angle = 0;
  }

  getHitbox() {
    const w = this.width * 0.55;
    const h = this.height * 0.55;
    const x = this.x + (this.width - w) / 2;
    const y = this.y + (this.height - h) / 2;
    return { x, y, width: w, height: h };
  }

  draw() {
    ctx.save();
    ctx.drawImage(this.image, this.x, this.y, this.width, this.height);
    ctx.restore();
  }

  update() {
    this.x -= this.speed;
    if (this.pattern === "sine") {
      this.angle += 0.05 * this.speed;
      this.y += Math.sin(this.angle) * 3;
    }
  }
}

class EnemyBullet {
  constructor(x, y, targetX, targetY) {
    this.x = x;
    this.y = y;
    this.width = 10;
    this.height = 4;

    const dx = targetX - x;
    const dy = targetY - y;
    const len = Math.sqrt(dx * dx + dy * dy) || 1;
    // bullet speedd - mark
    const speed = 5;

    this.vx = (dx / len) * speed;
    this.vy = (dy / len) * speed;
  }

  getHitbox() {
    const padding = 1;
    return {
      x: this.x + padding,
      y: this.y + padding,
      width: this.width - padding * 2,
      height: this.height - padding * 2,
    };
  }

  draw() {
    const padding = 15;
    ctx.drawImage(enemyBulletSprite, this.x - padding, this.y - padding);
  }

  update() {
    this.x += this.vx;
    this.y += this.vy;
  }
}

class Planet {
  constructor(img) {
    this.image = img;
    this.width = 160;
    this.height = 160;
    this.x = canvasWidth + 50;
    this.y = Math.random() * 300 + 50;
    this.speed = 1.2;
    this.active = true;
  }

  draw() {
    ctx.drawImage(this.image, this.x, this.y, this.width, this.height);
  }

  update() {
    this.x -= this.speed * game.surge;
    if (this.x < -this.width) {
      this.active = false;
    }
  }
}

function spawnPlanet() {
  if (currentPlanet == null || currentPlanet.active === false) {
    let randomImg =
      planetImages[Math.floor(Math.random() * planetImages.length)];
    currentPlanet = new Planet(randomImg);
  }
}

function addShips() {
  if (game.frames < 200) return;

  if (currentWave) {
    if (currentWave.spawned < currentWave.count) {
      if (currentWave.spawnTimer <= 0) {
        spawnEnemyFromWave(currentWave);
        currentWave.spawned++;
        // --- RANDOM SPACING ---
        let randomSpacing =
          currentWave.spacing + Math.floor(Math.random() * 30);
        currentWave.spawnTimer = randomSpacing;
      } else {
        currentWave.spawnTimer--;
      }
    } else {
      if (enemyShipArray.length === 0) {
        currentWave = null;
        waveCooldown = Math.max(60, 120 - game.level * 2);
      }
    }
  } else {
    if (waveCooldown > 0) {
      waveCooldown--;
    } else {
      startNewWave();
    }
  }
}

function startNewWave() {
  // --- CHAOS WAVE MODE ---

  let baseCount = 3;
  let scalingCount = Math.floor(game.level / 2);
  let count = Math.min(
    20, // Max musuh ditingkatkan sedikit untuk kompensasi sebaran
    baseCount + scalingCount + Math.floor(Math.random() * 5)
  );

  // Spacing dasar (nanti diacak lagi per musuh)
  let spacing = Math.max(15, 40 - game.level);

  currentWave = {
    count: count,
    spacing: spacing,
    spawned: 0,
    spawnTimer: 0,
  };
}

function spawnEnemyFromWave(wave) {
  // --- POSISI BENAR-BENAR ACAK ---
  // Tentukan Y sembarang di area layar
  // Area aman: 60px dari atas, 100px dari bawah
  const minY = 60;
  const maxY = canvasHeight - 120;

  const y = Math.random() * (maxY - minY) + minY;

  // Random X Offset biar tidak muncul dalam satu garis lurus sempurna
  const xOffset = Math.random() * 200;

  const randomShip = Math.floor(Math.random() * enemyImgArray.length);

  // Scaling Speed per 5 Level (0.2 factor)
  let rawSpeed = 3.5 + Math.random() * 2 + game.level * 0.2;
  const speed = Math.min(rawSpeed, 8);

  // --- RANDOM MOVEMENT TYPE ---
  // Setiap musuh melempar dadu sendiri untuk menentukan tipe gerakannya
  // 30% kemungkinan gerak gelombang (sine), sisanya lurus.
  let movementType = Math.random() < 0.3 ? "sine" : "straight";

  let enemy = new EnemyObj(
    canvasWidth + 50 + xOffset, // X position + random offset
    y,
    speed,
    enemyImgArray[randomShip],
    movementType
  );

  // BALANCING HEALTH
  enemy.health = 60 + game.level * 10;

  enemyShipArray.push(enemy);
}

// --- CLASS ORB UPDATE: SUPPORT IMAGE & OUTLINE ---
class AbilityToken {
  constructor(x, y) {
    this.x = x;
    this.y = y;
    this.width = 40; // Ukuran sedikit diperbesar untuk gambar
    this.height = 40;
    this.speed = 4;
    // RAND: 0-0.33=Bomb, 0.33-0.66=Double, 0.66-1.0=Missile
    let r = Math.random();
    if (r < 0.33) this.type = "bomb";
    else if (r < 0.66) this.type = "double";
    else this.type = "missile";
  }

  draw() {
    ctx.save();

    // --- GAYA METAL SLUG (KOTAK PUTIH TEBAL) UNTUK SEMUA TIPE PICKUP ---
    ctx.strokeStyle = "#ffffff";
    ctx.lineWidth = 3;
    ctx.strokeRect(this.x, this.y, this.width, this.height);

    const padding = 4;
    let imgToDraw = null;

    if (this.type === "missile") {
      imgToDraw = missilePickupImg;
    } else if (this.type === "double") {
      imgToDraw = laserPickupImg;
    } else if (this.type === "bomb") {
      // GUNAKAN GAMBAR BOM PICKUP YANG BARU
      imgToDraw = bombPickupImg;
    }

    if (imgToDraw) {
      ctx.drawImage(
        imgToDraw,
        this.x + padding,
        this.y + padding,
        this.width - padding * 2,
        this.height - padding * 2
      );
    }

    ctx.restore();
  }

  update() {
    this.x -= this.speed;
  }
}

function maybeSpawnAbilityToken() {
  // --- 0.2% (0.002) ---
  if (Math.random() < 0.002 && abilityTokens.length < 3) {
    const y = Math.random() * (canvasHeight - 120) + 60;
    abilityTokens.push(new AbilityToken(canvasWidth + 40, y));
  }
}

function useAbility() {
  if (enemyShipArray.length === 0 && enemyBulletsArray.length === 0) return;

  explosion_enemy.currentTime = 0;
  explosion_enemy.play();

  enemyShipArray.forEach((e) => {
    explosions.push(new Explosion(e.x + e.width / 2, e.y + e.height / 2));
    createParticles(e.x + e.width / 2, e.y + e.height / 2, 20, "#ff9900");
    // --- FIX: Tambah Score ---
    player1.score += 100 + game.level * 10;
  });

  enemyShipArray = [];
  enemyBulletsArray = [];
  missilesArray = [];

  damageFlash = 10;
}

class Particle {
  constructor(x, y, color) {
    this.x = x;
    this.y = y;
    this.vx = (Math.random() - 0.5) * 8;
    this.vy = (Math.random() - 0.5) * 8;
    this.life = 30;
    this.maxLife = 30;
    this.color = color;
    this.size = Math.random() * 3 + 2;
  }

  update() {
    this.x += this.vx;
    this.y += this.vy;
    this.vx *= 0.95;
    this.vy *= 0.95;
    this.life--;
  }

  draw() {
    const alpha = this.life / this.maxLife;
    ctx.save();
    ctx.globalAlpha = alpha;
    ctx.fillStyle = this.color;
    ctx.beginPath();
    ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
    ctx.fill();
    ctx.restore();
  }

  get isDead() {
    return this.life <= 0;
  }
}

function createParticles(x, y, count, color) {
  for (let i = 0; i < count; i++) {
    particles.push(new Particle(x, y, color));
  }
}

function updateParticles() {
  for (let i = particles.length - 1; i >= 0; i--) {
    particles[i].update();
    if (particles[i].isDead) {
      particles.splice(i, 1);
    }
  }
}

function drawParticles() {
  particles.forEach((p) => p.draw());
}

function Tabrakan(o, p) {
  if (
    o.x + o.width > p.x &&
    o.x < p.x + p.width &&
    o.y + o.height > p.y &&
    o.y < p.y + p.height
  ) {
    return true;
  }
  return false;
}

class Explosion {
  constructor(x, y, scale = 1) {
    this.x = x;
    this.y = y;
    this.frame = 0;
    this.maxFrames = 30;
    this.scale = scale;
  }

  update() {
    this.frame++;
  }

  draw() {
    let progress = this.frame / this.maxFrames;
    let radius = (20 + 60 * progress) * this.scale;
    ctx.save();
    ctx.globalAlpha = 1 - progress;
    let gradient = ctx.createRadialGradient(
      this.x,
      this.y,
      0,
      this.x,
      this.y,
      radius
    );
    gradient.addColorStop(0, "#ffffff");
    gradient.addColorStop(0.2, "#ffe066");
    gradient.addColorStop(0.5, "#ff8c42");
    gradient.addColorStop(1, "#ff0000");
    ctx.fillStyle = gradient;
    ctx.beginPath();
    ctx.arc(this.x, this.y, radius, 0, Math.PI * 2);
    ctx.fill();
    ctx.restore();
  }

  get done() {
    return this.frame >= this.maxFrames;
  }
}

function drawGameOver() {
  ctx.fillStyle = "rgba(53, 0, 0, 0.7)";
  ctx.fillRect(0, 0, canvasWidth, canvasHeight);

  ctx.font = "80px Arial";
  ctx.fillStyle = "red";
  ctx.textAlign = "center";
  ctx.fillText("GAME OVER", canvasWidth / 2, canvasHeight / 2 - 50);

  ctx.font = "40px Arial";
  ctx.fillStyle = "white";
  ctx.fillText(
    "Final Score: " + player1.score,
    canvasWidth / 2,
    canvasHeight / 2 + 20
  );
  ctx.fillText("Refresh to Restart", canvasWidth / 2, canvasHeight / 2 + 70);

  ctx.textAlign = "left";
}

function drawPauseOverlay() {
  ctx.fillStyle = "rgba(0,0,0,0.5)";
  ctx.fillRect(0, 0, canvasWidth, canvasHeight);

  ctx.font = "60px Arial";
  ctx.fillStyle = "white";
  ctx.textAlign = "center";
  ctx.fillText("PAUSED", canvasWidth / 2, canvasHeight / 2);
  ctx.font = "24px Arial";
  ctx.fillText("Press P to Resume", canvasWidth / 2, canvasHeight / 2 + 50);
  ctx.textAlign = "left";
}

function drawScreenShading() {
  if (!vignetteCanvas) {
    vignetteCanvas = document.createElement("canvas");
    vignetteCanvas.width = canvasWidth;
    vignetteCanvas.height = canvasHeight;
    const vCtx = vignetteCanvas.getContext("2d");

    let grd = vCtx.createRadialGradient(
      canvasWidth / 2,
      canvasHeight / 2,
      200,
      canvasWidth / 2,
      canvasHeight / 2,
      canvasWidth
    );
    grd.addColorStop(0, "rgba(0,0,0,0)");
    grd.addColorStop(1, "rgba(0,0,0,0.6)");
    vCtx.fillStyle = grd;
    vCtx.fillRect(0, 0, canvasWidth, canvasHeight);
  }

  ctx.drawImage(vignetteCanvas, 0, 0);

  if (damageFlash > 0) {
    let alpha = (damageFlash / 20) * 0.6;
    ctx.fillStyle = "rgba(255,0,0," + alpha.toFixed(2) + ")";
    ctx.fillRect(0, 0, canvasWidth, canvasHeight);
    damageFlash--;
  }

  // --- BRIGHTNESS SURGE OVERLAY ---
  // Use 'hard-light' or 'screen' to make dark backgrounds brighter
  if (game.surge > 1.0) {
    let intensity = (game.surge - 1.0) / (7.0 - 1.0); // Normalized 0 to 1
    if (intensity > 0) {
      ctx.save();
      ctx.globalCompositeOperation = "hard-light"; // Better for space haze
      ctx.fillStyle = "white";
      // Intensity 0.0 to 1.0 -> Alpha 0.0 to 0.4
      ctx.globalAlpha = intensity * 0.4;
      ctx.fillRect(0, 0, canvasWidth, canvasHeight);
      ctx.restore();
    }
  }
}

function updateSurge() {
  const RAMP_UP_FRAMES = 240;  // 4 seconds
  const HOLD_FRAMES = 780;     // 13 seconds
  const RAMP_DOWN_FRAMES = 300;// 5 seconds
  const MAX_SURGE_SPEED = 7.0;

  // Phase 0: Cooldown
  if (game.surgePhase === 0) {
    if (game.surgeCooldown > 0) {
      game.surgeCooldown--;
    } else {
      // Cooldown finished, check probability
      // "2/10 chance on incidents in 40 seconds" -> 20% chance every 40s check
      if (Math.random() < 0.2) {
        game.surgePhase = 1; // Start Surge
      } else {
        game.surgeCooldown = 2400; // Wait another 40s
      }
    }
  }

  // Phase 1: Ramping Up (Ease In)
  else if (game.surgePhase === 1) {
    let step = (MAX_SURGE_SPEED - 1.0) / RAMP_UP_FRAMES;
    game.surge += step;
    // Safety Clamp
    if (game.surge >= MAX_SURGE_SPEED) {
      game.surge = MAX_SURGE_SPEED;
      game.surgePhase = 2;
      game.surgeTimer = HOLD_FRAMES;
    }
  }

  // Phase 2: Holding Speed
  else if (game.surgePhase === 2) {
    game.surgeTimer--;
    if (game.surgeTimer <= 0) game.surgePhase = 3;
  }

  // Phase 3: Ramping Down (Ease Out)
  else if (game.surgePhase === 3) {
    let step = (MAX_SURGE_SPEED - 1.0) / RAMP_DOWN_FRAMES;
    game.surge -= step;
    if (game.surge <= 1.0) {
      game.surge = 1.0;
      game.surgePhase = 0;
      game.surgeCooldown = 2400; // Start cooldown for next cycle
    }
  }
}

function togglePause() {
  if (game.gameOver || !gameStarted) return;
  gamePaused = !gamePaused;

  if (gamePaused) {
    currentBGM.pause();
  } else if (!musicMuted && audioStarted) {
    currentBGM.play().catch(() => { });
    lastFrameTime = performance.now ? performance.now() : Date.now();
  }
}

function crossfadeToGameOver() {
  let fadeSpeed = 0.02;

  gameOverBGM.volume = 0;
  gameOverBGM.play();

  let fadeInterval = setInterval(() => {
    currentBGM.volume -= fadeSpeed;
    if (currentBGM.volume < 0) currentBGM.volume = 0;

    gameOverBGM.volume += fadeSpeed;
    if (gameOverBGM.volume > 1) gameOverBGM.volume = 1;

    if (currentBGM.volume === 0) {
      currentBGM.pause();
      clearInterval(fadeInterval);
    }
  }, 1000 / 30);
}
