/**
 * MoveValidator.js - Chess move validation engine
 * Validates moves including check constraints
 */

export class MoveValidator {
    /**
     * Check if move is legal (including check validation)
     * @param {Board} board - Game board
     * @param {Piece} piece - Piece to move
     * @param {number} toRow - Target row
     * @param {number} toCol - Target column
     * @param {GameState} gameState - Game state
     * @returns {boolean} True if legal
     */
    static isMoveLegal(board, piece, toRow, toCol, gameState) {
        // 1. Check if move is in piece's valid moves
        if (!piece.isValidMove(board, toRow, toCol)) {
            return false;
        }

        // 2. Simulate move to check if it leaves king in check
        const simulatedBoard = this.simulateMove(board, piece, toRow, toCol);

        // 3. Verify own king is not in check after move
        if (this.isKingInCheck(simulatedBoard, piece.color)) {
            return false;
        }

        return true;
    }

    /**
     * Simulate a move on a cloned board
     * @param {Board} board - Original board
     * @param {Piece} piece - Piece to move
     * @param {number} toRow - Target row
     * @param {number} toCol - Target column
     * @returns {Board} Board with simulated move
     */
    static simulateMove(board, piece, toRow, toCol) {
        const clonedBoard = board.clone();
        const fromRow = piece.position.row;
        const fromCol = piece.position.col;

        clonedBoard.movePiece(fromRow, fromCol, toRow, toCol);

        return clonedBoard;
    }

    /**
     * Check if king is in check
     * @param {Board} board - Game board
     * @param {string} color - King color ('white' or 'black')
     * @returns {boolean} True if in check
     */
    static isKingInCheck(board, color) {
        // Find king position
        const kingPos = board.findKing(color);
        if (!kingPos) return false;

        // Check if any opponent piece can attack king
        const opponentColor = color === 'white' ? 'black' : 'white';

        for (let row = 0; row < 8; row++) {
            for (let col = 0; col < 8; col++) {
                const piece = board.getPiece(row, col);

                if (piece && piece.color === opponentColor) {
                    // Get piece's valid moves (without recursion into check validation)
                    const validMoves = piece.getValidMoves(board);

                    // Check if king position is in attack range
                    if (validMoves.some(move =>
                        move.row === kingPos.row && move.col === kingPos.col)) {
                        return true;
                    }
                }
            }
        }

        return false;
    }

    /**
     * Check if position is checkmate
     * @param {Board} board - Game board
     * @param {string} color - Player color
     * @param {GameState} gameState - Game state
     * @returns {boolean} True if checkmate
     */
    static isCheckmate(board, color, gameState) {
        // Must be in check for checkmate
        if (!this.isKingInCheck(board, color)) {
            return false;
        }

        // Check if any legal move exists
        return !this.hasAnyLegalMove(board, color, gameState);
    }

    /**
     * Check if position is stalemate
     * @param {Board} board - Game board
     * @param {string} color - Player color
     * @param {GameState} gameState - Game state
     * @returns {boolean} True if stalemate
     */
    static isStalemate(board, color, gameState) {
        // Must NOT be in check for stalemate
        if (this.isKingInCheck(board, color)) {
            return false;
        }

        // No legal moves available
        return !this.hasAnyLegalMove(board, color, gameState);
    }

    /**
     * Check if player has any legal move
     * @param {Board} board - Game board
     * @param {string} color - Player color
     * @param {GameState} gameState - Game state
     * @returns {boolean} True if at least one legal move exists
     */
    static hasAnyLegalMove(board, color, gameState) {
        // Check all pieces of this color
        for (let row = 0; row < 8; row++) {
            for (let col = 0; col < 8; col++) {
                const piece = board.getPiece(row, col);

                if (piece && piece.color === color) {
                    // Get all valid moves for this piece
                    const validMoves = piece.getValidMoves(board);

                    // Check if any move is legal (doesn't leave king in check)
                    for (const move of validMoves) {
                        if (this.isMoveLegal(board, piece, move.row, move.col, gameState)) {
                            return true;
                        }
                    }

                    // Check special moves for pawns and kings
                    if (piece.type === 'pawn' && piece.getEnPassantMoves) {
                        const enPassantMoves = piece.getEnPassantMoves(board, gameState);
                        for (const move of enPassantMoves) {
                            if (this.isMoveLegal(board, piece, move.row, move.col, gameState)) {
                                return true;
                            }
                        }
                    }

                    if (piece.type === 'king' && piece.getCastlingMoves) {
                        const castlingMoves = piece.getCastlingMoves(board, gameState);
                        for (const move of castlingMoves) {
                            if (this.canCastleToPosition(board, piece, move.col, gameState)) {
                                return true;
                            }
                        }
                    }
                }
            }
        }

        return false;
    }

