/* ==========================================
   2048 LOGIC 
   ========================================== 
   fungsi inti:
   1. addNewTile() - spawn tile baru (angka 2)
   2. slide() - algoritma merge tile
   3. move functions - 4 arah pergerakan
   4. canMove() - Cek game over
   ========================================== */

/* ==========================================
   SPAWN TILE BARU
   ========================================== */

function addNewTile() {
  // Step 1: Cari semua cell kosong (value = 0)
  const empty = [];
  for (let r = 0; r < 4; r++) {
    for (let c = 0; c < 4; c++) {
      if (board[r][c] === 0) empty.push({ r, c });
    }
  }
  
  // Kalau board penuh, return false (game over)
  if (empty.length === 0) return false;

  // Step 2: Pilih 1 posisi random dari cell kosong
  const spot = empty[Math.floor(Math.random() * empty.length)];
  board[spot.r][spot.c] = 2; // Tile baru selalu angka 2

  // Step 3: Animasi "new" + sound effect
  const tile = document.getElementById(`${spot.r}-${spot.c}`);
  if (tile) {
    tile.classList.add("new"); // Trigger animasi pop
    playSound(audio.pop); // Sound effect
    setTimeout(() => tile.classList.remove("new"), 300);
  }

  updateTile(spot.r, spot.c, 2); // Update visual tile
  return true;
}

/* ==========================================
   HELPER: FILTER ANGKA NOL
   ========================================== */
function filterZero(row) {
  // Buang semua 0 dari array
  // Contoh: [2, 0, 2, 0] → [2, 2]
  return row.filter(n => n !== 0);
}

/* ==========================================
   ALGORITMA SLIDE & MERGE (CORE!)
   ========================================== 
   Ini yang bikin 2+2=4, 4+4=8, dst
   ========================================== */
function slide(row) {
  // Step 1: Filter zero - kumpulkan tile
  // [2, 0, 2, 4] → [2, 2, 4]
  row = filterZero(row);

  let mergedThisMove = false;
  let mergedPositions = []; // Posisi tile yang di-merge (untuk animasi)
  let mergeCount = 0; // Hitung berapa kali merge (untuk combo)

  // Step 2: Loop cek tile sebelahan
  for (let i = 0; i < row.length - 1; i++) {
    if (row[i] === row[i + 1]) {
      //  MERGE! Tile sama ketemu
      row[i] = row[i] * 2; // Tile pertama jadi 2x lipat
      
      playSound(audio.merge); // Sound effect merge
      
      // Haptic feedback (getaran) di mobile
      if (navigator.vibrate) {
        navigator.vibrate([80, 20, 80]);
      }

      currentScore += row[i]; // Tambah score
      row[i + 1] = 0; // Tile kedua hilang (jadi 0)

      mergedThisMove = true;
      mergedPositions.push(i); // Simpan posisi untuk animasi
      mergeCount++;
    }
  }

  // Step 3: Filter zero lagi & padding
  // [4, 0, 4] → [4, 4] → [4, 4, 0, 0]
  row = filterZero(row);
  while (row.length < 4) row.push(0); // Padding 0 di kanan

  return { 
    row, 
    merged: mergedThisMove, 
    mergedPositions, 
    mergeCount };
}

/* ==========================================
   HELPER: CEK ARRAY SAMA ATAU TIDAK
   ========================================== */
function arraysEqual(a, b) {
  // Bandingin setiap elemen
  // Dipakai untuk cek apakah board berubah setelah move
  return a.length === b.length && a.every((v, i) => v === b[i]);
}

/* ==========================================
   MOVE FUNCTIONS - 4 ARAH PERGERAKAN
   ========================================== 
   Semua punya struktur yang sama:
   1. Loop setiap baris/kolom
   2. Panggil slide() untuk merge
   3. Cek perubahan dengan arraysEqual()
   4. Refresh board kalau ada perubahan
   ========================================== */

 /* MOVE LEFT - Geser ke kiri */  
function moveLeft() {
  let moved = false;
  let mergedCells = []; // Track cell yang di-merge
  mergesInCurrentMove = 0; // Reset combo counter
  
  // Loop setiap baris (horizontal)
  for (let r = 0; r < 4; r++) {
    const { row: newRow, mergedPositions, mergeCount } = slide(board[r]);

    // Cek apakah row berubah
    if (!arraysEqual(newRow, board[r])) moved = true;
    board[r] = newRow;
    
    mergesInCurrentMove += mergeCount;
    
    // Simpan posisi cell yang merge untuk combo effect
    if (mergedPositions && mergedPositions.length > 0) {
      mergedPositions.forEach(c => {
        mergedCells.push({ r, c });
      });
    }
  }
  
  // Kalau ada pergerakan, update visual + effect
  if (moved) {
    refreshBoard();
    triggerComboEffect(mergedCells, mergesInCurrentMove);
  }
  return moved;
}

