// Express + WebSocket server for Kafaball
const express = require('express');
const http = require('http');
const { WebSocketServer } = require('ws');
const path = require('path');
const { Game } = require('./game');

const app = express();
const server = http.createServer(app);
const wss = new WebSocketServer({ server });

// Serve static files
app.use(express.static(path.join(__dirname, '..', 'public')));

// Room management
const rooms = new Map();
let nextPlayerId = 1;

function generateRoomId() {
    return Math.random().toString(36).substring(2, 8).toUpperCase();
}

function broadcastRoomList() {
    const roomList = Array.from(rooms.values()).map(r => r.getRoomListEntry());
    const msg = JSON.stringify({ type: 'room_list', data: roomList });
    wss.clients.forEach(client => {
        if (client.readyState === 1 && !client.roomId) {
            try { client.send(msg); } catch (e) { }
        }
    });
}

wss.on('connection', (ws) => {
    const playerId = 'p' + (nextPlayerId++);
    ws.playerId = playerId;
    ws.playerName = '';
    ws.roomId = null;
    ws.isAlive = true;

    // Send initial room list
    const roomList = Array.from(rooms.values()).map(r => r.getRoomListEntry());
    ws.send(JSON.stringify({ type: 'room_list', data: roomList }));
    ws.send(JSON.stringify({ type: 'welcome', data: { playerId } }));

    ws.on('pong', () => { ws.isAlive = true; });

    ws.on('message', (data) => {
        let msg;
        try {
            msg = JSON.parse(data);
        } catch (e) {
            return;
        }

        switch (msg.type) {
            case 'set_name':
                ws.playerName = (msg.data.name || '').substring(0, 20).trim() || 'Player';
                break;

            case 'create_room': {
                const roomId = generateRoomId();
                const roomName = (msg.data.roomName || '').substring(0, 30).trim() || 'Room ' + roomId;
                const maxPlayers = Math.min(Math.max(msg.data.maxPlayers || 10, 2), 20);
                const password = msg.data.password || null;

                const game = new Game(roomId, roomName, maxPlayers, password, playerId);
                rooms.set(roomId, game);

                game.addPlayer(playerId, ws.playerName, ws);
                ws.roomId = roomId;

                ws.send(JSON.stringify({ type: 'room_joined', data: { roomId } }));
                game.broadcastRoomState();
                broadcastRoomList();
                break;
            }

            case 'join_room': {
                const roomId = msg.data.roomId;
                const password = msg.data.password;
                const game = rooms.get(roomId);

                if (!game) {
                    ws.send(JSON.stringify({ type: 'error', data: { message: 'Oda bulunamadı' } }));
                    return;
                }
                if (game.players.size >= game.maxPlayers) {
                    ws.send(JSON.stringify({ type: 'error', data: { message: 'Oda dolu' } }));
                    return;
                }
                if (game.password && game.password !== password) {
                    ws.send(JSON.stringify({ type: 'error', data: { message: 'Yanlış şifre' } }));
                    return;
                }

                game.addPlayer(playerId, ws.playerName, ws);
                ws.roomId = roomId;

                ws.send(JSON.stringify({ type: 'room_joined', data: { roomId } }));
                game.broadcastRoomState();
                broadcastRoomList();

                for (const chatMsg of game.chatMessages) {
                    ws.send(JSON.stringify({ type: 'chat_msg', data: chatMsg }));
                }
                break;
            }

            case 'leave_room': {
                leaveRoom(ws);
                break;
            }

            case 'admin_set_team': {
                const game = rooms.get(ws.roomId);
                if (!game || game.adminId !== playerId) return;
                game.setTeam(msg.data.playerId, msg.data.team);
                game.broadcastRoomState();
                break;
            }

            case 'give_admin': {
                const game = rooms.get(ws.roomId);
                if (!game || game.adminId !== playerId) return;
                const targetId = msg.data.playerId;
                if (game.players.has(targetId)) {
                    game.adminId = targetId;
                    game.broadcastRoomState();
                    broadcastRoomList();
                }
                break;
            }

            case 'kick_player': {
                const game = rooms.get(ws.roomId);
                if (!game || game.adminId !== playerId) return;
                const targetId = msg.data.playerId;
                const targetPlayer = game.players.get(targetId);
                if (targetPlayer && targetPlayer.ws) {
                    targetPlayer.ws.send(JSON.stringify({ type: 'kicked' }));
                    targetPlayer.ws.roomId = null;
                    game.removePlayer(targetId);
                    game.broadcastRoomState();
                    broadcastRoomList();
                }
                break;
            }

            case 'start_game': {
                const game = rooms.get(ws.roomId);
                if (!game || game.adminId !== playerId) return;
                if (game.startGame()) {
                    game.broadcastRoomState();
                    game.broadcastEvent('game_start', {});
                }
                break;
            }

            case 'stop_game': {
                const game = rooms.get(ws.roomId);
                if (!game || game.adminId !== playerId) return;
                game.stopGame();
                game.broadcastRoomState();
                broadcastRoomList();
                break;
            }

            case 'input': {
                const game = rooms.get(ws.roomId);
                if (!game) return;
                game.handleInput(playerId, msg.data);
                break;
            }

            case 'chat': {
                const game = rooms.get(ws.roomId);
                if (!game) return;
                const chatText = (msg.data.message || '').trim();
                if (chatText.length > 0) {
                    game.broadcastChat(playerId, ws.playerName, chatText);
                }
                break;
            }

            case 'get_rooms': {
                const roomList = Array.from(rooms.values()).map(r => r.getRoomListEntry());
                ws.send(JSON.stringify({ type: 'room_list', data: roomList }));
                break;
            }
        }
    });

    ws.on('close', () => { leaveRoom(ws); });
    ws.on('error', () => { leaveRoom(ws); });
});

function leaveRoom(ws) {
    if (ws.roomId) {
        const game = rooms.get(ws.roomId);
        if (game) {
            game.removePlayer(ws.playerId);
            if (game.players.size === 0) {
                game.stopGame();
                rooms.delete(ws.roomId);
            } else {
                game.broadcastRoomState();
            }
            broadcastRoomList();
        }
        ws.roomId = null;
        const roomList = Array.from(rooms.values()).map(r => r.getRoomListEntry());
        try { ws.send(JSON.stringify({ type: 'room_list', data: roomList })); } catch (e) { }
    }
}

// Heartbeat
const heartbeatInterval = setInterval(() => {
    wss.clients.forEach(ws => {
        if (!ws.isAlive) { leaveRoom(ws); return ws.terminate(); }
        ws.isAlive = false;
        ws.ping();
    });
}, 30000);

wss.on('close', () => { clearInterval(heartbeatInterval); });

const PORT = process.env.PORT || 3000;
server.listen(PORT, () => {
    console.log(`Kafaball server running on http://localhost:${PORT}`);
});
