/**
 * GameController.js - Main chess game controller
 * Orchestrates game flow, move execution, and state management
 */

import { Board } from '../game/Board.js';
import { GameState } from '../game/GameState.js';
import { MoveValidator } from '../engine/MoveValidator.js';
import { SpecialMoves } from '../engine/SpecialMoves.js';

export class GameController {
    constructor(config = {}) {
        this.board = new Board();
        this.board.setupInitialPosition();

        this.gameState = new GameState();
        this.currentTurn = 'white';
        this.selectedSquare = null;

        this.config = {
            autoSave: config.autoSave !== false,
            enableTimer: config.enableTimer || false,
            timeControl: config.timeControl || null
        };

        // Event handling
        this.eventHandlers = {};
    }

    /**
     * Make a chess move
     * @param {number} fromRow - Source row
     * @param {number} fromCol - Source column
     * @param {number} toRow - Target row
     * @param {number} toCol - Target column
     * @returns {MoveResult} Result of the move
     */
    makeMove(fromRow, fromCol, toRow, toCol) {
        const piece = this.board.getPiece(fromRow, fromCol);

        // Validation
        if (!piece) {
            return { success: false, error: 'No piece at source position' };
        }

        if (piece.color !== this.currentTurn) {
            return { success: false, error: 'Not your turn' };
        }

        if (!MoveValidator.isMoveLegal(this.board, piece, toRow, toCol, this.gameState)) {
            return { success: false, error: 'Invalid move' };
        }

        // Detect special moves
        const specialMoveType = SpecialMoves.detectSpecialMove(
            this.board, piece, fromRow, fromCol, toRow, toCol, this.gameState
        );

        // Execute move
        const moveResult = this.executeMove(piece, fromRow, fromCol, toRow, toCol, specialMoveType);

        // Update game state
        this.gameState.updateEnPassantTarget(piece, fromRow, toRow);

        // Switch turns
        this.currentTurn = this.currentTurn === 'white' ? 'black' : 'white';

        // Check game status
        this.updateGameStatus();

        // Emit event
        this.emit('move', { move: moveResult, gameStatus: this.gameState.status });

        // Auto-save if enabled
        if (this.config.autoSave) {
            this.save();
        }

        return {
            success: true,
            move: moveResult,
            gameStatus: this.gameState.status
        };
    }

    /**
     * Execute a move (including special moves)
     * @param {Piece} piece - Piece to move
     * @param {number} fromRow - Source row
     * @param {number} fromCol - Source column
     * @param {number} toRow - Target row
     * @param {number} toCol - Target column
     * @param {string} specialMoveType - Type of special move or null
     * @returns {Move} Move object
     */
    executeMove(piece, fromRow, fromCol, toRow, toCol, specialMoveType) {
        let captured = null;
        let promotedTo = null;

        if (specialMoveType === 'castle-kingside' || specialMoveType === 'castle-queenside') {
            // Execute castling
            SpecialMoves.executeCastle(this.board, piece, toCol);
        } else if (specialMoveType === 'en-passant') {
            // Execute en passant
            captured = SpecialMoves.executeEnPassant(this.board, piece, toRow, toCol);
        } else {
            // Normal move
            const moveResult = this.board.movePiece(fromRow, fromCol, toRow, toCol);
            captured = moveResult.captured;

            // Check for promotion - emit event WITHOUT auto-promoting
            if (specialMoveType === 'promotion' || (piece.type === 'pawn' && piece.canPromote())) {
                // Emit promotion event for UI to handle - DON'T auto-promote yet
                this.emit('promotion', { pawn: piece, position: { row: toRow, col: toCol } });
                // promotedTo will be set when the UI calls back with the chosen piece
            }
        }

        // Generate move notation
        const notation = this.generateNotation(piece, fromRow, fromCol, toRow, toCol, captured, specialMoveType);

        // Create move object
        const move = {
            from: { row: fromRow, col: fromCol },
            to: { row: toRow, col: toCol },
            piece: piece,
            captured: captured,
            notation: notation,
            special: specialMoveType,
            promotedTo: promotedTo,
            timestamp: Date.now(),
            fen: this.gameState.toFEN(this.board, this.currentTurn)
        };

        // Record move in history
        this.gameState.recordMove(move);

        return move;
    }

    /**
     * Generate algebraic notation for a move
     * @param {Piece} piece - Moved piece
     * @param {number} fromRow - Source row
     * @param {number} fromCol - Source column
     * @param {number} toRow - Target row
     * @param {number} toCol - Target column
     * @param {Piece} captured - Captured piece
     * @param {string} specialMove - Special move type
     * @returns {string} Move notation
     */
    generateNotation(piece, fromRow, fromCol, toRow, toCol, captured, specialMove) {
        if (specialMove === 'castle-kingside') {
            return 'O-O';
        }
        if (specialMove === 'castle-queenside') {
            return 'O-O-O';
        }

        let notation = '';

        // Piece symbol (except pawns)
        if (piece.type !== 'pawn') {
            notation += piece.type[0].toUpperCase();
        }

        // Source square (for disambiguation or pawn captures)
        if (piece.type === 'pawn' && captured) {
            notation += String.fromCharCode(97 + fromCol); // File letter
        }

        // Capture notation
        if (captured) {
            notation += 'x';
        }

        // Destination square
        notation += this.gameState.positionToAlgebraic(toRow, toCol);

        // Promotion
        if (specialMove === 'promotion') {
            notation += '=Q'; // Default to queen
        }

        // Check/checkmate will be added in updateGameStatus()

        return notation;
    }

