import type { GamePlugin, GameResult, GameOverResult } from "../types";
import type { ChessState, ChessAction, Piece, PieceColor, PieceType } from "./types";

const BACK_ROW: PieceType[] = ["rook", "knight", "bishop", "queen", "king", "bishop", "knight", "rook"];

function createStartingBoard(): (Piece | null)[][] {
    const board: (Piece | null)[][] = Array.from({ length: 8 }, () => Array(8).fill(null));
    for (let col = 0; col < 8; col++) {
        board[0][col] = { type: BACK_ROW[col], color: "black" };
        board[1][col] = { type: "pawn", color: "black" };
        board[6][col] = { type: "pawn", color: "white" };
        board[7][col] = { type: BACK_ROW[col], color: "white" };
    }
    return board;
}

function inBounds(row: number, col: number): boolean {
    return row >= 0 && row < 8 && col >= 0 && col < 8;
}

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

function isValidMove(board: (Piece | null)[][], from: [number, number], to: [number, number], piece: Piece): boolean {
    const [fromRow, fromCol] = from;
    const [toRow, toCol] = to;
    const target = board[toRow][toCol];
    if (target && target.color === piece.color) return false;
    const rowDiff = toRow - fromRow;
    const colDiff = toCol - fromCol;
    const absRow = Math.abs(rowDiff);
    const absCol = Math.abs(colDiff);

    switch (piece.type) {
        case "pawn": {
            const direction = piece.color === "white" ? -1 : 1;
            const startRow = piece.color === "white" ? 6 : 1;
            if (colDiff === 0 && rowDiff === direction && !target) return true;
            if (colDiff === 0 && rowDiff === 2 * direction && fromRow === startRow && !target && !board[fromRow + direction][fromCol]) return true;
            if (absCol === 1 && rowDiff === direction && target) return true;
            return false;
        }
        case "rook":
            if (fromRow !== toRow && fromCol !== toCol) return false;
            return isPathClear(board, from, to);
        case "knight":
            return (absRow === 2 && absCol === 1) || (absRow === 1 && absCol === 2);
        case "bishop":
            if (absRow !== absCol) return false;
            return isPathClear(board, from, to);
        case "queen":
            if (fromRow !== toRow && fromCol !== toCol && absRow !== absCol) return false;
            return isPathClear(board, from, to);
        case "king":
            return absRow <= 1 && absCol <= 1;
        default:
            return false;
    }
}

function isPathClear(board: (Piece | null)[][], from: [number, number], to: [number, number]): boolean {
    const [fromRow, fromCol] = from;
    const [toRow, toCol] = to;
    const rowStep = Math.sign(toRow - fromRow);
    const colStep = Math.sign(toCol - fromCol);
    let row = fromRow + rowStep;
    let col = fromCol + colStep;
    while (row !== toRow || col !== toCol) {
        if (board[row][col]) return false;
        row += rowStep;
        col += colStep;
    }
    return true;
}

function toAlgebraic(from: [number, number], to: [number, number], piece: Piece, captured: boolean): string {
    const files = "abcdefgh";
    const prefix = piece.type === "pawn" ? "" : piece.type[0].toUpperCase();
    const cap = captured ? "x" : "";
    const fromStr = piece.type === "pawn" && captured ? files[from[1]] : "";
    return `${prefix}${fromStr}${cap}${files[to[1]]}${8 - to[0]}`;
}

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

    createInitialState(players: string[]): ChessState {
        return {
            board: createStartingBoard(),
            currentTurn: "white",
            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" };
        }
        if (action.type === "forfeit") {
            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 { from, to } = action;
            if (!inBounds(from[0], from[1]) || !inBounds(to[0], to[1])) {
                return { ok: false, error: "Coordinates out of bounds" };
            }
            const piece = state.board[from[0]][from[1]];
            if (!piece) return { ok: false, error: "No piece at source square" };
            const playerColor = getPlayerColor(state, playerId);
            if (!playerColor) return { ok: false, error: "You are not a player in this game" };
            if (playerColor !== state.currentTurn) return { ok: false, error: "It is not your turn" };
            if (piece.color !== playerColor) return { ok: false, error: "That is not your piece" };
            if (!isValidMove(state.board, from, to, piece)) return { ok: false, error: "Invalid move" };

            const newBoard = state.board.map(row => [...row]);
            const captured = newBoard[to[0]][to[1]];
            newBoard[to[0]][to[1]] = piece;
            newBoard[from[0]][from[1]] = null;
            const notation = toAlgebraic(from, to, piece, captured !== null);
            const nextTurn: PieceColor = state.currentTurn === "white" ? "black" : "white";

            return {
                ok: true,
                state: { ...state, board: newBoard, currentTurn: nextTurn, moveHistory: [...state.moveHistory, notation] },
            };
        }
        return { ok: false, error: "Unknown action type" };
    },

    getPlayerView(state: ChessState, _playerId: string): ChessState { 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 {
        const color = getPlayerColor(state, playerId);
        if (!color) return state;
        const winner = color === "white" ? state.players.black : state.players.white;
        return { ...state, status: "forfeit", winner };
    },
};
