import 'package:puissance4/coordinate.dart';

import 'match_page.dart';

class Board {
  List<List<Color?>> _boxes = List.generate(
    7,
    (i) => List.generate(
      7,
      (i) => null,
    ),
  );

  Board();

  Board.from(List<List<Color?>> boxes) {
    _boxes = boxes;
  }

  Color? getBox(Coordinate coordinate) => _boxes[coordinate.col ?? 0][coordinate.row ?? 0];

  int getColumnTarget(int? col) => _boxes[col ?? 0].lastIndexOf(null);

  void setBox(Coordinate coordinate, Color? player) =>
      _boxes[coordinate.col ?? 0][coordinate.row ?? 0] = player;

  bool checkWinner(Coordinate coordinate, Color? player) {
    return checkHorizontally(coordinate, player) ||
        checkVertically(coordinate, player) ||
        checkDiagonally(coordinate, player);
  }

  bool checkHorizontally(Coordinate coordinate, Color? player) {
    var r = 0;
    for (;
        (coordinate.col ?? 0) + r < 7 &&
            r < 4 &&
            getBox(coordinate.copyWith(col: (coordinate.col ?? 0) + r)) == player;
        ++r) {}
    if (r >= 4) {
      return true;
    }

    var l = 0;
    for (;
        (coordinate.col ?? 0) - l >= 0 &&
            l < 4 &&
            getBox(coordinate.copyWith(col: (coordinate.col ?? 0) - l)) == player;
        ++l) {}
    if (l >= 4 || l + r >= 5) {
      return true;
    }

    return false;
  }

  bool checkDiagonally(Coordinate coordinate, Color? player) {
    var ur = 0;
    for (;
        (coordinate.col ?? 0) + ur < 7 &&
            (coordinate.row ?? 0) + ur < 7 &&
            ur < 4 &&
            getBox(coordinate.copyWith(
                  col: (coordinate.col ?? 0) + ur,
                  row: (coordinate.row ?? 0) + ur,
                )) ==
                player;
        ++ur) {}
    if (ur >= 4) {
      return true;
    }
    var dl = 0;
    for (;
        (coordinate.col ?? 0) - dl >= 0 &&
            (coordinate.row ?? 0) - dl >= 0 &&
            dl < 4 &&
            getBox(coordinate.copyWith(
                  col: (coordinate.col ?? 0) - dl,
                  row: (coordinate.row ?? 0) - dl,
                )) ==
                player;
        ++dl) {}
    if (dl >= 4 || dl + ur >= 5) {
      return true;
    }

    var dr = 0;
    for (;
        (coordinate.col ?? 0) + dr < 7 &&
            (coordinate.row ?? 0) - dr >= 0 &&
            dr < 4 &&
            getBox(coordinate.copyWith(
                  col: (coordinate.col ?? 0) + dr,
                  row: (coordinate.row ?? 0) - dr,
                )) ==
                player;
        ++dr) {}
    if (dr >= 4) {
      return true;
    }

    var ul = 0;
    for (;
        (coordinate.col ?? 0) - ul >= 0 &&
            (coordinate.row ?? 0) + ul < 7 &&
            ul < 4 &&
            getBox(coordinate.copyWith(
                  col: (coordinate.col ?? 0) - ul,
                  row: (coordinate.row ?? 0) + ul,
                )) ==
                player;
        ++ul) {}
    if (ul >= 4 || dr + ul >= 5) {
      return true;
    }
    return false;
  }

  bool checkVertically(Coordinate coordinate, Color? player) {
    var u = 0;
    for (;
        (coordinate.row ?? 0) + u < 7 &&
            u < 4 &&
            getBox(coordinate.copyWith(
                  row: (coordinate.row ?? 0) + u,
                )) ==
                player;
        ++u) {}
    if (u >= 4) {
      return true;
    }
    var d = 0;
    for (;
        (coordinate.row ?? 0) - d >= 0 &&
            d < 4 &&
            getBox(coordinate.copyWith(
                  row: (coordinate.row ?? 0) - d,
                )) ==
                player;
        ++d) {}
    if (d >= 4 || d + u >= 5) {
      return true;
    }

    return false;
  }

  Board clone() {
    return Board.from(_boxes.map((c) => c.map((b) => b).toList()).toList());
  }
}