// /server/bc.js - Главный файл сервера Battle Club

// Загружаем переменные окружения В САМОМ НАЧАЛЕ, до всех других импортов,
// которые могут зависеть от process.env
// Убедитесь, что путь к .env правильный относительно места запуска приложения.
// Если bc.js запускается из папки server/, а .env в корне, то путь должен быть '../.env'
// Но обычно dotenv ищет .env в process.cwd()
require('dotenv').config({ path: require('node:path').resolve(process.cwd(), '.env') });


const express = require('express');
const http = require('http');
const { Server } = require('socket.io');
const path = require('path');

// Импорт серверных модулей из их новых местоположений
const authService = require('./auth/authService');       // Сервис аутентификации
const GameManager = require('./game/GameManager');        // Менеджер игр
const db = require('./core/db');                          // Модуль базы данных (важно, чтобы он тоже использовал dotenv)
const GAME_CONFIG = require('./core/config');             // Глобальный конфиг игры

const app = express();
const server = http.createServer(app);

// Настройка Socket.IO
const io = new Server(server, {
    cors: {
        // origin: process.env.CORS_ORIGIN || "https://pavel-chagovsky.com:3200", // Пример, если нужно CORS из .env
        // methods: ["GET", "POST"]
    },
    // pingInterval: 10000,
    // pingTimeout: 5000,
});

// Раздача статических файлов из папки 'public'
app.use(express.static(path.join(__dirname, '..', 'public')));

// Создаем экземпляр GameManager
const gameManager = new GameManager(io);

const loggedInUsers = {};

io.on('connection', (socket) => {
    console.log(`[Socket.IO] Пользователь подключился: ${socket.id}`);
    socket.userData = null;

    socket.on('register', async (data) => {
        console.log(`[Socket.IO] Register attempt for username: "${data?.username}" from ${socket.id}`);
        const result = await authService.registerUser(data?.username, data?.password);
        if (result.success) {
            console.log(`[Socket.IO] Registration successful for ${result.username} (${result.userId})`);
        } else {
            console.warn(`[Socket.IO] Registration failed for "${data?.username}": ${result.message}`);
        }
        socket.emit('registerResponse', result);
    });

    socket.on('login', async (data) => {
        console.log(`[Socket.IO] Login attempt for username: "${data?.username}" from ${socket.id}`);
        const result = await authService.loginUser(data?.username, data?.password);
        if (result.success && result.userId && result.username) {
            console.log(`[Socket.IO] Login successful for ${result.username} (${result.userId}). Assigning to socket ${socket.id}.`);
            socket.userData = { userId: result.userId, username: result.username };
            loggedInUsers[socket.id] = socket.userData;
            if (gameManager && typeof gameManager.handleRequestGameState === 'function') {
                gameManager.handleRequestGameState(socket, result.userId);
            }
        } else {
            console.warn(`[Socket.IO] Login failed for "${data?.username}": ${result.message}`);
            socket.userData = null;
            if (loggedInUsers[socket.id]) delete loggedInUsers[socket.id];
        }
        socket.emit('loginResponse', result);
    });

    socket.on('logout', () => {
        const username = socket.userData?.username || 'UnknownUser';
        const userId = socket.userData?.userId;
        console.log(`[Socket.IO] Logout request from user ${username} (ID: ${userId}, Socket: ${socket.id})`);
        if (gameManager && typeof gameManager.handleDisconnect === 'function' && userId) {
            gameManager.handleDisconnect(socket.id, userId);
        }
        if (loggedInUsers[socket.id]) {
            delete loggedInUsers[socket.id];
        }
        socket.userData = null;
        console.log(`[Socket.IO] User ${username} (Socket: ${socket.id}) logged out.`);
    });

    socket.on('createGame', (data) => {
        const identifier = socket.userData?.userId || socket.id;
        const mode = data?.mode || 'ai';
        if (mode === 'pvp' && !socket.userData) {
            socket.emit('gameError', { message: 'Необходимо войти в систему для создания PvP игры.' });
            return;
        }
        console.log(`[Socket.IO] Create Game from ${socket.userData?.username || socket.id} (ID: ${identifier}). Mode: ${mode}, Char: ${data?.characterKey}`);
        gameManager.createGame(socket, mode, data?.characterKey, identifier);
    });

    socket.on('joinGame', (data) => {
        if (!socket.userData?.userId) {
            socket.emit('gameError', { message: 'Необходимо войти для присоединения к PvP игре.' });
            return;
        }
        console.log(`[Socket.IO] Join Game from ${socket.userData.username} (ID: ${socket.userData.userId}). GameID: ${data?.gameId}`);
        gameManager.joinGame(socket, data?.gameId, socket.userData.userId);
    });

    socket.on('findRandomGame', (data) => {
        if (!socket.userData?.userId) {
            socket.emit('gameError', { message: 'Необходимо войти для поиска случайной PvP игры.' });
            return;
        }
        console.log(`[Socket.IO] Find Random Game from ${socket.userData.username} (ID: ${socket.userData.userId}). PrefChar: ${data?.characterKey}`);
        gameManager.findAndJoinRandomPvPGame(socket, data?.characterKey, socket.userData.userId);
    });

    socket.on('requestPvPGameList', () => {
        const availableGames = gameManager.getAvailablePvPGamesListForClient();
        socket.emit('availablePvPGamesList', availableGames);
    });

    socket.on('requestGameState', () => {
        if (!socket.userData?.userId) {
            socket.emit('gameNotFound', { message: 'Необходимо войти для восстановления игры.' });
            return;
        }
        gameManager.handleRequestGameState(socket, socket.userData.userId);
    });

    socket.on('playerAction', (actionData) => {
        const identifier = socket.userData?.userId || socket.id;
        gameManager.handlePlayerAction(identifier, actionData);
    });

    socket.on('disconnect', (reason) => {
        const identifier = socket.userData?.userId || socket.id;
        console.log(`[Socket.IO] Пользователь отключился: ${socket.id} (Причина: ${reason}). Identifier: ${identifier}`);
        gameManager.handleDisconnect(socket.id, identifier);
        if (loggedInUsers[socket.id]) {
            delete loggedInUsers[socket.id];
        }
    });
});

