const SHARED_PATH_LENGTH = 52;
const HOME_ENTRY_POS = 50;
const HOME_STRETCH = 5;
const FINISH_POS = HOME_ENTRY_POS + 1 + HOME_STRETCH; // 56 — the 6th home column square (outer middle of center 3x3)
// Must match board-map.js START_SQUARES exactly
const START_POSITIONS = [0, 13, 26, 39];
const SAFE_SQUARES = [0, 8, 13, 21, 26, 34, 39, 47];

// Player order: 0=Red(BL), 1=Green(TL), 2=Yellow(TR), 3=Blue(BR)
export const COLORS = ['red', 'green', 'yellow', 'blue'];
export const COLOR_CSS = ['#E53935', '#43A047', '#FDD835', '#1E88E5'];

export function createGame(numPlayers = 4) {
  const players = [];
  for (let i = 0; i < numPlayers; i++) {
    players.push({
      color: COLORS[i],
      pieces: [
        { id: `${i}-0`, pos: -1, finished: false },
        { id: `${i}-1`, pos: -1, finished: false },
        { id: `${i}-2`, pos: -1, finished: false },
        { id: `${i}-3`, pos: -1, finished: false }
      ],
      finished: false,
      consecutiveSixes: 0
    });
  }
  return {
    players,
    currentPlayer: 0,
    diceValue: null,
    rolled: false,
    numPlayers,
    winners: [],
    gameOver: false,
    extraTurn: false
  };
}

export function rollDice(game, playerIdx) {
  if (!game || playerIdx == null) return Math.floor(Math.random() * 6) + 1;
  const ctx = getDiceContext(game, playerIdx);
  const weights = computeDiceWeights(ctx);
  return weightedRoll(weights);
}

function getDiceContext(game, playerIdx) {
  const player = game.players[playerIdx];
  const piecesHome = player.pieces.filter(p => p.pos === -1 && !p.finished).length;

  const progress = player.pieces.reduce((sum, p) => {
    if (p.finished) return sum + FINISH_POS;
    if (p.pos === -1) return sum;
    return sum + p.pos;
  }, 0) / (FINISH_POS * 4) * 100;

  const othersProgress = game.players
    .filter((_, i) => i !== playerIdx && !game.players[i].finished)
    .map(op => op.pieces.reduce((s, p) => s + (p.finished ? FINISH_POS : p.pos === -1 ? 0 : p.pos), 0) / (FINISH_POS * 4) * 100);
  const avgOthersProgress = othersProgress.length ? othersProgress.reduce((a, b) => a + b, 0) / othersProgress.length : 0;

  let killValues = 0;
  const capturePerDie = [false, false, false, false, false, false];
  for (let d = 1; d <= 6; d++) {
    const moves = getValidMoves(game, playerIdx, d);
    if (moves.some(m => m.type === 'capture')) {
      killValues++;
      capturePerDie[d - 1] = true;
    }
  }

  const nearCapture = detectNearCapture(game, playerIdx);
  const elapsed = game.startTime ? (Date.now() - game.startTime) / 60000 : 0;

  return { piecesHome, progress, avgOthersProgress, killValues, capturePerDie, nearCapture, elapsed };
}

function detectNearCapture(game, playerIdx) {
  const player = game.players[playerIdx];
  let bestDist = Infinity;
  for (const piece of player.pieces) {
    if (piece.pos === -1 || piece.finished || piece.pos >= HOME_ENTRY_POS) continue;
    const myGlobal = (piece.pos + START_POSITIONS[playerIdx]) % SHARED_PATH_LENGTH;
    for (let opp = 0; opp < game.numPlayers; opp++) {
      if (opp === playerIdx) continue;
      for (const op of game.players[opp].pieces) {
        if (op.pos === -1 || op.finished || op.pos >= HOME_ENTRY_POS) continue;
        const theirGlobal = (op.pos + START_POSITIONS[opp]) % SHARED_PATH_LENGTH;
        if (SAFE_SQUARES.includes(theirGlobal)) continue;
        const stepsNeeded = (theirGlobal - myGlobal + SHARED_PATH_LENGTH) % SHARED_PATH_LENGTH;
        if (stepsNeeded >= 1 && stepsNeeded <= 6 && stepsNeeded < bestDist) {
          bestDist = stepsNeeded;
        }
      }
    }
  }
  return bestDist <= 6 ? bestDist : 0;
}

function computeDiceWeights(ctx) {
  const w = [1, 1, 1, 1, 1, 1];

  if (ctx.piecesHome === 4) {
    w[5] += 0.8;
  } else if (ctx.piecesHome >= 3) {
    w[5] += 0.4;
  }

  const deficit = ctx.avgOthersProgress - ctx.progress;
  if (deficit > 15) {
    w[5] += Math.min(0.8, deficit / 40);
  }

  if (ctx.killValues >= 2 && ctx.progress < ctx.avgOthersProgress) {
    w[1] += 0.2; w[2] += 0.2; w[3] += 0.2; w[4] += 0.2;
  }

  if (ctx.progress - ctx.avgOthersProgress > 20 && ctx.piecesHome === 0) {
    w[5] = Math.max(0.5, w[5] - 0.5);
  }

  if (ctx.elapsed > 12) {
    w[5] += 0.3;
  }

  // "Lucky roll" — subtle boost toward capture dice (should feel lucky, not guaranteed)
  if (ctx.nearCapture > 0) {
    const idx = ctx.nearCapture - 1;
    w[idx] += 0.3;
  }
  for (let i = 0; i < 6; i++) {
    if (ctx.capturePerDie[i]) w[i] += 0.15;
  }

  return w;
}

