import 'package:solitaire_game/entities/tile.dart';
import 'package:solitaire_game/layout/game.dart';
import 'package:solitaire_game/provider/data.dart';
import 'package:solitaire_game/utils/board_utils.dart';

class GameUtils {
  static Future<void> quitGame(Data myProvider) async {
    myProvider.updateGameIsRunning(false);
  }

  static Future<void> startNewGame(Data myProvider) async {
    print('Starting game');

    BoardUtils.createNewBoard(myProvider);

    myProvider.updateGameIsRunning(true);
  }

  static void deleteSavedGame(Data myProvider) {
    myProvider.resetCurrentSavedState();
  }

  static void resumeSavedGame(Data myProvider) {
    Map<String, dynamic> savedState = myProvider.getCurrentSavedState();
    if (savedState.isNotEmpty) {
      try {
        myProvider.setParameterValue('skin', savedState['skin']);
        myProvider.updateMovesCount(int.parse(savedState['movesCount']));
        myProvider.updateBoard(
            BoardUtils.createBoardFromSavedState(myProvider, savedState['boardValues']));

        myProvider.updateGameIsRunning(true);
      } catch (e) {
        print('Failed to resume game. Will start new one instead.');
        myProvider.resetCurrentSavedState();
        myProvider.initParametersValues();
        startNewGame(myProvider);
      }
    } else {
      myProvider.resetCurrentSavedState();
      myProvider.initParametersValues();
      startNewGame(myProvider);
    }
  }

  static bool isMoveAllowed(Data myProvider, List<int> source, List<int> target) {
    List<List<Tile?>> board = myProvider.board;
    int sourceCol = source[0];
    int sourceRow = source[1];
    int targetCol = target[0];
    int targetRow = target[1];

    // ensure source exists and has a peg
    if (board[sourceRow][sourceCol] == null || board[sourceRow][sourceCol]?.hasPeg == false) {
      print('move forbidden: source peg does not exist');
      return false;
    }

    // ensure target exists and is empty
    if (board[targetRow][targetCol] == null || board[targetRow][targetCol]?.hasPeg == true) {
      print('move forbidden: target does not exist or already with a peg');
      return false;
    }

    // ensure source and target are in the same line/column
    if ((targetCol != sourceCol) && (targetRow != sourceRow)) {
      print('move forbidden: source and target are not in the same line or column');
      return false;
    }

    // ensure source and target are separated by exactly one tile
    if (((targetCol == sourceCol) && ((targetRow - sourceRow).abs() != 2)) ||
        ((targetRow == sourceRow) && ((targetCol - sourceCol).abs() != 2))) {
      print('move forbidden: source and target must be separated by exactly one tile');
      return false;
    }

    // ensure middle tile exists and has a peg
    int middleRow = (sourceRow + ((targetRow - sourceRow) / 2)).round();
    int middleCol = (sourceCol + ((targetCol - sourceCol) / 2)).round();
    if (board[middleRow][middleCol] == null || board[middleRow][middleCol]?.hasPeg == false) {
      print('move forbidden: tile between source and target does not contain a peg');
      return false;
    }

    // ok, move is allowed
    return true;
  }

  static void move(Data myProvider, List<int> source, List<int> target) {
    print('Move from ' + source.toString() + ' to ' + target.toString());
    int sourceCol = source[0];
    int sourceRow = source[1];
    int targetCol = target[0];
    int targetRow = target[1];

    int middleRow = (sourceRow + ((targetRow - sourceRow) / 2)).round();
    int middleCol = (sourceCol + ((targetCol - sourceCol) / 2)).round();

    // remove peg from source
    myProvider.updatePegValue(sourceRow, sourceCol, false);
    // put peg in target
    myProvider.updatePegValue(targetRow, targetCol, true);
    // remove peg from middle tile
    myProvider.updatePegValue(middleRow, middleCol, false);

    // increment moves count
    myProvider.incrementMovesCount();
    // update remaining pegs count
    myProvider.updateRemainingPegsCount(GameUtils.countRemainingPegs(myProvider));
  }

  static int countRemainingPegs(Data myProvider) {
    int count = 0;

    List<List<Tile?>> board = myProvider.board;
    for (var rowIndex = 0; rowIndex < board.length; rowIndex++) {
      for (var colIndex = 0; colIndex < board[rowIndex].length; colIndex++) {
        Tile? tile = board[rowIndex][colIndex];
        if (tile != null && tile.hasPeg == true) {
          count++;
        }
      }
    }

    return count;
  }
}