const canvas = document.getElementById("gameCanvas");
const ctx = canvas.getContext("2d");
const miniCanvas = document.getElementById("miniMapCanvas");
const miniCtx = miniCanvas.getContext("2d");

const tileCountX = 24;
const tileCountY = 21;

const tileSize = Math.floor(canvas.width / tileCountX);
canvas.height = tileSize * tileCountY;

const headUp = new Image(); headUp.src = "assets/snake/head_up.png";
const headDown = new Image(); headDown.src = "assets/snake/head_down.png";
const headLeft = new Image(); headLeft.src = "assets/snake/head_left.png";
const headRight = new Image(); headRight.src = "assets/snake/head_right.png";

const bodyHor = new Image(); bodyHor.src = "assets/snake/body_horizontal.png";
const bodyVer = new Image(); bodyVer.src = "assets/snake/body_vertical.png";

const tailUp = new Image(); tailUp.src = "assets/snake/tail_up.png";
const tailDown = new Image(); tailDown.src = "assets/snake/tail_down.png";
const tailLeft = new Image(); tailLeft.src = "assets/snake/tail_left.png";
const tailRight = new Image(); tailRight.src = "assets/snake/tail_right.png";

const appleImg = new Image();
appleImg.src = "assets/apple.png";

const upSound = document.getElementById("upSound");
const downSound = document.getElementById("downSound");
const leftSound = document.getElementById("leftSound");
const rightSound = document.getElementById("rightSound");
const eatSound = document.getElementById("eatSound");
const hitSound = document.getElementById("hitSound");
const levelUpSound = document.getElementById("levelUpSound");

let isSoundOn = localStorage.getItem("sound") !== "off";

let snake, prevSnake, velocity, directionQueue, food;
let score;
let highscore = sessionStorage.getItem("highscore") || 0;
let lives = 3;

let isPaused = false;
let isCountingDown = false;
let isHit = false;
let isGameOver = false;

let level = 1;
let lastMoveTime = 0;
let moveDelay = 250;
let progress = 0;

let frameCount = 0;
let fpsLastTime = performance.now();
let currentFPS = 0;

let blinkCount = 0;
let maxBlink = 5;
let blinkTimer = 0;

let lastFaceDir = { dx: 1, dy: 0 };
let guideSource = null;

document.getElementById("highscore").innerText = highscore;

function unlockAudio() {
  const sounds = [upSound, downSound, leftSound, rightSound, eatSound, hitSound];

  sounds.forEach(sound => {
    sound.volume = 0;
    sound.play().then(() => {
      sound.pause();
      sound.currentTime = 0;
      sound.volume = 1;
    }).catch(() => {});
  });
}

function playSound(sound) {
  if (!isSoundOn) return;

  const clone = sound.cloneNode();
  clone.play();
}

function startGame() {
  unlockAudio();

  document.getElementById("startScreen").style.display = "none";
  document.getElementById("gameScreen").style.display = "block";

  initGame();
}

function initGame() {
  snake = [{ x: 6, y: 10 }, { x: 5, y: 10 }];
  prevSnake = JSON.parse(JSON.stringify(snake));
  velocity = { x: 0, y: 0 };
  directionQueue = [];
  lastFaceDir = { dx: 1, dy: 0 };

  food = { x: 18, y: 10 };
  score = 0;
  lives = 3;

  level = 1;
  moveDelay = 250;

  document.getElementById("score").innerText = score;
  document.getElementById("levelText").innerText = "Level 1";
  updateLivesUI();
}

function gameLoop(time = 0) {
  frameCount++;
  const elapsed = performance.now() - fpsLastTime;
  
  if (elapsed >= 1000) {
    currentFPS = Math.round((frameCount * 1000) / elapsed);
    document.getElementById("game-fps").innerText = currentFPS + " FPS";
    
    frameCount = 0;
    fpsLastTime = performance.now();
  }

  update(time);
  draw();
  requestAnimationFrame(gameLoop);
}
requestAnimationFrame(gameLoop);

function togglePause() {
  if (isGameOver) return;
  isPaused = !isPaused;

  document.getElementById("pauseScreen").style.display = isPaused ? "flex" : "none";
}