    /**
     * Get all legal moves for a piece
     * @param {Board} board - Game board
     * @param {Piece} piece - Piece to check
     * @param {GameState} gameState - Game state
     * @returns {Position[]} Array of legal positions
     */
    static getLegalMoves(board, piece, gameState) {
        const legalMoves = [];

        // Get valid moves (piece-specific rules)
        const validMoves = piece.getValidMoves(board);

        // Filter by check constraint
        for (const move of validMoves) {
            if (this.isMoveLegal(board, piece, move.row, move.col, gameState)) {
                legalMoves.push(move);
            }
        }

        // Add special moves
        if (piece.type === 'pawn' && piece.getEnPassantMoves) {
            const enPassantMoves = piece.getEnPassantMoves(board, gameState);
            for (const move of enPassantMoves) {
                if (this.isMoveLegal(board, piece, move.row, move.col, gameState)) {
                    legalMoves.push(move);
                }
            }
        }

        if (piece.type === 'king' && piece.getCastlingMoves) {
            const castlingMoves = piece.getCastlingMoves(board, gameState);
            for (const move of castlingMoves) {
                if (this.canCastleToPosition(board, piece, move.col, gameState)) {
                    legalMoves.push(move);
                }
            }
        }

        return legalMoves;
    }

    /**
     * Check if castling to position is legal
     * @param {Board} board - Game board
     * @param {King} king - King piece
     * @param {number} targetCol - Target column (2 or 6)
     * @param {GameState} gameState - Game state
     * @returns {boolean} True if castling is legal
     */
    static canCastleToPosition(board, king, targetCol, gameState) {
        // King can't be in check
        if (this.isKingInCheck(board, king.color)) {
            return false;
        }

        const row = king.position.row;
        const direction = targetCol > king.position.col ? 1 : -1;

        // King can't pass through check
        for (let col = king.position.col + direction;
            col !== targetCol + direction;
            col += direction) {

            const simulatedBoard = board.clone();
            simulatedBoard.movePiece(king.position.row, king.position.col, row, col);

            if (this.isKingInCheck(simulatedBoard, king.color)) {
                return false;
            }
        }

        return true;
    }

    /**
     * Check for insufficient material (automatic draw)
     * @param {Board} board - Game board
     * @returns {boolean} True if insufficient material
     */
    static isInsufficientMaterial(board) {
        const pieces = {
            white: board.getPiecesByColor('white'),
            black: board.getPiecesByColor('black')
        };

        // King vs King
        if (pieces.white.length === 1 && pieces.black.length === 1) {
            return true;
        }

        // King and Bishop vs King or King and Knight vs King
        for (const color of ['white', 'black']) {
            if (pieces[color].length === 2) {
                const nonKing = pieces[color].find(p => p.type !== 'king');
                if (nonKing && (nonKing.type === 'bishop' || nonKing.type === 'knight')) {
                    const otherColor = color === 'white' ? 'black' : 'white';
                    if (pieces[otherColor].length === 1) {
                        return true;
                    }
                }
            }
        }

        // King and Bishop vs King and Bishop (same color squares)
        if (pieces.white.length === 2 && pieces.black.length === 2) {
            const whiteBishop = pieces.white.find(p => p.type === 'bishop');
            const blackBishop = pieces.black.find(p => p.type === 'bishop');

            if (whiteBishop && blackBishop) {
                const whiteSquareColor = (whiteBishop.position.row + whiteBishop.position.col) % 2;
                const blackSquareColor = (blackBishop.position.row + blackBishop.position.col) % 2;

                if (whiteSquareColor === blackSquareColor) {
                    return true;
                }
            }
        }

        return false;
    }
}
