import {
    GameState,
    Player,
    GamePhase,
    Role,
    Faction,
    GAME_CONFIG
} from '../../../shared/types';

export class Game {
    public state: GameState;

    public roomName: string;
    public hostId: string;
    public maxPlayers: number;
    public password?: string;

    constructor(
        roomId: string,
        roomName: string,
        hostId: string,
        maxPlayers: number,
        password?: string
    ) {
        this.roomName = roomName;
        this.hostId = hostId;
        this.maxPlayers = maxPlayers;
        this.password = password;

        this.state = {
            roomId,
            roomName,
            phase: GamePhase.LOBBY,
            players: [],
            currentRound: 1,
            failedVotesCount: 0,
            questResults: [null, null, null, null, null],
            currentLeaderId: '',
            leaderVotes: {},
            proposedTeam: [],
            teamVotes: {},
            missionVotes: [],
            missionHistory: [],
            revealedVotes: [],
            history: [],
            hostId: hostId
        };
    }

    addPlayer(id: string, name: string): Player {
        // Asignar avatar aleatorio sin repetir (rebel001.jpg - rebel010.jpg)
        // Obtener avatares ya usados
        const usedAvatars = this.state.players.map(p => p.avatar);

        // Crear lista de avatares disponibles
        const allAvatars = Array.from({ length: 10 }, (_, i) =>
            `rebel${(i + 1).toString().padStart(3, '0')}.jpg`
        );

        const availableAvatars = allAvatars.filter(av => !usedAvatars.includes(av));

        // Si no hay avatares disponibles (más de 10 jugadores), usar cualquiera
        const avatarStr = availableAvatars.length > 0
            ? availableAvatars[Math.floor(Math.random() * availableAvatars.length)]
            : allAvatars[Math.floor(Math.random() * allAvatars.length)];

        const player: Player = {
            id,
            name,
            avatar: avatarStr,
            isLeader: false
        };
        this.state.players.push(player);
        this.log(`${name} se ha unido a la partida.`);
        return player;
    }

    removePlayer(id: string) {
        this.state.players = this.state.players.filter(p => p.id !== id);
    }

    startGame(): boolean {
        const count = this.state.players.length;
        if (count < 5 || count > 10) return false;

        const config = GAME_CONFIG[count as keyof typeof GAME_CONFIG];

        // 1. Asignar Roles
        this.assignRoles(config.good, config.evil);

        // 2. Asignar Líder inicial aleatorio
        const leaderIndex = Math.floor(Math.random() * count);
        this.state.players[leaderIndex].isLeader = true;
        this.state.currentLeaderId = this.state.players[leaderIndex].id;

        // 3. Iniciar juego - Fase Votación de Líder
        this.state.phase = GamePhase.VOTE_LEADER;
        this.state.leaderVotes = {}; // Reset votes
        this.state.currentRound = 1;
        this.log('¡La partida ha comenzado! Ahora deben votar para confirmar al Líder.');

        return true;
    }

    // ... assignRoles se mantiene igual ...
    private assignRoles(goodCount: number, evilCount: number) {
        // Roles obligatorios
        const roles: Role[] = [Role.MARLENE, Role.FRANCOTIRADOR]; // Updated roles

        // Rellenar resto de malos
        for (let i = 0; i < evilCount - 1; i++) roles.push(Role.COLABORACIONISTA); // Updated role

        // Rellenar resto de buenos
        for (let i = 0; i < goodCount - 1; i++) roles.push(Role.PARTISANO); // Updated role

        // Barajar roles
        const shuffledRoles = roles.sort(() => Math.random() - 0.5);

        // Asignar a jugadores
        this.state.players.forEach((player, index) => {
            player.role = shuffledRoles[index];
            // Asignar facción basada en el rol
            if ([Role.MARLENE, Role.PARTISANO].includes(player.role)) { // Updated roles
                player.faction = Faction.ALIADOS;
            } else {
                player.faction = Faction.ALEMANES;
            }
        });
    }

    // --- LOGICA DE VOTACIÓN DE LÍDER ---
    voteLeader(playerId: string, approve: boolean) {
        // Solo registrar el voto si el jugador existe y aún no ha votado
        const player = this.state.players.find(p => p.id === playerId);
        if (!player) return;

        this.state.leaderVotes[playerId] = approve;

        // Comprobar si todos han votado
        if (Object.keys(this.state.leaderVotes).length === this.state.players.length) {
            this.resolveLeaderVote();
        }
    }

    // Método para forzar la resolución de votos cuando se acaba el tiempo
    forceResolveLeaderVote() {
        // Si nadie votó o no todos votaron, se considera fracaso
        this.resolveLeaderVote();
    }