    /**
     * Update game status (check, checkmate, stalemate, draw)
     */
    updateGameStatus() {
        const opponentColor = this.currentTurn;

        // Check for checkmate
        if (MoveValidator.isCheckmate(this.board, opponentColor, this.gameState)) {
            this.gameState.status = 'checkmate';
            this.emit('checkmate', { winner: this.currentTurn === 'white' ? 'black' : 'white' });
            return;
        }

        // Check for stalemate
        if (MoveValidator.isStalemate(this.board, opponentColor, this.gameState)) {
            this.gameState.status = 'stalemate';
            this.emit('stalemate', {});
            return;
        }

        // Check for check
        if (MoveValidator.isKingInCheck(this.board, opponentColor)) {
            this.gameState.status = 'check';
            this.emit('check', { color: opponentColor });

            // Add check symbol to last move notation
            const lastMove = this.gameState.getLastMove();
            if (lastMove && !lastMove.notation.endsWith('+')) {
                lastMove.notation += '+';
            }
        } else {
            this.gameState.status = 'active';
        }

        // Check for draws
        if (this.gameState.isFiftyMoveRule()) {
            this.gameState.status = 'draw';
            this.emit('draw', { reason: '50-move rule' });
            return;
        }

        if (MoveValidator.isInsufficientMaterial(this.board)) {
            this.gameState.status = 'draw';
            this.emit('draw', { reason: 'Insufficient material' });
            return;
        }

        const currentFEN = this.gameState.toFEN(this.board, this.currentTurn);
        if (this.gameState.isThreefoldRepetition(currentFEN)) {
            this.gameState.status = 'draw';
            this.emit('draw', { reason: 'Threefold repetition' });
            return;
        }
    }

    /**
     * Get all legal moves for a piece
     * @param {Piece} piece - Piece to check
     * @returns {Position[]} Array of legal positions
     */
    getLegalMoves(piece) {
        return MoveValidator.getLegalMoves(this.board, piece, this.gameState);
    }

    /**
     * Check if a player is in check
     * @param {string} color - Player color
     * @returns {boolean} True if in check
     */
    isInCheck(color) {
        return MoveValidator.isKingInCheck(this.board, color);
    }

    /**
     * Start a new game
     */
    newGame() {
        this.board.clear();
        this.board.setupInitialPosition();
        this.gameState.reset();
        this.currentTurn = 'white';
        this.selectedSquare = null;

        this.emit('newgame', {});
    }

    /**
     * Undo the last move
     * @returns {boolean} True if successful
     */
    undo() {
        const move = this.gameState.undo();
        if (!move) {
            return false;
        }

        // Restore board state (simplified - full implementation needs move reversal)
        // This would require storing board state with each move
        // For now, replay moves from start
        this.replayMovesFromHistory();

        this.currentTurn = this.currentTurn === 'white' ? 'black' : 'white';
        this.emit('undo', { move });

        return true;
    }

    /**
     * Redo a previously undone move
     * @returns {boolean} True if successful
     */
    redo() {
        const move = this.gameState.redo();
        if (!move) {
            return false;
        }

        this.replayMovesFromHistory();

        this.currentTurn = this.currentTurn === 'white' ? 'black' : 'white';
        this.emit('redo', { move });

        return true;
    }

    /**
     * Replay moves from history to restore board state
     */
    replayMovesFromHistory() {
        this.board.clear();
        this.board.setupInitialPosition();

        for (let i = 0; i < this.gameState.currentMove; i++) {
            const move = this.gameState.moveHistory[i];
            // Re-execute move
            this.board.movePiece(move.from.row, move.from.col, move.to.row, move.to.col);
        }
    }

    /**
     * Current player resigns
     */
    resign() {
        this.gameState.status = 'resigned';
        this.emit('resign', { loser: this.currentTurn });
    }

    /**
     * Offer a draw
     */
    offerDraw() {
        this.gameState.drawOffer = this.currentTurn;
        this.emit('draw-offered', { by: this.currentTurn });
    }

    /**
     * Accept a draw offer
     */
    acceptDraw() {
        if (this.gameState.drawOffer && this.gameState.drawOffer !== this.currentTurn) {
            this.gameState.status = 'draw';
            this.emit('draw', { reason: 'Agreement' });
        }
    }

    /**
     * Save game state to localStorage
     */
    save() {
        const saveData = {
            fen: this.gameState.toFEN(this.board, this.currentTurn),
            pgn: this.gameState.toPGN(),
            timestamp: Date.now()
        };

        localStorage.setItem('chess-game-save', JSON.stringify(saveData));
    }

    /**
     * Load game state from localStorage
     * @returns {boolean} True if loaded successfully
     */
    load() {
        const saved = localStorage.getItem('chess-game-save');
        if (!saved) {
            return false;
        }

        const saveData = JSON.parse(saved);
        // FEN loading would be implemented here
        // For now, just indicate success
        this.emit('load', saveData);

        return true;
    }

    /**
     * Add event listener
     * @param {string} event - Event name
     * @param {Function} handler - Event handler
     */
    on(event, handler) {
        if (!this.eventHandlers[event]) {
            this.eventHandlers[event] = [];
        }
        this.eventHandlers[event].push(handler);
    }

    /**
     * Emit an event
     * @param {string} event - Event name
     * @param {Object} data - Event data
     */
    emit(event, data) {
        if (this.eventHandlers[event]) {
            this.eventHandlers[event].forEach(handler => handler(data));
        }
    }
}
