import express from 'express';
import http from 'http';
import { Server } from 'socket.io';
import cors from 'cors';
import dotenv from 'dotenv';
import crypto from 'crypto';
import { Game } from './models/Game';

dotenv.config();

const app = express();
const port = process.env.PORT || 4000;

app.use(cors({
    origin: process.env.CORS_ORIGIN || "http://localhost:3000",
    methods: ["GET", "POST"]
}));

const server = http.createServer(app);
const io = new Server(server, {
    cors: {
        origin: process.env.CORS_ORIGIN || "http://localhost:3000",
        methods: ["GET", "POST"]
    }
});

// ALMACÉN DE PARTIDAS (En memoria por ahora)
// En el futuro esto podría estar en Redis o Postgres
const games: Record<string, Game> = {};

// --- LOBBY MANAGEMENT ---

const MISSION_NAMES = [
    "Operación Overlord", "Operación Market Garden", "Operación Barbarroja",
    "Operación Valkiria", "Operación Torch", "Operación Husky",
    "Batalla de Stalingrado", "Dunkerque", "El Alamein", "Midway",
    "Operación Ciudadela", "Operación Dragoon", "Operación Fortaleza",
    "Operación Eiche", "Operación León Marino", "Operación Urano"
];

const generateRoomName = () => {
    const idx = Math.floor(Math.random() * MISSION_NAMES.length);
    const suffix = Math.floor(100 + Math.random() * 900); // 3 digit code
    return `${MISSION_NAMES[idx]} #${suffix}`;
};

