package com.lona.tictactoe.server;

import java.io.PrintWriter;
import java.util.Arrays;

public class GameInstance {
    private final String code;
    private ClientHandler playerX; // Creator
    private ClientHandler playerO; // Joiner
    private final char[][] board = new char[3][3];
    private char currentTurn = 'X';
    private boolean finished = false;

    public GameInstance(String code, ClientHandler creator) {
        this.code = code;
        this.playerX = creator;
        for (char[] row : board) {
            Arrays.fill(row, ' ');
        }
    }

    public synchronized boolean join(ClientHandler joiner) {
        if (playerO != null)
            return false;
        this.playerO = joiner;
        broadcast("START X");
        sendBoard();
        return true;
    }

    public synchronized void move(ClientHandler player, int x, int y) {
        if (finished || playerO == null)
            return;

        char symbol = (player == playerX) ? 'X' : 'O';

        // --- ANTICHEAT / VALIDATION ---
        if (symbol != currentTurn) {
            player.sendMessage("ERROR: It is not your turn!");
            return;
        }

        if (x < 0 || x > 2 || y < 0 || y > 2) {
            player.sendMessage("ERROR: Invalid coordinates!");
            return;
        }

        if (board[x][y] != ' ') {
            player.sendMessage("ERROR: Cell occupied!");
            return;
        }

        board[x][y] = symbol;
        sendBoard();

        if (checkWin(symbol)) {
            finished = true;
            lastWinner = symbol;
            broadcast("WIN " + symbol);
        } else if (checkDraw()) {
            finished = true;
            broadcast("DRAW");
        } else {
            currentTurn = (currentTurn == 'X') ? 'O' : 'X';
            broadcast("TURN " + currentTurn);
        }
    }

    public synchronized void surrender(ClientHandler player) {
        if (finished)
            return;
        finished = true;
        char loser = (player == playerX) ? 'X' : 'O';
        char winner = (loser == 'X') ? 'O' : 'X';
        broadcast("WIN " + winner + " (Surrender)");
        lastWinner = winner;
    }

    private char lastWinner = ' ';

    public synchronized void restart() {
        // Determine who starts: The loser of the previous game.
        // If lastWinner was 'X', then 'O' (the loser) starts.
        // If lastWinner was 'O', then 'X' (the loser) starts.
        // If it was a draw or new game, default to 'X'.

        if (lastWinner == 'X') {
            currentTurn = 'O';
        } else if (lastWinner == 'O') {
            currentTurn = 'X';
        } else {
            currentTurn = 'X'; // Default for Draw/New
        }

        lastWinner = ' '; // Reset for next game
        finished = false;

        // Clear board
        for (char[] row : board)
            Arrays.fill(row, ' ');

        broadcast("RESTART");
        sendBoard();
        broadcast("TURN " + currentTurn);
    }

    public synchronized void leave(ClientHandler player) {
        if (player == playerX) {
            // Creator left, if playerO exists, tell them?
            if (playerO != null) {
                playerO.sendMessage("OPPONENT_LEFT");
            }
            playerX = null;
        } else if (player == playerO) {
            if (playerX != null) {
                playerX.sendMessage("OPPONENT_LEFT");
            }
            playerO = null;
        }
        // If empty, GameManager will eventually remove if we allow it,
        // but for now let's rely on GameManager to check if empty logic or just keep it
        // simple.
    }

    public synchronized boolean isEmpty() {
        return playerX == null && playerO == null;
    }

    public synchronized void disconnect(ClientHandler player) {
        leave(player);
    }

    private boolean checkWin(char s) {
        // Rows & Cols
        for (int i = 0; i < 3; i++) {
            if (board[i][0] == s && board[i][1] == s && board[i][2] == s)
                return true;
            if (board[0][i] == s && board[1][i] == s && board[2][i] == s)
                return true;
        }
        // Diagonals
        if (board[0][0] == s && board[1][1] == s && board[2][2] == s)
            return true;
        if (board[0][2] == s && board[1][1] == s && board[2][0] == s)
            return true;
        return false;
    }

    private boolean checkDraw() {
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                if (board[i][j] == ' ')
                    return false;
            }
        }
        return true;
    }

    private void sendBoard() {
        StringBuilder sb = new StringBuilder("BOARD ");
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                sb.append(board[i][j]);
            }
        }
        broadcast(sb.toString());
    }

    private void broadcast(String msg) {
        if (playerX != null)
            playerX.sendMessage(msg);
        if (playerO != null)
            playerO.sendMessage(msg);
    }
}