function resumeGame() {
    document.getElementById("pauseScreen").style.display = "none";
    
    const overlay = document.getElementById("countdown-overlay");
    const text = document.getElementById("countdown-text");
    
    isCountingDown = true;
    overlay.style.display = "flex";
    
    let count = 3;
    text.innerText = count;

    const countdownInterval = setInterval(() => {
        count--;
        
        if (count > 0) {
            text.innerText = count;
        } else {
            clearInterval(countdownInterval);
            overlay.style.display = "none";
            
            isCountingDown = false;
            isPaused = false; 
        }
    }, 1000);
}

function exitGame() {
  isPaused = false;

  document.getElementById("pauseScreen").style.display = "none";
  document.getElementById("gameScreen").style.display = "none";
  document.getElementById("startScreen").style.display = "flex";

  initGame();
}

function update(time) {
  if (!snake) return;

  if (isHit) {
    if (time - blinkTimer > 100) {
      blinkTimer = time;
      blinkCount++;
    }
  }

  if (isPaused) return;

  if (isGameOver) {
    if (time - blinkTimer > 100) {
      blinkTimer = time;
      blinkCount++;

      if (blinkCount >= maxBlink) {
        document.getElementById("gameScreen").style.display = "none";
        document.getElementById("startScreen").style.display = "flex";

        isGameOver = false;
        initGame();
      }
    }
    return;
  }

  if (time - lastMoveTime > moveDelay) {
    prevSnake = JSON.parse(JSON.stringify(snake));

    if (directionQueue.length > 0) {
      velocity = directionQueue.shift();
      
      if (gestureChangeTimestamp > 0) {
        const inputLag = Math.round(performance.now() - gestureChangeTimestamp);
        document.getElementById("game-latency").innerText = inputLag + " ms";
        gestureChangeTimestamp = 0; 
      }
    }

    const head = {
      x: snake[0].x + velocity.x,
      y: snake[0].y + velocity.y
    };

    if (velocity.x === 0 && velocity.y === 0) return;

    if (
      head.x < 0 || head.x >= tileCountX ||
      head.y < 0 || head.y >= tileCountY
    ) return gameOver();

    for (let part of snake) {
      if (part.x === head.x && part.y === head.y) {
        return gameOver();
      }
    }

    snake.unshift(head);

    if (head.x === food.x && head.y === food.y) {
      playSound(eatSound);
      score++;
      document.getElementById("score").innerText = score;
      updateHighscore();
      updateLevel();
      spawnFood();
    } else {
      snake.pop();
    }
    lastMoveTime = time;
  }
  progress = Math.min((time - lastMoveTime) / moveDelay, 1);
}

function gameOver() {
  playSound(hitSound);

  lives--;
  updateLivesUI();

  if (lives > 0) {
    isHit = true;
    isPaused = true;
    blinkCount = 0;
    blinkTimer = 0;

    setTimeout(() => {
      snake = [{ x: 6, y: 10 }, { x: 5, y: 10 }];
      prevSnake = JSON.parse(JSON.stringify(snake));
      velocity = { x: 0, y: 0 };
      directionQueue = [];
      lastFaceDir = { dx: 1, dy: 0 };

      food = { x: 18, y: 10 };
      moveDelay = 250;

      isHit = false;
      isPaused = false;
    }, 500);

    return;
  }

  isGameOver = true;
  blinkCount = 0;
  blinkTimer = 0;

  if (score > highscore) {
    highscore = score;
    sessionStorage.setItem("highscore", highscore);
    document.getElementById("highscore").innerText = highscore;
  }
}