function weightedRoll(weights) {
  const total = weights.reduce((a, b) => a + b, 0);
  let r = Math.random() * total;
  for (let i = 0; i < 6; i++) {
    r -= weights[i];
    if (r <= 0) return i + 1;
  }
  return 6;
}

export function getValidMoves(game, playerIdx, dice) {
  const player = game.players[playerIdx];
  const moves = [];

  for (const piece of player.pieces) {
    if (piece.finished) continue;

    if (piece.pos === -1) {
      if (dice === 6) {
        moves.push({ pieceId: piece.id, from: -1, to: 0, type: 'enter' });
      }
    } else {
      // Pawn turns into home column directly from position 50 (skipping the corner)
      const newPos = piece.pos + dice;

      if (newPos === FINISH_POS) {
        moves.push({ pieceId: piece.id, from: piece.pos, to: newPos, type: 'finish' });
      } else if (newPos < FINISH_POS) {
        if (newPos > HOME_ENTRY_POS) {
          moves.push({ pieceId: piece.id, from: piece.pos, to: newPos, type: 'home' });
        } else {
          const globalPos = (newPos + START_POSITIONS[playerIdx]) % SHARED_PATH_LENGTH;
          const captured = checkCapture(game, playerIdx, globalPos);
          moves.push({ pieceId: piece.id, from: piece.pos, to: newPos, type: captured ? 'capture' : 'move' });
        }
      }
      // newPos > FINISH_POS = overshoot, invalid
    }
  }

  return moves;
}

export function applyMove(game, playerIdx, move) {
  const player = game.players[playerIdx];
  const piece = player.pieces.find(p => p.id === move.pieceId);
  if (!piece) return game;

  game.extraTurn = false;

  if (move.type === 'enter') {
    piece.pos = 0;
    const globalPos = START_POSITIONS[playerIdx];
    move._capturedPlayers = captureAt(game, playerIdx, globalPos);
    game.extraTurn = true;
  } else if (move.type === 'finish') {
    piece.pos = move.to;
    piece.finished = true;
    game.extraTurn = true;
    if (player.pieces.every(p => p.finished)) {
      player.finished = true;
      game.winners.push(playerIdx);
      // Game ends when 3 players finish — the 4th is the loser
      if (game.winners.length >= 3) {
        const lastPlayer = game.players.findIndex((p, i) => !p.finished);
        if (lastPlayer !== -1) game.winners.push(lastPlayer);
        game.gameOver = true;
      }
    }
  } else if (move.type === 'capture') {
    piece.pos = move.to;
    const globalPos = (move.to + START_POSITIONS[playerIdx]) % SHARED_PATH_LENGTH;
    move._capturedPlayers = captureAt(game, playerIdx, globalPos);
    game.extraTurn = true;
  } else if (move.type === 'home') {
    piece.pos = move.to;
  } else {
    piece.pos = move.to;
  }

  if (game.diceValue === 6) {
    game.extraTurn = true;
    player.consecutiveSixes = (player.consecutiveSixes || 0) + 1;
    if (player.consecutiveSixes >= 3) {
      // Triple-six penalty: lose extra turn only, pawn stays in place
      player.consecutiveSixes = 0;
      game.extraTurn = false;
    }
  } else {
    player.consecutiveSixes = 0;
  }

  return game;
}

export function nextTurn(game) {
  if (game.extraTurn) {
    game.extraTurn = false;
    return;
  }
  do {
    game.currentPlayer = (game.currentPlayer + 1) % game.numPlayers;
  } while (game.players[game.currentPlayer].finished && !game.gameOver);
}

function checkCapture(game, playerIdx, globalPos) {
  if (SAFE_SQUARES.includes(globalPos)) return false;

  for (let i = 0; i < game.numPlayers; i++) {
    if (i === playerIdx) continue;
    for (const piece of game.players[i].pieces) {
      if (piece.pos === -1 || piece.finished) continue;
      if (piece.pos > HOME_ENTRY_POS) continue;
      const theirGlobal = (piece.pos + START_POSITIONS[i]) % SHARED_PATH_LENGTH;
      if (theirGlobal === globalPos) return true;
    }
  }
  return false;
}

function captureAt(game, playerIdx, globalPos) {
  const captured = [];
  if (SAFE_SQUARES.includes(globalPos)) return captured;

  for (let i = 0; i < game.numPlayers; i++) {
    if (i === playerIdx) continue;
    for (const piece of game.players[i].pieces) {
      if (piece.pos === -1 || piece.finished) continue;
      if (piece.pos > HOME_ENTRY_POS) continue;
      const theirGlobal = (piece.pos + START_POSITIONS[i]) % SHARED_PATH_LENGTH;
      // Double-check: never capture a piece sitting on ANY safe square
      if (SAFE_SQUARES.includes(theirGlobal)) continue;
      if (theirGlobal === globalPos) {
        piece.pos = -1;
        if (!captured.includes(i)) captured.push(i);
      }
    }
  }
  return captured;
}

export function getBotMove(game, playerIdx, dice) {
  const moves = getValidMoves(game, playerIdx, dice);
  if (moves.length === 0) return null;

  // Priority: finish > capture > enter > advance furthest
  const finishes = moves.filter(m => m.type === 'finish');
  if (finishes.length > 0) return finishes[0];

  const captures = moves.filter(m => m.type === 'capture');
  if (captures.length > 0) return captures[0];

  const enters = moves.filter(m => m.type === 'enter');
  if (enters.length > 0) return enters[0];

  // Advance the piece that's furthest along (closest to home)
  const sorted = moves.sort((a, b) => b.to - a.to);
  return sorted[0];
}
