import { Chess } from "chess.js";
import type { GamePlugin, GameResult, GameOverResult } from "../types";
import type { ChessState, ChessAction } from "./types";

function getPlayerColor(state: ChessState, playerId: string): "white" | "black" | null {
    if (state.players.white === playerId) return "white";
    if (state.players.black === playerId) return "black";
    return null;
}

function deriveStatus(game: Chess): ChessState["status"] {
    if (game.isCheckmate()) return "checkmate";
    if (game.isStalemate()) return "stalemate";
    if (game.isDraw()) return "draw";
    return "playing";
}

export const chessPlugin: GamePlugin<ChessState, ChessAction> = {
    slug: "chess",
    name: "Chess",
    minPlayers: 2,
    maxPlayers: 2,

    createInitialState(players: string[]): ChessState {
        const game = new Chess();
        return {
            fen: game.fen(),
            players: { white: players[0]!, black: players[1]! },
            moveHistory: [],
            status: "playing",
            winner: null,
        };
    },

    handleAction(state: ChessState, action: ChessAction, playerId: string): GameResult<ChessState> {
        if (state.status !== "playing") {
            return { ok: false, error: "Game is already over" };
        }

        const solo = state.players.white === state.players.black;

        if (action.type === "forfeit") {
            if (solo) return { ok: true, state: { ...state, status: "forfeit", winner: null } };
            const color = getPlayerColor(state, playerId);
            if (!color) return { ok: false, error: "You are not a player in this game" };
            const winner = color === "white" ? state.players.black : state.players.white;
            return { ok: true, state: { ...state, status: "forfeit", winner } };
        }

        if (action.type === "move") {
            const game = new Chess(state.fen);
            const turn = game.turn() === "w" ? "white" : "black";

            if (!solo) {
                const playerColor = getPlayerColor(state, playerId);
                if (!playerColor) return { ok: false, error: "You are not a player in this game" };
                if (playerColor !== turn) return { ok: false, error: "It is not your turn" };
            }

            let move;
            try {
                move = game.move({
                    from: action.from,
                    to: action.to,
                    promotion: action.promotion ?? "q",
                });
            } catch {
                return { ok: false, error: "Invalid move" };
            }

            if (!move) return { ok: false, error: "Invalid move" };

            const status = deriveStatus(game);
            const winner = status === "checkmate"
                ? (turn === "white" ? state.players.white : state.players.black)
                : null;

            return {
                ok: true,
                state: {
                    ...state,
                    fen: game.fen(),
                    moveHistory: [...state.moveHistory, move.san],
                    status,
                    winner,
                },
            };
        }

        return { ok: false, error: "Unknown action type" };
    },

    getPlayerView(state: ChessState, playerId: string): ChessState {
        const playerColor = getPlayerColor(state, playerId);
        if (!playerColor) return state;
        return state;
    },
    getSpectatorView(state: ChessState): ChessState { return state; },

    isGameOver(state: ChessState): GameOverResult | null {
        if (state.status === "playing") return null;
        return { winner: state.winner, reason: state.status };
    },

    onPlayerDisconnect(state: ChessState, playerId: string): ChessState {
        if (state.players.white === state.players.black) {
            return { ...state, status: "forfeit", winner: null };
        }
        const color = getPlayerColor(state, playerId);
        if (!color) return state;
        const winner = color === "white" ? state.players.black : state.players.white;
        return { ...state, status: "forfeit", winner };
    },
};