// Запуск HTTP сервера
// Используем переменные окружения или значения по умолчанию
const PORT = parseInt(process.env.BC_APP_PORT || '3200', 10);
const HOSTNAME = process.env.BC_APP_HOSTNAME || '127.0.0.1';

// Проверка, что порт является числом
if (isNaN(PORT)) {
    console.error(`[Server FATAL] Некорректное значение для BC_APP_PORT: "${process.env.BC_APP_PORT}". Ожидается число.`);
    process.exit(1);
}

server.listen(PORT, HOSTNAME, () => {
    console.log(`Battle Club HTTP Application Server running at http://${HOSTNAME}:${PORT}`);
    if (HOSTNAME === '127.0.0.1') {
        console.log(`Server is listening on localhost only. This is suitable if a reverse proxy handles external traffic.`);
    } else if (HOSTNAME === '0.0.0.0') {
        console.log(`Server is listening on all available network interfaces.`);
    } else {
        console.log(`Server is listening on a specific interface: ${HOSTNAME}.`);
    }
    console.log(`Environment (NODE_ENV): ${process.env.NODE_ENV || 'not set (defaults to development behavior)'}`);
    console.log(`Serving static files from: ${path.join(__dirname, '..', 'public')}`);
});

process.on('unhandledRejection', (reason, promise) => {
    console.error('[Server FATAL] Unhandled Rejection at:', promise, 'reason:', reason);
    // process.exit(1);
});

process.on('uncaughtException', (err) => {
    console.error('[Server FATAL] Uncaught Exception:', err);
    process.exit(1);
});