var BackgammonBot = (function() {
  'use strict';

  var C = BackgammonConstants;

  function chooseMove(board, bar, borneOff, player, diceRemaining, difficulty) {
    var sequences = C.getAllMovesForDice(board, bar, borneOff, player, diceRemaining);
    if (!sequences || sequences.length === 0) return [];

    if (difficulty === 'easy') {
      return sequences[Math.floor(Math.random() * sequences.length)];
    }

    var best = null;
    var bestScore = -Infinity;

    for (var i = 0; i < sequences.length; i++) {
      var score = scoreSequence(board, bar, borneOff, player, sequences[i], difficulty);
      if (score > bestScore) {
        bestScore = score;
        best = sequences[i];
      }
    }

    return best || sequences[0];
  }

  function scoreSequence(board, bar, borneOff, player, moves, difficulty) {
    var state = { board: board.slice(), bar: bar.slice(), borneOff: borneOff.slice() };

    var score = 0;
    for (var i = 0; i < moves.length; i++) {
      var move = moves[i];
      if (move.hit) score += (difficulty === 'hard') ? 4 : 3;
      if (move.to === 'off') score += 5;
      state = C.applyMove(state.board, state.bar, state.borneOff, player, move);
    }

    if (difficulty === 'medium') {
      score += scoreMedium(state.board, state.bar, state.borneOff, player);
    } else if (difficulty === 'hard') {
      score += scoreHard(state.board, state.bar, state.borneOff, player);
    }

    return score;
  }

  function scoreMedium(board, bar, borneOff, player) {
    var score = 0;
    var opp = 1 - player;
    var homeStart = (player === 0) ? 0 : 18;
    var homeEnd = (player === 0) ? 5 : 23;

    for (var i = 0; i < 24; i++) {
      var count = board[i];
      var isOwn = (player === 0) ? count > 0 : count < 0;
      var absCount = Math.abs(count);

      if (isOwn) {
        if (absCount === 1) {
          score -= 4;
          if (isInOpponentHome(i, player)) score -= 3;
        }
        if (absCount >= 2) {
          score += 1;
        }
      }
    }

    score += borneOff[player] * 5;
    score -= bar[player] * 8;
    score += bar[opp] * 3;

    return score;
  }

  function scoreHard(board, bar, borneOff, player) {
    var score = 0;
    var opp = 1 - player;

    var myPips = C.pipCount(board, bar, player);
    var oppPips = C.pipCount(board, bar, opp);
    score -= myPips * 0.3;
    score += (oppPips - myPips) * 0.2;

    var primeLen = longestPrime(board, player);
    score += primeLen * primeLen * 2;

    var blots = countBlots(board, player);
    for (var b = 0; b < blots.length; b++) {
      score -= 3;
      if (isInOpponentHome(blots[b], player)) score -= 5;
    }

    var anchors = countAnchors(board, player);
    score += anchors * 4;

    score += borneOff[player] * 6;
    score -= bar[player] * 10;
    score += bar[opp] * 4;

    var phase = detectPhase(board, bar, borneOff, player);
    if (phase === 'bearoff') {
      score += borneOff[player] * 3;
    } else if (phase === 'prime') {
      score += primeLen * 3;
    }

    return score;
  }

  function detectPhase(board, bar, borneOff, player) {
    if (C.isAllHome(board, bar, player)) return 'bearoff';
    if (longestPrime(board, player) >= 4) return 'prime';
    var myPips = C.pipCount(board, bar, player);
    var oppPips = C.pipCount(board, bar, 1 - player);
    if (Math.abs(myPips - oppPips) > 30) return 'race';
    return 'positional';
  }

  function longestPrime(board, player) {
    var max = 0;
    var current = 0;
    for (var i = 0; i < 24; i++) {
      var count = board[i];
      var isOwn = (player === 0) ? count >= 2 : count <= -2;
      if (isOwn) {
        current++;
        if (current > max) max = current;
      } else {
        current = 0;
      }
    }
    return max;
  }

  function countBlots(board, player) {
    var blots = [];
    for (var i = 0; i < 24; i++) {
      var count = board[i];
      var isBlot = (player === 0) ? count === 1 : count === -1;
      if (isBlot) blots.push(i);
    }
    return blots;
  }

  function countAnchors(board, player) {
    var count = 0;
    var oppHomeStart = (player === 0) ? 18 : 0;
    var oppHomeEnd = (player === 0) ? 23 : 5;
    for (var i = oppHomeStart; i <= oppHomeEnd; i++) {
      var val = board[i];
      var isOwn = (player === 0) ? val >= 2 : val <= -2;
      if (isOwn) count++;
    }
    return count;
  }

  function isInOpponentHome(point, player) {
    if (player === 0) return point >= 18 && point <= 23;
    return point >= 0 && point <= 5;
  }

  return {
    chooseMove: chooseMove
  };
})();
