
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Random;

public class GomokuGame {

    public static final int DEFAULT_BOARD_WIDTH = 15; // largeur du plateau
    public static final int DEFAULT_BOARD_HEIGHT = 15; // hauteur du plateau
    public static final int DEFAULT_TOKENS_COUNT = 60; // nb de jetons
    public static final int NB_CELL_PLAY = 5; // nb de jetons

    private Player player1;
    private Player player2;

    private GomokuBoard board;

    private GomokuRenderer renderer;

    Color colorP1;
    int currP;
    int nbTokens1, nbTokens2;

    public static void main(String[] args) {
        // Test
        GomokuGame g = new GomokuGame();
        System.out.println(g.load(Path.of(".cache/test.dat")));
        g.renderer = new ConsoleRenderer();
        g.renderer.init(g);
        g.renderer.update();
        g.board.expandBoard(Cardinal.SE);
        g.renderer.update();
    }

    public void newGame(boolean bot, String name1, String name2) {
        Color[] possible = { Color.WHITE, Color.BLACK };
        int rnd = new Random().nextInt(possible.length);
        Color colorPlayer1 = possible[rnd];
        Color colorPlayer2 = colorPlayer1.inverse();

        this.player1 = new Human(name1, colorPlayer1);

        if (bot) {
            this.player2 = new GomokuAI(name2, colorPlayer2);

        } else {
            this.player2 = new Human(name2, colorPlayer2);
        }

        this.board = new GomokuBoard(15, 15);
        this.colorP1 = colorPlayer1;
        this.currP = this.player1.color == Color.WHITE ? 1 : 2;
        this.nbTokens1 = 60;
        this.nbTokens2 = 60;

    }

    public void startGame() {

        GomokuCell actualPlayedCell = play(player1);
        if( NB_CELL_PLAY >= board.countMax(board.countAlignedCells(actualPlayedCell)))
        {
           System.out.println("c'est gangée !");
        }
        
    }

    /**
    * Place the token on the cell where the player play.
    * @param Player get player to play the cell.
    */
    public GomokuCell play(Player player) {

        GomokuCell cellToPlay = player.chooseMove(board);
        cellToPlay.setState(player.color);
        return cellToPlay;
    }
    


    public boolean save(Path filename) {
        // save the game state to the file
        // 1. Open the file
        // 2. Write the first line with:
        // w h colorP1 currP nbTokens1 nbTokens2
        // 3. Write the next h lines with the board
        // 4. Close the file
        // 5. Return true if successful, false otherwise

        // if filename is null, save to default file in ".cache/save.dat"
        if (filename == null) {
            filename = Path.of(".cache/save.dat");
        }

        try (BufferedWriter writer = Files.newBufferedWriter(filename)) {
            // Write the first line
            writer.write(String.format("%d %d %s %d %d %d%n",
                    this.getBoard().getWidth(),
                    this.getBoard().getHeight(),
                    colorP1,
                    currP,
                    nbTokens1,
                    nbTokens2
                ));

            // Write the board
            for (int i = 0; i < this.getBoard().getHeight(); ++i) {
                for (int j = 0; j < this.getBoard().getWidth(); ++j) {
                    char c = ' ';
                    switch (board.get(i, j).getState()) {
                        case BLACK:
                            c = 'X';
                            break;
                        case WHITE:

                            break;
                        case NIL:
                            c = '.';
                            break;
                        default:
                            throw new IllegalStateException(
                                    String.format("Unexpected value at cell (%d, %d): %s", i, j,
                                            board.get(i, j).getState()));
                    }
                    writer.write(c);
                }
                writer.newLine();
            }
        } catch (IOException e) {
            System.err.println("Error writing file: " + e.getMessage());
            return false;
        } catch (Exception e) {
            System.err.println("Unexpected error: " + e.getMessage());
            return false;
        }
        return true;
    }

    public boolean load(Path filename) {
        // load the game state from the file
        // 1. Open the file
        // 2. Read the first line to get:
        // w h colorP1 currP nbTokens1 nbTokens2
        // 3. Read the next h lines to get the board
        // 4. Close the file
        // 5. Initialize the board with the read values

        int w, h;
        Color[][] colors;

        try (BufferedReader reader = Files.newBufferedReader(filename)) {
            String line = reader.readLine();
            if (line == null) {
                throw new IOException("Empty save file");
            }

            String[] parts = line.split(" ");
            if (parts.length != 6) {
                throw new IOException("Invalid save file format");
            }
            w = Integer.parseInt(parts[0]);
            h = Integer.parseInt(parts[1]);
            colorP1 = Color.valueOf(parts[2]);
            currP = Integer.parseInt(parts[3]);
            nbTokens1 = Integer.parseInt(parts[4]);
            nbTokens2 = Integer.parseInt(parts[5]);

            if (w <= 0 || h <= 0) {
                throw new IllegalArgumentException("Invalid board dimensions");
            }

            colors = new Color[h][w];

            for (int i = 0; i < h; ++i) {
                line = reader.readLine();
                if (line == null) {
                    throw new IOException("Unexpected end of file");
                }

                if (line.length() != w) {
                    throw new IOException("Invalid board line format");
                }

                for (int j = 0; j < w; ++j) {
                    switch (line.charAt(j)) {
                        case 'X':
                            colors[i][j] = Color.BLACK;
                            break;
                        case 'O':
                            colors[i][j] = Color.WHITE;
                            break;
                        case '.':
                            colors[i][j] = Color.NIL;
                            break;
                        default:
                            throw new IllegalArgumentException("Invalid color: " + line.charAt(j));
                    }
                }
            }

        } catch (IOException e) {
            System.err.println("Error reading file: " + e.getMessage());
            return false;
        } catch (NumberFormatException e) {
            System.err.println("Invalid number format: " + e.getMessage());
            return false;
        } catch (IllegalArgumentException e) {
            System.err.println("Invalid color format: " + e.getMessage());
            return false;
        } catch (Exception e) {
            System.err.println("Unexpected error: " + e.getMessage());
            return false;
        }

        // Initialize the board with the read values
        this.board = new GomokuBoard(w, h, colors);

        return true;
    }

    public GomokuBoard getBoard() {
        return this.board;
    }
}