    private resolveLeaderVote() {
        const totalPlayers = this.state.players.length;
        const votesCount = Object.keys(this.state.leaderVotes).length;

        // Si nadie votó, rechazar automáticamente
        if (votesCount === 0) {
            this.log(`Votación de Líder: nadie votó. Líder rechazado.`);
            this.state.failedVotesCount++;

            if (this.state.failedVotesCount >= 5) {
                this.endGame(Faction.ALEMANES, 'Se han rechazado 5 líderes consecutivos.');
            } else {
                this.nextLeader();
            }
            return;
        }

        // Contar votos de aprobación y rechazo
        const approves = Object.values(this.state.leaderVotes).filter(v => v === true).length;
        const rejects = Object.values(this.state.leaderVotes).filter(v => v === false).length;

        // La mayoría se calcula sobre los que votaron, no sobre el total
        const isSuccess = approves > rejects;

        this.log(`Votación de Líder: ${approves} a favor, ${rejects} en contra (${votesCount}/${totalPlayers} votaron)`);

        if (isSuccess) {
            // Líder Aprobado -> Fase de Construcción de Equipo
            this.state.phase = GamePhase.TEAM_BUILDING;
            this.state.proposedTeam = []; // Reset team selection
            this.state.failedVotesCount = 0; // Reset contador al aprobar líder
            this.log(`Líder ${this.state.players.find(p => p.id === this.state.currentLeaderId)?.name} confirmado con ${approves} votos a favor.`);
        } else {
            // Líder Rechazado -> Incrementar contador y pasar al siguiente líder
            this.state.failedVotesCount++;
            this.log(`Líder rechazado: ${rejects} votos en contra superan a ${approves} a favor. Pasando turno al siguiente jugador.`);

            // Verificar si se alcanzó el límite de rechazos (5 votos fallidos = alemanes ganan)
            if (this.state.failedVotesCount >= 5) {
                this.endGame(Faction.ALEMANES, 'Se han rechazado 5 líderes consecutivos.');
            } else {
                this.nextLeader(); // Esto pondrá phase en VOTE_LEADER de nuevo
            }
        }
    }

    proposeTeam(playerIds: string[]): boolean {
        // Validar tamaño del equipo según la ronda
        const config = GAME_CONFIG[this.state.players.length as keyof typeof GAME_CONFIG];
        const requiredSize = config.quests[this.state.currentRound - 1];

        if (playerIds.length !== requiredSize) return false;

        this.state.proposedTeam = playerIds;
        this.state.phase = GamePhase.MISSION; // Ir directamente a la misión
        this.state.missionVotes = []; // Resetear votos de misión
        this.state.failedVotesCount = 0; // Reset contador de rechazos
        this.log(`El líder ha seleccionado un equipo de ${playerIds.length} personas. ¡Comienza la misión!`);
        return true;
    }

    voteForTeam(playerId: string, approve: boolean) {
        this.state.teamVotes[playerId] = approve;

        // Comprobar si todos han votado
        if (Object.keys(this.state.teamVotes).length === this.state.players.length) {
            this.resolveTeamVote();
        }
    }

    private resolveTeamVote() {
        const votes = Object.values(this.state.teamVotes);
        const approves = votes.filter(v => v).length;
        const rejects = votes.length - approves;

        this.log(`Votación completada: ${approves} A favor - ${rejects} En contra.`);

        if (approves > rejects) {
            // Equipo Aprobado
            this.state.phase = GamePhase.MISSION;
            this.state.missionVotes = [];
            this.state.failedVotesCount = 0;
            this.log('El equipo ha sido aprobado. ¡Comienza la misión!');
        } else {
            // Equipo Rechazado
            this.state.failedVotesCount++;
            this.state.proposedTeam = [];

            if (this.state.failedVotesCount >= 5) {
                this.endGame(Faction.ALEMANES, 'Se han rechazado 5 equipos consecutivos.'); // Updated Faction
            } else {
                this.nextLeader(); // Pasa a VOTE_LEADER
                this.log('El equipo fue rechazado. El liderazgo pasa al siguiente jugador.');
            }
        }
    }

    voteMission(success: boolean) {
        this.state.missionVotes.push(success);

        // Comprobar si todos los miembros del equipo han votado
        if (this.state.missionVotes.length === this.state.proposedTeam.length) {
            this.resolveMission();
        }
    }

    private resolveMission() {
        const fails = this.state.missionVotes.filter(v => !v).length;
        const successes = this.state.missionVotes.filter(v => v).length;
        const playerCount = this.state.players.length;
        const round = this.state.currentRound;

        // Regla especial: 4ta misión con 7+ jugadores necesita 2 fallos
        let failsRequired = 1;
        if (playerCount >= 7 && round === 4) {
            failsRequired = 2;
        }

        const isSuccess = fails < failsRequired;

        // 1. BARAJAR los votos para que no se sepa quién votó qué
        const shuffledVotes = [...this.state.missionVotes].sort(() => Math.random() - 0.5);

        // 2. Guardar en el histórico
        const missionRecord = {
            round,
            team: [...this.state.proposedTeam],
            votes: shuffledVotes,
            successes,
            fails,
            isSuccess,
            leaderId: this.state.currentLeaderId
        };
        this.state.missionHistory.push(missionRecord);

        // 3. Actualizar resultado de la quest
        this.state.questResults[round - 1] = isSuccess;

        // 4. Pasar a fase MISSION_REVEAL (mostrar cartas una a una)
        this.state.phase = GamePhase.MISSION_REVEAL;
        this.state.revealedVotes = shuffledVotes; // Las cartas a revelar

        this.log(`Misión ${round} completada. Revelando votos...`);

        // El cliente controlará el avance a MISSION_RESULT con su timer
    }