/* MOVE RIGHT - Geser ke kanan */
function moveRight() {
  let moved = false;
  let mergedCells = [];
  mergesInCurrentMove = 0;
  
  // TRICK: Reverse → slide → reverse lagi
    // Supaya bisa pakai logic slide yang sama
  for (let r = 0; r < 4; r++) {
    let reversed = [...board[r]].reverse();
    const { row: slid, mergedPositions, mergeCount } = slide(reversed);
    let newRow = slid.reverse(); // Balik lagi ke posisi asli

    if (!arraysEqual(newRow, board[r])) moved = true;
    board[r] = newRow;
    
    mergesInCurrentMove += mergeCount;
    
    // Convert posisi merge ke koordinat asli (dari kanan)
    if (mergedPositions && mergedPositions.length > 0) {
      mergedPositions.forEach(pos => {
        const c = 3 - pos; // Mirror position
        mergedCells.push({ r, c });
      });
    }
  }
  
  if (moved) {
    refreshBoard();
    triggerComboEffect(mergedCells, mergesInCurrentMove);
  }
  return moved;
}

/* MOVE UP - Geser ke atas */
function moveUp() {
  let moved = false;
  let mergedCells = [];
  mergesInCurrentMove = 0;
  
  // Loop setiap kolom (vertical)
  for (let c = 0; c < 4; c++) {
    // Ambil kolom vertikal sebagai array
    const col = [board[0][c], board[1][c], board[2][c], board[3][c]];
    const { row: newCol, mergedPositions, mergeCount } = slide(col);

    // Update board per row
    for (let r = 0; r < 4; r++) {
      if (board[r][c] !== newCol[r]) moved = true;
      board[r][c] = newCol[r];
    }
    
    mergesInCurrentMove += mergeCount;
    
    if (mergedPositions && mergedPositions.length > 0) {
      mergedPositions.forEach(r => {
        mergedCells.push({ r, c });
      });
    }
  }
  
  if (moved) {
    refreshBoard();
    triggerComboEffect(mergedCells, mergesInCurrentMove);
  }
  return moved;
}

/* MOVE DOWN - Geser ke bawah */
function moveDown() {
  let moved = false;
  let mergedCells = [];
  mergesInCurrentMove = 0;
  
  for (let c = 0; c < 4; c++) {
    //TRICK: Ambil kolom dari bawah ke atas (reversed)
    const col = [board[3][c], board[2][c], board[1][c], board[0][c]];
    const { row: slid, mergedPositions, mergeCount } = slide(col);
    const newCol = slid.reverse(); // Balik ke urutan normal

    for (let r = 0; r < 4; r++) {
      if (board[r][c] !== newCol[r]) moved = true;
      board[r][c] = newCol[r];
    }
    
    mergesInCurrentMove += mergeCount;
    
    // Convert posisi merge ke koordinat asli (dari bawah)
    if (mergedPositions && mergedPositions.length > 0) {
      mergedPositions.forEach(pos => {
        const r = 3 - pos; // Mirror position
        mergedCells.push({ r, c });
      });
    }
  }
  
  if (moved) {
    refreshBoard();
    triggerComboEffect(mergedCells, mergesInCurrentMove);
  }
  return moved;
}

/* ==========================================
   CEK GAME OVER
   ========================================== */
function canMove() {
  // Kondisi 1: Ada cell kosong?
  for (let r = 0; r < 4; r++) {
    for (let c = 0; c < 4; c++) {
      if (board[r][c] === 0) return true; // Masih ada ruang
    }
  }
  
  // Kondisi 2: Ada tile sebelahan yang bisa di-merge?
  for (let r = 0; r < 4; r++) {
    for (let c = 0; c < 4; c++) {
      const current = board[r][c];
      //cek kanan
      if (c < 3 && board[r][c + 1] === current) return true;
      //cek bawah
      if (r < 3 && board[r + 1][c] === current) return true;
    }
  }
  // Kalau kedua kondisi false → STUCK = Game Over
  return false;
}