function draw() {
  if (!snake) return;

  ctx.fillStyle = "black";
  ctx.fillRect(0, 0, canvas.width, canvas.height);
  drawGrid();

  if ((!isGameOver && !isHit) || blinkCount % 2 === 0) {
    for (let i = 0; i < snake.length; i++) {
      const current = snake[i];
      const previous = prevSnake[i] || current;

      const interpX = previous.x + (current.x - previous.x) * progress;
      const interpY = previous.y + (current.y - previous.y) * progress;

      const x = interpX * tileSize;
      const y = interpY * tileSize;

      if (i === 0) {
        let dx = current.x - previous.x;
        let dy = current.y - previous.y;

        if (dx !== 0 || dy !== 0) {
          lastFaceDir = { dx, dy };
        } else {
          dx = lastFaceDir.dx;
          dy = lastFaceDir.dy;
        }

        let img, w, h;
        if (dx > 0) { img = headRight; w = 120; h = 108; }
        else if (dx < 0) { img = headLeft; w = 120; h = 108; }
        else if (dy > 0) { img = headDown; w = 108; h = 120; }
        else { img = headUp; w = 108; h = 120; }

        drawScaledImage(img, x, y, w, h);

      } else if (i === snake.length - 1) {
        let dx = previous.x - current.x;
        let dy = previous.y - current.y;

        if (dx === 0 && dy === 0) {
            dx = -lastFaceDir.dx; 
            dy = -lastFaceDir.dy;
        }

        let img, w, h;
        if (dx > 0) { img = tailLeft; w = 100; h = 92; }
        else if (dx < 0) { img = tailRight; w = 100; h = 92; }
        else if (dy > 0) { img = tailUp; w = 92; h = 100; }
        else { img = tailDown; w = 92; h = 100; }

        drawScaledImage(img, x, y, w, h);

      } else {
        const parent = snake[i - 1];
        let img, w, h;
        
        if (current.y === parent.y) { 
          img = bodyHor; w = 100; h = 92;
        } else {
          img = bodyVer; w = 92; h = 100;
        }
        
        drawScaledImage(img, x, y, w, h);
      }
    }
  }

  ctx.drawImage(
    appleImg, 
    food.x * tileSize, 
    food.y * tileSize, 
    tileSize, 
    tileSize
  );

  drawMiniMap();
}

function drawGrid() {
  for (let y = 0; y < tileCountY; y++) {
    for (let x = 0; x < tileCountX; x++) {
      ctx.fillStyle = (x + y) % 2 === 0 ? "#AAD751" : "#A2D149";
      ctx.fillRect(x * tileSize, y * tileSize, tileSize + 1, tileSize + 1);
    }
  }
}

function drawScaledImage(img, x, y, baseW, baseH) {
  const scale = tileSize / 100; 
  const width = baseW * scale;
  const height = baseH * scale;

  const offsetX = (tileSize - width) / 2;
  const offsetY = (tileSize - height) / 2;

  ctx.drawImage(img, x + offsetX, y + offsetY, width + 1, height + 1);
}

function drawMiniMap() {
  if (!snake) return;

  const scaleX = miniCanvas.width / tileCountX;
  const scaleY = miniCanvas.height / tileCountY;

  miniCtx.fillStyle = "#1F2020";
  miniCtx.fillRect(0, 0, miniCanvas.width, miniCanvas.height);

  miniCtx.fillStyle = "#E7471D";
  miniCtx.fillRect(
    food.x * scaleX,
    food.y * scaleY,
    scaleX,
    scaleY
  );

  snake.forEach((part, index) => {
    miniCtx.fillStyle = index === 0 ? "#6AB04A" : "#6AB04A";
    miniCtx.fillRect(
      part.x * scaleX,
      part.y * scaleY,
      scaleX,
      scaleY
    );
  });

  const head = snake[0];
  const cx = head.x * scaleX + scaleX / 2;
  const cy = head.y * scaleY + scaleY / 2;

  miniCtx.strokeStyle = "rgba(255,255,255,0.5)";
  miniCtx.lineWidth = 1;

  miniCtx.beginPath();
  miniCtx.moveTo(cx, 0);
  miniCtx.lineTo(cx, miniCanvas.height);

  miniCtx.moveTo(0, cy);
  miniCtx.lineTo(miniCanvas.width, cy);
  miniCtx.stroke();

  miniCtx.fillStyle = "white";
  miniCtx.font = "10px Arial";
  miniCtx.fillText("N", miniCanvas.width / 2 - 3, 10);
  miniCtx.fillText("S", miniCanvas.width / 2 - 3, miniCanvas.height - 2);
  miniCtx.fillText("W", 2, miniCanvas.height / 2 + 3);
  miniCtx.fillText("E", miniCanvas.width - 10, miniCanvas.height / 2 + 3);
}

function spawnFood() {
  let valid = false;

  while (!valid) {
    food.x = Math.floor(Math.random() * (tileCountX - 2)) + 1;
    food.y = Math.floor(Math.random() * (tileCountY - 2)) + 1;

    valid = !snake.some(p => p.x === food.x && p.y === food.y);
  }
}

function isGameRunning() {
  return document.getElementById("gameScreen").style.display === "block";
}

function updateHighscore() {
  if (score > highscore) {
    highscore = score;
    sessionStorage.setItem("highscore", highscore);
    document.getElementById("highscore").innerText = highscore;
  }
}