    // Método para avanzar desde MISSION_REVEAL a MISSION_RESULT
    finishReveal() {
        this.state.phase = GamePhase.MISSION_RESULT;
    }

    // Método para avanzar desde MISSION_RESULT y continuar el juego
    finishMissionResult() {
        const round = this.state.currentRound;
        const isSuccess = this.state.questResults[round - 1];

        this.log(`Misión ${round}: ${isSuccess ? 'ÉXITO' : 'FRACASO'}`);

        // Comprobar condiciones de victoria
        const successes = this.state.questResults.filter(r => r === true).length;
        const failures = this.state.questResults.filter(r => r === false).length;

        if (failures >= 3) {
            // Los Nazis ganan directamente
            this.state.winner = Faction.ALEMANES;
            this.state.phase = GamePhase.NAZIS_WIN;
            this.log('¡Los Nazis han ganado! Tres misiones han fracasado.');
        } else if (successes >= 3) {
            // Los Aliados han completado 3 misiones, pero el Asesino tiene una oportunidad
            this.state.phase = GamePhase.ASSASSIN_PHASE;
            this.log('¡La Resistencia ha triunfado! Pero el Francotirador tiene una última oportunidad...');
        } else {
            // Siguiente ronda
            this.state.currentRound++;
            this.nextLeader(); // Esto pone phase = VOTE_LEADER
            this.state.proposedTeam = [];
            this.state.missionVotes = [];
            this.state.revealedVotes = [];
        }
    }

    assassinKill(targetId: string) {
        const target = this.state.players.find(p => p.id === targetId);
        if (target && target.role === Role.MARLENE) {
            // El Francotirador acierta: Nazis ganan
            this.state.winner = Faction.ALEMANES;
            this.state.phase = GamePhase.NAZIS_WIN;
            this.log('¡El Francotirador ha eliminado a Marlene! Los Nazis ganan.');
        } else {
            // El Francotirador falla: Aliados ganan
            this.state.winner = Faction.ALIADOS;
            this.state.phase = GamePhase.ALLIED_WIN;
            this.log('El Francotirador ha fallado. ¡La Resistencia gana!');
        }
    }

    nextLeader() {
        const currentIdx = this.state.players.findIndex(p => p.id === this.state.currentLeaderId);
        const nextIdx = (currentIdx + 1) % this.state.players.length;

        this.state.players[currentIdx].isLeader = false;
        this.state.players[nextIdx].isLeader = true;
        this.state.currentLeaderId = this.state.players[nextIdx].id;

        // Fase de confirmar al nuevo líder
        this.state.phase = GamePhase.VOTE_LEADER;
        this.state.leaderVotes = {};
    }

    private endGame(winner: Faction, reason: string) {
        this.state.winner = winner;
        this.state.phase = GamePhase.GAME_OVER;
        this.log(`FIN DEL JUEGO. Victoria para ${winner}. Razón: ${reason}`);
    }

    // Método para reiniciar la partida (volver a REVEAL_ROLE)
    restartGame() {
        this.log('=== REINICIANDO PARTIDA ===');

        // Resetear variables de juego
        this.state.currentRound = 1;
        this.state.failedVotesCount = 0;
        this.state.questResults = [null, null, null, null, null];
        this.state.leaderVotes = {};
        this.state.proposedTeam = [];
        this.state.teamVotes = {};
        this.state.missionVotes = [];
        this.state.revealedVotes = [];
        this.state.missionHistory = [];
        this.state.winner = undefined;

        // Reasignar roles
        const count = this.state.players.length;
        const config = GAME_CONFIG[count as keyof typeof GAME_CONFIG];
        this.assignRoles(config.good, config.evil);

        // Asignar nuevo líder aleatorio
        const leaderIndex = Math.floor(Math.random() * count);
        this.state.players.forEach((p, i) => p.isLeader = i === leaderIndex);
        this.state.currentLeaderId = this.state.players[leaderIndex].id;

        // Volver a REVEAL_ROLE
        this.state.phase = GamePhase.REVEAL_ROLE;
        this.log('Nueva partida iniciada. Revelando roles...');
    }

    // Método para finalizar definitivamente y preparar expulsión
    finalizeGame() {
        this.state.phase = GamePhase.GAME_OVER;
        this.log('Partida finalizada. Los jugadores serán expulsados.');
    }

    private log(message: string) {
        this.state.history.push(message);
        // Mantener solo los últimos 50 mensajes
        if (this.state.history.length > 50) this.state.history.shift();
    }
}
