/**
 * GameState.js - Chess game state management
 * Manages move history, game status, and metadata
 */

export class GameState {
    constructor() {
        this.moveHistory = [];
        this.capturedPieces = { white: [], black: [] };
        this.currentMove = 0;
        this.status = 'active'; // 'active', 'check', 'checkmate', 'stalemate', 'draw', 'resigned'
        this.enPassantTarget = null;
        this.halfMoveClock = 0; // For 50-move rule
        this.fullMoveNumber = 1;
        this.drawOffer = null;
    }

    /**
     * Record a move in history
     * @param {Move} move - Move object
     */
    recordMove(move) {
        // Truncate history if we're not at the end
        if (this.currentMove < this.moveHistory.length) {
            this.moveHistory = this.moveHistory.slice(0, this.currentMove);
        }

        this.moveHistory.push(move);
        this.currentMove++;

        // Update half-move clock
        if (move.piece.type === 'pawn' || move.captured) {
            this.halfMoveClock = 0;
        } else {
            this.halfMoveClock++;
        }

        // Update full-move number (after black's move)
        if (move.piece.color === 'black') {
            this.fullMoveNumber++;
        }

        // Track captured pieces
        if (move.captured) {
            this.capturedPieces[move.captured.color].push(move.captured);
        }
    }

    /**
     * Get the last move
     * @returns {Move|null} Last move or null
     */
    getLastMove() {
        if (this.moveHistory.length === 0) {
            return null;
        }
        return this.moveHistory[this.currentMove - 1];
    }

    /**
     * Undo to previous state
     * @returns {Move|null} Undone move or null
     */
    undo() {
        if (this.currentMove === 0) {
            return null;
        }

        this.currentMove--;
        const move = this.moveHistory[this.currentMove];

        // Remove captured piece from list
        if (move.captured) {
            const capturedList = this.capturedPieces[move.captured.color];
            const index = capturedList.indexOf(move.captured);
            if (index > -1) {
                capturedList.splice(index, 1);
            }
        }

        return move;
    }

    /**
     * Redo to next state
     * @returns {Move|null} Redone move or null
     */
    redo() {
        if (this.currentMove >= this.moveHistory.length) {
            return null;
        }

        const move = this.moveHistory[this.currentMove];
        this.currentMove++;

        // Re-add captured piece
        if (move.captured) {
            this.capturedPieces[move.captured.color].push(move.captured);
        }

        return move;
    }

    /**
     * Check if 50-move rule applies
     * @returns {boolean} True if 50 moves without capture or pawn move
     */
    isFiftyMoveRule() {
        return this.halfMoveClock >= 100; // 50 moves = 100 half-moves
    }

    /**
     * Check for threefold repetition
     * @param {string} currentFEN - Current position FEN
     * @returns {boolean} True if position repeated 3 times
     */
    isThreefoldRepetition(currentFEN) {
        if (this.moveHistory.length < 8) {
            return false; // Need at least 4 moves per side
        }

        let count = 0;

        // Count occurrences of current position in history
        for (const move of this.moveHistory) {
            if (move.fen === currentFEN) {
                count++;
                if (count >= 3) {
                    return true;
                }
            }
        }

        return false;
    }

    /**
     * Export full game state to FEN notation
     * @param {Board} board - Game board
     * @param {string} currentTurn - Current turn ('white' or 'black')
     * @returns {string} Complete FEN string
     */
    toFEN(board, currentTurn) {
        // 1. Piece placement
        const piecePlacement = board.toFEN();

        // 2. Active color
        const activeColor = currentTurn === 'white' ? 'w' : 'b';

        // 3. Castling availability
        let castling = '';
        const whiteKing = board.getPiece(7, 4);
        const blackKing = board.getPiece(0, 4);

        if (whiteKing && !whiteKing.hasMoved) {
            const kingsideRook = board.getPiece(7, 7);
            if (kingsideRook && !kingsideRook.hasMoved) {
                castling += 'K';
            }
            const queensideRook = board.getPiece(7, 0);
            if (queensideRook && !queensideRook.hasMoved) {
                castling += 'Q';
            }
        }

        if (blackKing && !blackKing.hasMoved) {
            const kingsideRook = board.getPiece(0, 7);
            if (kingsideRook && !kingsideRook.hasMoved) {
                castling += 'k';
            }
            const queensideRook = board.getPiece(0, 0);
            if (queensideRook && !queensideRook.hasMoved) {
                castling += 'q';
            }
        }

        if (castling === '') {
            castling = '-';
        }

        // 4. En passant target
        const enPassant = this.enPassantTarget ?
            this.positionToAlgebraic(this.enPassantTarget.row, this.enPassantTarget.col) :
            '-';

        // 5. Halfmove clock
        const halfmove = this.halfMoveClock;

        // 6. Fullmove number
        const fullmove = this.fullMoveNumber;

        return `${piecePlacement} ${activeColor} ${castling} ${enPassant} ${halfmove} ${fullmove}`;
    }

    /**
     * Export game to PGN notation
     * @param {Object} metadata - Game metadata
     * @returns {string} PGN formatted string
     */
    toPGN(metadata = {}) {
        const {
            event = 'Casual Game',
            site = 'Web Browser',
            date = new Date().toISOString().split('T')[0].replace(/-/g, '.'),
            white = 'Player 1',
            black = 'Player 2',
            result = this.status === 'checkmate' ? '1-0' : '*'
        } = metadata;

        let pgn = `[Event "${event}"]\n`;
        pgn += `[Site "${site}"]\n`;
        pgn += `[Date "${date}"]\n`;
        pgn += `[White "${white}"]\n`;
        pgn += `[Black "${black}"]\n`;
        pgn += `[Result "${result}"]\n\n`;

        // Add moves
        let moveNumber = 1;
        for (let i = 0; i < this.moveHistory.length; i++) {
            const move = this.moveHistory[i];

            if (move.piece.color === 'white') {
                pgn += `${moveNumber}. ${move.notation} `;
            } else {
                pgn += `${move.notation} `;
                moveNumber++;
            }

            // Add line break every 6 full moves for readability
            if (i % 12 === 11) {
                pgn += '\n';
            }
        }

        pgn += ` ${result}`;

        return pgn;
    }

    /**
     * Convert position to algebraic notation
     * @param {number} row - Row index
     * @param {number} col - Column index
     * @returns {string} Algebraic notation (e.g., "e4")
     */
    positionToAlgebraic(row, col) {
        const files = 'abcdefgh';
        const ranks = '87654321';
        return files[col] + ranks[row];
    }

    /**
     * Reset game state to initial
     */
    reset() {
        this.moveHistory = [];
        this.capturedPieces = { white: [], black: [] };
        this.currentMove = 0;
        this.status = 'active';
        this.enPassantTarget = null;
        this.halfMoveClock = 0;
        this.fullMoveNumber = 1;
        this.drawOffer = null;
    }

    /**
     * Update en passant target after a move
     * @param {Piece} piece - Moved piece
     * @param {number} fromRow - Source row
     * @param {number} toRow - Target row
     */
    updateEnPassantTarget(piece, fromRow, toRow) {
        if (piece.type === 'pawn' && Math.abs(toRow - fromRow) === 2) {
            const targetRow = (fromRow + toRow) / 2;
            this.enPassantTarget = { row: targetRow, col: piece.position.col };
        } else {
            this.enPassantTarget = null;
        }
    }
}