function updateLivesUI() {
  const hearts = [
    document.getElementById("life1"),
    document.getElementById("life2"),
    document.getElementById("life3")
  ];

  for (let i = 0; i < 3; i++) {
    hearts[i].src = i < lives
      ? "assets/heart-full.png"
      : "assets/heart.png";
  }
}

function updateLevel() {
  const newLevel = Math.floor(score / 10) + 1;

  if (newLevel !== level) {
    level = newLevel;
    document.getElementById("levelText").innerText = "Level " + level;

    playSound(levelUpSound);
  }
  moveDelay = Math.max(100, 250 - (level - 1) * 10);
}

function toggleSound() {
  isSoundOn = !isSoundOn;
  localStorage.setItem("sound", isSoundOn ? "on" : "off");
  updateSoundUI();
}

function updateSoundUI() {
  const soundBtn = document.getElementById("soundToggle");
  if (soundBtn) {
    soundBtn.innerText = isSoundOn ? "Efek Suara (ON)" : "Efek Suara (OFF)";
  }
}

window.onload = () => {
  updateSoundUI();
};

function showGuide(source) {
  guideSource = source;

  document.getElementById("guidePopup").style.display = "flex";
  
  const guideBox = document.querySelector(".guide-box");
  guideBox.scrollTop = 0;
}

function closeGuide() {
  document.getElementById("guidePopup").style.display = "none";
  document.activeElement.blur();
}

function showTutorial() {
    onboardingComplete = false;
    currentStep = 1;

    document.getElementById("startScreen").style.display = "none";

    const onboardingScreen = document.getElementById("onboardingScreen");
    onboardingScreen.style.display = "flex";

    document.getElementById("step1").style.display = "block";
    document.getElementById("step2").style.display = "none";
    document.getElementById("step3").style.display = "none";

    const statusBox = document.getElementById("cameraStatus");
    if (statusBox) {
        statusBox.innerText = "Mendeteksi Tangan...";
        statusBox.classList.remove("ready");
    }
}

const hand = document.querySelector(".demo-hand");
const gestureLabel = document.getElementById("gestureLabel");

const animations = [
  {
    x: "-50%",
    y: "-150%",
    text: "Atas"
  },
  {
    x: "100%",
    y: "-50%",
    text: "Kanan"
  },
  {
    x: "-50%",
    y: "50%",
    text: "Bawah"
  },
  {
    x: "-200%",
    y: "-50%",
    text: "Kiri"
  }
];

let index = 0;

setInterval(() => {
  const anim = animations[index];

  hand.style.transform = `translate(${anim.x}, ${anim.y})`;
  gestureLabel.innerText = anim.text;

  index = (index + 1) % animations.length;
}, 1000);

// document.addEventListener("keydown", (e) => {

//   if (e.key === "Escape") {

//     const guideVisible = document.getElementById("guidePopup").style.display === "flex";

//     if (guideVisible) {
//       closeGuide();

//       if (guideSource === "pause") {
//         document.getElementById("pauseScreen").style.display = "flex";
//       } else {
//         document.getElementById("startScreen").style.display = "flex";
//       }
//       return;
//     }

//     if (isGameRunning()) {
//       togglePause();
//       return;
//     }
//   }

//   if (isPaused) return;

//   let newDir = null;
//   let sound = null;

//   switch (e.key) {
//     case "ArrowUp": newDir = { x: 0, y: -1 }; sound = upSound; break;
//     case "ArrowDown": newDir = { x: 0, y: 1 }; sound = downSound; break;
//     case "ArrowLeft": newDir = { x: -1, y: 0 }; sound = leftSound; break;
//     case "ArrowRight": newDir = { x: 1, y: 0 }; sound = rightSound; break;
//   }

//   if (!newDir) return;

//   if (velocity.x === 0 && velocity.y === 0) {
//     const defaultDir = {
//       x: snake[0].x - snake[1].x,
//       y: snake[0].y - snake[1].y
//     };

//     if (newDir.x === -defaultDir.x && newDir.y === -defaultDir.y) return;

//     playSound(sound);
//     velocity = newDir;
//     return;
//   }

//   const lastDir = directionQueue.length > 0
//     ? directionQueue[directionQueue.length - 1]
//     : velocity;

//   if (newDir.x === -lastDir.x && newDir.y === -lastDir.y) return;
//   if (newDir.x === lastDir.x && newDir.y === lastDir.y) return;

//   playSound(sound);

//   if (directionQueue.length < 3) {
//     directionQueue.push(newDir);
//   }
// });