io.on('connection', (socket) => {
    console.log('Cliente conectado:', socket.id);

    // Enviar lista de salas al conectar
    socket.emit('rooms_list', getRoomsList());

    // A. CREAR SALA
    socket.on('create_game', ({ hostName, maxPlayers, password }) => {
        console.log(`[CREATE_GAME] Host: ${hostName}, Players: ${maxPlayers}`);
        const roomId = crypto.randomUUID();
        const roomName = generateRoomName();

        const newGame = new Game(roomId, roomName, socket.id, maxPlayers, password);
        games[roomId] = newGame;

        // Unir al creador automáticamente
        newGame.addPlayer(socket.id, hostName);
        socket.join(roomId);

        // Notificar al creador
        socket.emit('game_joined', { roomId, state: newGame.state });

        // Actualizar lista a todos
        io.emit('rooms_list', getRoomsList());
    });

    // B. UNIRSE A SALA
    socket.on('join_game', ({ roomId, playerName, password }) => {
        const game = games[roomId];

        if (!game) {
            socket.emit('error', 'La partida no existe');
            return;
        }

        if (game.password && game.password !== password) {
            socket.emit('error', 'Contraseña incorrecta');
            return;
        }

        if (game.state.players.length >= game.maxPlayers) {
            socket.emit('error', 'La partida está llena');
            return;
        }

        // Evitar duplicados
        const existingPlayer = game.state.players.find(p => p.id === socket.id);
        if (!existingPlayer) {
            game.addPlayer(socket.id, playerName);
        }

        socket.join(roomId);

        // Enviar estado actualizado a la sala
        io.to(roomId).emit('game_state', game.state);
        // Avisar al usuario que entró OK
        socket.emit('game_joined', { roomId, state: game.state });

        // Actualizar lista de salas (cambió contador de jugadores)
        io.emit('rooms_list', getRoomsList());
    });

    // C. REFRESCAR LISTA
    socket.on('get_rooms', () => {
        socket.emit('rooms_list', getRoomsList());
    });

    // --- GAMEPLAY DE SIEMPRE (Adaptado a roomId dinámico) ---

    // 2. INICIAR PARTIDA - FASE INTRO
    socket.on('start_game', ({ roomId }) => {
        const game = games[roomId];
        // Solo el host puede iniciar
        if (game && game.hostId === socket.id && game.state.phase === 'lobby') {
            game.state.phase = 'intro' as any;
            io.to(roomId).emit('game_state', game.state);
            io.emit('rooms_list', getRoomsList());
        }
    });

    // 2.1 PASAR INTRO -> REVEAL ROLE
    socket.on('finish_intro', ({ roomId }) => {
        const game = games[roomId];
        if (game && game.hostId === socket.id && game.state.phase === 'intro') {
            // AQUI DISTRIBUIMOS ROLES
            if (game.startGame()) {
                // startGame pone phase en TEAM_BUILDING, pero nosotros queremos REVEAL_ROLE primero
                game.state.phase = 'reveal_role' as any;
                io.to(roomId).emit('game_state', game.state);
            }
        }
    });

    // 2.2 REVEAL ROLE -> ROLL CALL
    socket.on('finish_reveal', ({ roomId }) => {
        const game = games[roomId];
        // Cualquiera puede llamar a esto si es auto-timer, o solo host?
        // El usuario dijo "Habrá una cuenta atrás de 5 segundos".
        // Lo ideal es que el Host controle el tiempo para sincronizar.
        if (game && game.hostId === socket.id && game.state.phase === 'reveal_role') {
            game.state.phase = 'roll_call' as any;
            io.to(roomId).emit('game_state', game.state);
        }
    });

    // 2.3 FINALIZAR ROLL CALL -> PRIMER TURNO DE JUEGO (TEAM_BUILDING)
    socket.on('finish_roll_call', ({ roomId }) => {
        const game = games[roomId];
        if (game && game.hostId === socket.id && game.state.phase === 'roll_call') {
            // Ir a VOTE_LEADER (ya que startGame lo inicializa a VOTE_LEADER en el modelo, y nextLeader tambien)
            // Solo debemos asegurarnos que el GameState se sincronice.
            if (game.startGame()) {
                io.to(roomId).emit('game_state', game.state);
            }
        }
    });

    // 2.4 VOTAR LÍDER
    socket.on('vote_leader', ({ roomId, approve }) => {
        const game = games[roomId];
        if (game) {
            game.voteLeader(socket.id, approve);
            io.to(roomId).emit('game_state', game.state);
        }
    });

    // 3. PROPONER EQUIPO
    socket.on('propose_team', ({ roomId, teamIds }) => {
        const game = games[roomId];
        if (game && game.proposeTeam(teamIds)) {
            io.to(roomId).emit('game_state', game.state);
        }
    });

    // 4. VOTAR EQUIPO
    socket.on('vote_team', ({ roomId, approve }) => {
        const game = games[roomId];
        if (game) {
            game.voteForTeam(socket.id, approve);
            io.to(roomId).emit('game_state', game.state);
        }
    });


    // 5. VOTAR MISIÓN
    socket.on('vote_mission', ({ roomId, success }) => {
        const game = games[roomId];
        if (game) {
            game.voteMission(success);
            io.to(roomId).emit('game_state', game.state);
        }
    });

    // 5.1 FINALIZAR REVELACIÓN DE CARTAS
    socket.on('finish_reveal', ({ roomId }) => {
        const game = games[roomId];
        if (game && game.hostId === socket.id && game.state.phase === 'mission_reveal') {
            game.finishReveal();
            io.to(roomId).emit('game_state', game.state);
        }
    });

    // 5.2 FINALIZAR PANTALLA DE RESULTADO
    socket.on('finish_mission_result', ({ roomId }) => {
        const game = games[roomId];
        if (game && game.hostId === socket.id && game.state.phase === 'mission_result') {
            game.finishMissionResult();
            io.to(roomId).emit('game_state', game.state);
        }
    });


    // 6. ASESINATO FINAL
    socket.on('assassin_kill', ({ roomId, targetId }) => {
        const game = games[roomId];
        if (game) {
            game.assassinKill(targetId);
            io.to(roomId).emit('game_state', game.state);
        }
    });

    // 7. DESCONEXIÓN
    socket.on('disconnect', () => {
        // Buscar en qué partida estaba y sacarlo (opcional, por ahora solo notificamos)
        console.log('Desconectado:', socket.id);
        // TODO: Eliminar de la partida si está en LOBBY para liberar hueco
    });
});

const getRoomsList = () => {
    return Object.values(games).map(g => ({
        id: g.state.roomId,
        name: g.roomName,
        hostId: g.hostId,
        currentPlayers: g.state.players.length,
        maxPlayers: g.maxPlayers,
        isPrivate: !!g.password,
        status: g.state.phase === 'lobby' ? 'waiting' : 'playing'
    }));
};

app.get('/', (req, res) => {
    res.send('Servidor de La Resistencia funcionando 🚀');
});

server.listen(port, () => {
    console.log(`[server]: Servidor corriendo en http://localhost:${port}`);
});
