/**
 * Game Server - Based on Client LocalServer Infrastructure
 * Handles real-time multiplayer game instances and gameplay
 */

const express = require('express');
const http = require('http');
const socketIo = require('socket.io');
const cors = require('cors');
const helmet = require('helmet');
const compression = require('compression');
const mongoose = require('mongoose');
require('dotenv').config();

const logger = require('./utils/logger');
const connectDB = require('./config/database');
const PlayerData = require('./models/PlayerData');

// Import server systems for player initialization
const QuestSystem = require('./systems/QuestSystem');
const SkillSystem = require('./systems/SkillSystem');
const DungeonSystem = require('./systems/DungeonSystem');
const CraftingSystem = require('./systems/CraftingSystem');
const IdleSystem = require('./systems/IdleSystem');
const ItemSystem = require('./systems/ItemSystem');

// Initialize server systems
const questSystem = new QuestSystem();
const skillSystem = new SkillSystem();
const dungeonSystem = new DungeonSystem();
const craftingSystem = new CraftingSystem();
const idleSystem = new IdleSystem();
const itemSystem = new ItemSystem();

const app = express();
const server = http.createServer(app);
const io = socketIo(server, {
  cors: {
    origin: [
      "http://localhost:3000", 
      "http://127.0.0.1:3000", 
      "file://",
      "https://dev.galaxystrike.online",
      "https://galaxystrike.online"
    ],
    methods: ["GET", "POST"],
    credentials: true
  }
});

// Game state
const gameInstances = new Map();
const connectedClients = new Map();

// Server-side shop item lookup using ItemSystem
function findShopItem(itemId) {
  return itemSystem.getItem(itemId);
}

// Middleware
app.use(cors({
  origin: [
    "http://localhost:3000", 
    "http://127.0.0.1:3000", 
    "file://",
    "https://dev.galaxystrike.online",
    "https://galaxystrike.online"
  ],
  credentials: true
}));
app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ extended: true }));

// Health check endpoint
app.get('/health', (req, res) => {
  res.status(200).json({ 
    status: 'OK', 
    timestamp: new Date().toISOString(),
    uptime: process.uptime(),
    mode: 'game-server',
    activeInstances: gameInstances.size,
    connectedClients: connectedClients.size
  });
});

// API version endpoint
app.get('/api/ssc/version', (req, res) => {
  res.status(200).json({ 
    version: '1.0.0',
    service: 'galaxystrikeonline-game-server',
    timestamp: new Date().toISOString(),
    mode: 'multiplayer'
  });
});

// Shop API endpoints
app.get('/api/shop/items', (req, res) => {
  try {
    const shopItems = itemSystem.getShopItems();
    res.status(200).json({
      success: true,
      items: shopItems,
      timestamp: new Date().toISOString()
    });
  } catch (error) {
    console.error('[GAME SERVER] Error fetching shop items:', error);
    res.status(500).json({
      success: false,
      error: 'Failed to fetch shop items'
    });
  }
});

app.get('/api/shop/items/:category', (req, res) => {
  try {
    const { category } = req.params;
    const items = itemSystem.getItemsByCategory(category);
    
    res.status(200).json({
      success: true,
      category: category,
      items: items,
      timestamp: new Date().toISOString()
    });
  } catch (error) {
    console.error('[GAME SERVER] Error fetching shop category:', error);
    res.status(500).json({
      success: false,
      error: 'Failed to fetch shop category'
    });
  }
});

app.get('/api/items/:itemId', (req, res) => {
  try {
    const { itemId } = req.params;
    const item = itemSystem.getItem(itemId);
    
    if (!item) {
      return res.status(404).json({
        success: false,
        error: 'Item not found'
      });
    }
    
    res.status(200).json({
      success: true,
      item: item
    });
  } catch (error) {
    console.error('[GAME SERVER] Error fetching item:', error);
    res.status(500).json({
      success: false,
      error: 'Failed to fetch item'
    });
  }
});

// Game data endpoints (similar to LocalServer)
app.post('/api/game/player/:id/save', (req, res) => {
  const playerId = req.params.id;
  const playerData = req.body;
  
  // Store player data in game instance
  if (connectedClients.has(playerId)) {
    connectedClients.get(playerId).playerData = playerData;
    
    // Broadcast to other players in same instance
    const instanceId = connectedClients.get(playerId).instanceId;
    if (gameInstances.has(instanceId)) {
      io.to(instanceId).emit('playerDataUpdated', {
        playerId,
        timestamp: Date.now()
      });
    }
  }
  
  res.status(200).json({
    success: true,
    message: 'Player data saved to game server'
  });
});

app.get('/api/game/player/:id', (req, res) => {
  const playerId = req.params.id;
  
  if (connectedClients.has(playerId)) {
    const playerData = connectedClients.get(playerId).playerData;
    res.status(200).json({
      success: true,
      player: playerData
    });
  } else {
    res.status(404).json({
      success: false,
      error: 'Player not connected to game server'
    });
  }
});

// Game system routes
app.use('/api/crafting', require('./routes/crafting'));
app.use('/api/quests', require('./routes/quests'));
app.use('/api/skills', require('./routes/skills'));
app.use('/api/ships', require('./routes/ships'));
app.use('/api/idle', require('./routes/idle'));
app.use('/api/dungeons', require('./routes/dungeons'));
app.use('/api/base', require('./routes/base'));

// Socket.IO handlers (based on LocalServer)
io.on('connection', (socket) => {
  console.log('[GAME SERVER] Client connected:', socket.id);
  connectedClients.set(socket.id, {
    connectedAt: Date.now(),
    playerData: null,
    instanceId: null
  });
  
  console.log('[GAME SERVER] Waiting for authentication from:', socket.id);
  
  // Update player count on API server when new player connects
  updatePlayerCountOnAPI();
  
  // Add timeout for authentication
  const authTimeout = setTimeout(() => {
    const clientData = connectedClients.get(socket.id);
    if (clientData && !clientData.userId) {
      console.log('[GAME SERVER] Authentication timeout for:', socket.id);
      socket.emit('authenticated', {
        success: false,
        error: 'Authentication timeout'
      });
      socket.disconnect();
    }
  }, 10000); // 10 seconds timeout
  
  // Clear timeout when authenticated
  socket.on('authenticated', () => {
    clearTimeout(authTimeout);
  });
  
  // Authentication (similar to LocalServer)
  socket.on('authenticate', async (data) => {
    console.log('[GAME SERVER] Authenticating client:', socket.id, data);
    
    try {
      // Check database connection first
      if (mongoose.connection.readyState !== 1) {
        console.error('[GAME SERVER] Database not connected, authentication failed');
        socket.emit('authenticated', {
          success: false,
          error: 'Database not available'
        });
        return;
      }
      
      console.log('[GAME SERVER] Database is connected, proceeding with authentication');
      
      // Load player data from database
      const playerData = await loadPlayerData(data.userId || socket.id, data.username || 'Game Player');
      
      if (playerData) {
        console.log('[GAME SERVER] Player data loaded successfully:', playerData.username);
        
        // Store player data in client connection
        const clientData = connectedClients.get(socket.id);
        if (clientData) {
          clientData.playerData = playerData;
          clientData.userId = playerData.userId;
          clientData.username = playerData.username;
        } else {
          console.error('[GAME SERVER] No client data found for socket:', socket.id);
        }
        
        // Join server
        playerData.joinServer(`devgame-server-${PORT}`);
        
        // Update last login time
        if (!playerData.stats) playerData.stats = {};
        playerData.stats.lastLogin = new Date().toISOString();
        
        // Ensure all required fields exist (for existing players)
        if (playerData.stats.totalExperience === undefined) playerData.stats.totalExperience = playerData.stats.experience || 0;
        if (playerData.stats.gems === undefined || playerData.stats.gems === 0) playerData.stats.gems = 50; // Restore gems if wiped
        if (playerData.stats.skillPoints === undefined) playerData.stats.skillPoints = 0;
        if (playerData.stats.totalKills === undefined) playerData.stats.totalKills = 0;
        if (playerData.stats.questsCompleted === undefined) playerData.stats.questsCompleted = 0;
        
        await savePlayerData(playerData.userId, playerData);
        
        // In production, validate with API server
        socket.emit('authenticated', {
          success: true,
          user: {
            id: playerData.userId,
            username: playerData.username,
            token: 'game-token-' + Date.now()
          },
          playerData: {
            ...playerData.toObject(),
            serverTimestamp: Date.now(), // Add server timestamp for time synchronization
            serverTimezone: 'UTC' // Server operates in UTC timezone
          }
        });
        
        console.log(`[GAME SERVER] ${playerData.username} authenticated with Level ${playerData.stats.level}`);
      } else {
        console.error('[GAME SERVER] Failed to load player data');
        socket.emit('authenticated', {
          success: false,
          error: 'Failed to load player data'
        });
      }
    } catch (error) {
      console.error('[GAME SERVER] Authentication error:', error);
      console.error('[GAME INITIALIZER] Error stack:', error.stack);
      socket.emit('authenticated', {
        success: false,
        error: 'Authentication failed: ' + error.message
      });
    }
  });
  
  // Game data events (similar to LocalServer)
  socket.on('saveGameData', async (data) => {
    console.log('[GAME SERVER] Saving game data for:', socket.id);
    
    const clientData = connectedClients.get(socket.id);
    if (clientData && clientData.userId) {
      try {
        // Validate the data before saving
        if (!data || typeof data !== 'object') {
          console.warn('[GAME SERVER] Invalid game data received, skipping save');
          socket.emit('gameDataSaved', { success: false, error: 'Invalid game data' });
          return;
        }
        
        // Update player data with new game data
        const updatedPlayerData = { ...clientData.playerData, ...data };
        clientData.playerData = updatedPlayerData;
        
        // Save to database
        const success = await savePlayerData(clientData.userId, updatedPlayerData);
        
        socket.emit('gameDataSaved', { 
          success: success,
          message: success ? 'Game saved to server!' : 'Failed to save to server'
        });
        
        console.log(`[GAME SERVER] Saved game data for ${clientData.username}`);
      } catch (error) {
        console.error('[GAME SERVER] Error saving game data:', error);
        socket.emit('gameDataSaved', { success: false, error: 'Failed to save data' });
      }
    } else {
      console.warn('[GAME SERVER] No client data or user ID found for saveGameData');
      socket.emit('gameDataSaved', { success: false, error: 'Player not authenticated' });
    }
  });

  socket.on('loadGameData', (data) => {
    console.log('[GAME SERVER] Loading game data for:', socket.id);
    
    const playerData = connectedClients.get(socket.id)?.playerData || {};
    
    socket.emit('gameDataLoaded', {
      success: true,
      data: playerData
    });
  });
  
  // Shop and item system events
  socket.on('getShopItems', (data) => {
    console.log('[GAME SERVER] Sending shop items to:', socket.id);
    
    try {
      const shopItems = itemSystem.getShopItems();
      socket.emit('shopItemsReceived', {
        success: true,
        items: shopItems,
        timestamp: new Date().toISOString()
      });
    } catch (error) {
      console.error('[GAME SERVER] Error sending shop items:', error);
      socket.emit('shopItemsReceived', {
        success: false,
        error: 'Failed to load shop items'
      });
    }
  });
  
  socket.on('getItemDetails', (data) => {
    const { itemId } = data;
    
    if (!itemId) {
      socket.emit('itemDetailsReceived', {
        success: false,
        error: 'Item ID required'
      });
      return;
    }
    
    try {
      const item = itemSystem.getItem(itemId);
      
      if (!item) {
        socket.emit('itemDetailsReceived', {
          success: false,
          error: 'Item not found'
        });
        return;
      }
      
      socket.emit('itemDetailsReceived', {
        success: true,
        item: item
      });
    } catch (error) {
      console.error('[GAME SERVER] Error getting item details:', error);
      socket.emit('itemDetailsReceived', {
        success: false,
        error: 'Failed to get item details'
      });
    }
  });
  
  // Game-specific events
  socket.on('joinGameInstance', (data) => {
    const { instanceId } = data;
    
    if (!gameInstances.has(instanceId)) {
      gameInstances.set(instanceId, {
        id: instanceId,
        players: new Set(),
        createdAt: Date.now()
      });
    }
    
    const instance = gameInstances.get(instanceId);
    instance.players.add(socket.id);
    
    connectedClients.get(socket.id).instanceId = instanceId;
    socket.join(instanceId);
    
    socket.emit('joinedGameInstance', {
      instanceId,
      playerCount: instance.players.size
    });
    
    // Notify other players
    socket.to(instanceId).emit('playerJoinedInstance', {
      playerId: socket.id,
      playerCount: instance.players.size
    });
  });
  
  socket.on('leaveGameInstance', (data) => {
    const clientData = connectedClients.get(socket.id);
    if (clientData && clientData.instanceId) {
      const instance = gameInstances.get(clientData.instanceId);
      if (instance) {
        instance.players.delete(socket.id);
        socket.leave(clientData.instanceId);
        
        // Clean up empty instances
        if (instance.players.size === 0) {
          gameInstances.delete(clientData.instanceId);
        }
        
        // Notify other players
        socket.to(clientData.instanceId).emit('playerLeftInstance', {
          playerId: socket.id,
          playerCount: instance.players.size
        });
      }
      
      clientData.instanceId = null;
    }
  });
  
  socket.on('gameAction', (data) => {
    const clientData = connectedClients.get(socket.id);
    if (clientData && clientData.instanceId) {
      // Broadcast game action to other players in same instance
      socket.to(clientData.instanceId).emit('gameAction', {
        playerId: socket.id,
        action: data,
        timestamp: Date.now()
      });
    }
  });
  
  // Idle rewards events
  socket.on('claimOfflineRewards', async (data) => {
    console.log('[GAME SERVER] Claiming offline rewards for:', socket.id);
    
    const clientData = connectedClients.get(socket.id);
    if (!clientData || !clientData.userId) {
      socket.emit('offlineRewardsClaimed', { success: false, error: 'Not authenticated' });
      return;
    }
    
    try {
      const playerData = await loadPlayerData(clientData.userId);
      const offlineRewards = idleSystem.calculateOfflineRewards(clientData.userId);
      
      if (offlineRewards.offlineTime > 0 && offlineRewards.rewards.credits > 0) {
        // Apply rewards to player
        playerData.stats.credits = (playerData.stats.credits || 0) + offlineRewards.rewards.credits;
        playerData.stats.experience = (playerData.stats.experience || 0) + offlineRewards.rewards.experience;
        
        // Update idle system data
        if (!playerData.idleSystem) playerData.idleSystem = {};
        playerData.idleSystem.lastActive = new Date().toISOString();
        playerData.idleSystem.totalOfflineTime += offlineRewards.offlineTime;
        playerData.idleSystem.totalIdleCredits += offlineRewards.rewards.credits;
        
        await savePlayerData(clientData.userId, playerData);
        
        socket.emit('offlineRewardsClaimed', { 
          success: true, 
          rewards: offlineRewards.rewards,
          offlineTime: offlineRewards.offlineTime
        });
        
        console.log(`[GAME SERVER] Offline rewards claimed for ${clientData.username}: ${offlineRewards.rewards.credits} credits`);
      } else {
        socket.emit('offlineRewardsClaimed', { 
          success: true, 
          rewards: { credits: 0, experience: 0, energy: 0 },
          offlineTime: 0
        });
      }
    } catch (error) {
      console.error('[GAME SERVER] Error claiming offline rewards:', error);
      socket.emit('offlineRewardsClaimed', { success: false, error: 'Failed to claim rewards' });
    }
  });
  
  // Shop purchase events
  socket.on('purchaseItem', async (data) => {
    console.log('[GAME SERVER] Processing purchase request:', socket.id, data);
    
    const clientData = connectedClients.get(socket.id);
    if (!clientData || !clientData.userId) {
      console.log('[GAME SERVER] Purchase failed - not authenticated');
      socket.emit('purchaseCompleted', { success: false, error: 'Not authenticated' });
      return;
    }
    
    try {
      const { itemId, quantity = 1 } = data;
      
      console.log('[GAME SERVER] Purchase details:', {
        itemId: itemId,
        quantity: quantity,
        userId: clientData.userId,
        username: clientData.username
      });
      
      if (!itemId) {
        console.log('[GAME SERVER] Purchase failed - no item ID');
        socket.emit('purchaseCompleted', { success: false, error: 'Item ID required' });
        return;
      }
      
      // Load current player data
      const playerData = await loadPlayerData(clientData.userId);
      console.log('[GAME SERVER] Player data loaded:', {
        username: playerData.username,
        credits: playerData.stats.credits,
        gems: playerData.stats.gems
      });
      
      // Find the item in shop (server-side validation)
      const item = findShopItem(itemId);
      if (!item) {
        console.log('[GAME SERVER] Purchase failed - item not found:', itemId);
        socket.emit('purchaseCompleted', { success: false, error: 'Item not found in shop' });
        return;
      }
      
      console.log('[GAME SERVER] Item found:', {
        id: item.id,
        name: item.name,
        type: item.type,
        price: item.price,
        currency: item.currency
      });
      
      // Calculate total cost
      const totalCost = item.price * quantity;
      const currency = item.currency;
      
      console.log('[GAME SERVER] Cost calculation:', {
        unitPrice: item.price,
        quantity: quantity,
        totalCost: totalCost,
        currency: currency
      });
      
      // Check if player can afford
      if (currency === 'credits' && (playerData.stats.credits || 0) < totalCost) {
        console.log('[GAME SERVER] Purchase failed - insufficient credits:', {
          required: totalCost,
          current: playerData.stats.credits || 0
        });
        socket.emit('purchaseCompleted', { success: false, error: 'Not enough credits' });
        return;
      }
      
      if (currency === 'gems' && (playerData.stats.gems || 0) < totalCost) {
        console.log('[GAME SERVER] Purchase failed - insufficient gems:', {
          required: totalCost,
          current: playerData.stats.gems || 0
        });
        socket.emit('purchaseCompleted', { success: false, error: 'Not enough gems' });
        return;
      }
      
      // Check if already owns this cosmetic
      if (item.type === 'cosmetic' && playerData.ownedCosmetics && playerData.ownedCosmetics.includes(item.id)) {
        console.log('[GAME SERVER] Purchase failed - already owns cosmetic:', item.id);
        socket.emit('purchaseCompleted', { success: false, error: 'You already own this cosmetic' });
        return;
      }
      
      // Process payment
      console.log('[GAME SERVER] Processing payment...');
      if (currency === 'credits') {
        playerData.stats.credits = (playerData.stats.credits || 0) - totalCost;
      } else if (currency === 'gems') {
        playerData.stats.gems = (playerData.stats.gems || 0) - totalCost;
      }
      
      console.log('[GAME SERVER] Payment processed, new balance:', {
        credits: playerData.stats.credits,
        gems: playerData.stats.gems
      });
      
      // Give item based on type
      console.log('[GAME SERVER] Adding item to inventory, type:', item.type);
      switch (item.type) {
        case 'ship':
          if (!playerData.ownedShips) playerData.ownedShips = [];
          if (!playerData.ownedShips.includes(item.id)) {
            playerData.ownedShips.push(item.id);
            console.log('[GAME SERVER] Ship added to owned ships:', item.id);
          } else {
            console.log('[GAME SERVER] Ship already owned:', item.id);
          }
          break;
          
        case 'cosmetic':
          if (!playerData.ownedCosmetics) playerData.ownedCosmetics = [];
          if (!playerData.ownedCosmetics.includes(item.id)) {
            playerData.ownedCosmetics.push(item.id);
            console.log('[GAME SERVER] Cosmetic added to owned cosmetics:', item.id);
          } else {
            console.log('[GAME SERVER] Cosmetic already owned:', item.id);
          }
          break;
          
        case 'consumable':
          if (!playerData.inventory) playerData.inventory = { items: [] };
          playerData.inventory.items.push({
            id: item.id,
            name: item.name,
            type: item.type,
            quantity: quantity,
            acquired: new Date().toISOString()
          });
          console.log('[GAME SERVER] Consumable added to inventory:', item.name);
          break;
          
        case 'material':
          if (!playerData.inventory) playerData.inventory = { items: [] };
          playerData.inventory.items.push({
            id: item.id,
            name: item.name,
            type: item.type,
            quantity: quantity,
            acquired: new Date().toISOString()
          });
          console.log('[GAME SERVER] Material added to inventory:', item.name);
          break;
          
        default:
          console.warn(`[GAME SERVER] Unknown item type: ${item.type}`);
          socket.emit('purchaseCompleted', { success: false, error: 'Unknown item type' });
          return;
      }
      
      // Save updated player data
      console.log('[GAME SERVER] Saving player data...');
      await savePlayerData(clientData.userId, playerData);
      
      // Update client data with new values
      clientData.playerData = playerData;
      
      // Send success response
      const response = {
        success: true,
        item: item,
        quantity: quantity,
        totalCost: totalCost,
        currency: currency,
        newBalance: currency === 'credits' ? playerData.stats.credits : playerData.stats.gems
      };
      
      console.log('[GAME SERVER] Sending success response:', response);
      socket.emit('purchaseCompleted', response);
      
      console.log(`[GAME SERVER] Purchase completed for ${clientData.username}: ${item.name} x${quantity} for ${totalCost} ${currency}`);
      
      // Broadcast economy update to client
      broadcastEconomyUpdate(socket.id);
      
    } catch (error) {
      console.error('[GAME SERVER] Error processing purchase:', error);
      socket.emit('purchaseCompleted', { success: false, error: 'Purchase failed: ' + error.message });
    }
  });
  
  // Dungeon System Packet Handlers
  socket.on('get_dungeons', () => {
    console.log('[GAME SERVER] Sending dungeons data to:', socket.id);
    const dungeons = dungeonSystem.getDungeonsGroupedByDifficulty();
    socket.emit('dungeons_data', { dungeons });
  });
  
  socket.on('get_room_types', () => {
    console.log('[GAME SERVER] Sending room types to:', socket.id);
    const roomTypes = dungeonSystem.getRoomTypes();
    socket.emit('room_types_data', roomTypes);
  });
  
  socket.on('get_enemy_templates', () => {
    console.log('[GAME SERVER] Sending enemy templates to:', socket.id);
    const enemyTemplates = dungeonSystem.getEnemyTemplates();
    socket.emit('enemy_templates_data', enemyTemplates);
  });
  
  // Economy System Packet Handlers
  socket.on('get_economy_data', () => {
    console.log('[GAME SERVER] Sending economy data to:', socket.id);
    const clientData = connectedClients.get(socket.id);
    if (clientData && clientData.playerData) {
      const economyData = {
        credits: clientData.playerData.stats.credits || 0,
        gems: clientData.playerData.stats.gems || 0
      };
      socket.emit('economy_data', economyData);
    }
  });
  
  // Function to broadcast economy updates to specific client
  function broadcastEconomyUpdate(socketId) {
    const clientData = connectedClients.get(socketId);
    if (clientData && clientData.playerData) {
      const economyData = {
        credits: clientData.playerData.stats.credits || 0,
        gems: clientData.playerData.stats.gems || 0
      };
      io.to(socketId).emit('economy_data', economyData);
      console.log('[GAME SERVER] Broadcasted economy update to:', socketId, economyData);
    }
  }
  
  socket.on('start_dungeon', (data) => {
    console.log('[GAME SERVER] Starting dungeon for:', socket.id, data);
    try {
      const { dungeonId, userId } = data;
      const instance = dungeonSystem.createInstance(dungeonId, userId, []);
      socket.emit('dungeon_started', { instance });
    } catch (error) {
      console.error('[GAME SERVER] Error starting dungeon:', error);
      socket.emit('dungeon_started', { success: false, error: error.message });
    }
  });
  
  socket.on('process_encounter', (data) => {
    console.log('[GAME SERVER] Processing encounter for:', socket.id, data);
    try {
      const { instanceId, userId } = data;
      const encounter = dungeonSystem.startEncounter(instanceId, userId);
      socket.emit('encounter_data', { encounter });
    } catch (error) {
      console.error('[GAME SERVER] Error processing encounter:', error);
      socket.emit('encounter_data', { success: false, error: error.message });
    }
  });
  
  socket.on('complete_dungeon', (data) => {
    console.log('[GAME SERVER] Completing dungeon for:', socket.id, data);
    try {
      const { instanceId, userId } = data;
      const result = dungeonSystem.completeDungeon(instanceId);
      socket.emit('dungeon_completed', { rewards: result });
    } catch (error) {
      console.error('[GAME SERVER] Error completing dungeon:', error);
      socket.emit('dungeon_completed', { success: false, error: error.message });
    }
  });
  
  socket.on('get_dungeon_status', (data) => {
    console.log('[GAME SERVER] Getting dungeon status for:', socket.id, data);
    try {
      const { userId } = data;
      const instance = dungeonSystem.getPlayerInstance(userId);
      if (instance) {
        socket.emit('dungeon_status', { 
          hasActiveDungeon: true, 
          currentInstance: instance 
        });
      } else {
        socket.emit('dungeon_status', { 
          hasActiveDungeon: false, 
          currentInstance: null 
        });
      }
    } catch (error) {
      console.error('[GAME SERVER] Error getting dungeon status:', error);
      socket.emit('dungeon_status', { success: false, error: error.message });
    }
  });
  
  socket.on('disconnect', async () => {
    console.log('[GAME SERVER] Client disconnected:', socket.id);
    
    const clientData = connectedClients.get(socket.id);
    if (clientData) {
      // Save player data before disconnect
      if (clientData.playerData && clientData.userId) {
        try {
          clientData.playerData.leaveServer();
          await savePlayerData(clientData.userId, clientData.playerData);
          console.log(`[GAME SERVER] Saved data for ${clientData.username} on disconnect`);
        } catch (error) {
          console.error('[GAME SERVER] Error saving data on disconnect:', error);
        }
      }
      
      // Handle game instance cleanup
      if (clientData.instanceId) {
        const instance = gameInstances.get(clientData.instanceId);
        if (instance) {
          instance.players.delete(socket.id);
          
          // Clean up empty instances
          if (instance.players.size === 0) {
            gameInstances.delete(clientData.instanceId);
          }
          
          // Notify other players
          socket.to(clientData.instanceId).emit('playerLeftInstance', {
            playerId: socket.id,
            playerCount: instance.players.size
          });
        }
      }
    }
    
    connectedClients.delete(socket.id);
    
    // Update player count on API server
    updatePlayerCountOnAPI();
  });
});

// Load player data from database
async function loadPlayerData(userId, username) {
  try {
    // Check if database is connected
    if (mongoose.connection.readyState !== 1) {
      console.error('[GAME SERVER] Database not connected, cannot load player data');
      return null;
    }
    
    let playerData = await PlayerData.findOne({ userId });
    
    if (!playerData) {
      // Create new player data with initialized systems
      console.log(`[GAME SERVER] Creating new player data for ${username} with system initialization`);
      
      // Initialize player data in all systems
      const questData = questSystem.initializePlayerData(userId);
      const skillData = skillSystem.initializePlayerData(userId);
      const craftingData = craftingSystem.initializePlayerData(userId);
      
      // For dungeons, initialize with available dungeons
      const availableDungeons = dungeonSystem.getAllDungeons();
      const dungeonData = {
        availableDungeons: availableDungeons.map(d => ({
          id: d.id,
          name: d.name,
          difficulty: d.difficulty,
          minLevel: d.minLevel || 1,
          maxPlayers: d.maxPlayers || 4,
          description: d.description
        })),
        completedDungeons: [],
        currentInstance: null,
        dungeonProgress: {}
      };
      
      playerData = new PlayerData({
        userId,
        username,
        stats: {
          level: 1,
          experience: 0,
          totalExperience: 0,
          credits: 1000,
          gems: 50, // Give some starting gems
          skillPoints: 0,
          totalKills: 0,
          dungeonsCleared: 0,
          questsCompleted: 0,
          playTime: 0,
          lastLogin: new Date()
        },
        // Initialize with system data
        quests: {
          active: Array.from(questData.activeQuests.values()),
          completed: Array.from(questData.completedQuests.keys())
        },
        skills: skillData,
        dungeonSystem: dungeonData,
        crafting: craftingData
      });
      await playerData.save();
      console.log(`[GAME SERVER] Created new player data for ${username} with ${questData.activeQuests.size} active quests`);
    } else {
      // Auto-migration for existing players - check for missing data
      console.log(`[GAME SERVER] Loading existing player data for ${username} (Level ${playerData.stats.level})`);
      
      let migrated = false;
      let migrationLog = [];
      
      // Always categorize quests to ensure proper format
      console.log(`[GAME SERVER] Categorizing quests for ${username}`);
      console.log(`[GAME SERVER] Current playerData.quests before categorization:`, playerData.quests);
      
      const questData = questSystem.getPlayerData(userId);
      console.log(`[GAME SERVER] QuestSystem data:`, {
        activeQuestsCount: questData.activeQuests.size,
        completedQuestsCount: questData.completedQuests.size,
        activeQuests: Array.from(questData.activeQuests.values())
      });
      
      // Categorize quests by type for client
      const activeQuests = Array.from(questData.activeQuests.values());
      const mainQuests = activeQuests.filter(quest => quest.type === 'main');
      const dailyQuests = activeQuests.filter(quest => quest.type === 'daily');
      const weeklyQuests = activeQuests.filter(quest => quest.type === 'weekly');
      const tutorialQuests = activeQuests.filter(quest => quest.type === 'tutorial');
      
      playerData.quests = {
        main: mainQuests,
        daily: dailyQuests,
        weekly: weeklyQuests,
        tutorial: tutorialQuests,
        active: activeQuests,
        completed: Array.from(questData.completedQuests.keys())
      };
      
      console.log(`[GAME SERVER] Quest categorization complete:`, {
        main: mainQuests.length,
        daily: dailyQuests.length,
        weekly: weeklyQuests.length,
        tutorial: tutorialQuests.length,
        total: activeQuests.length
      });
      
      console.log(`[GAME SERVER] Final playerData.quests after categorization:`, playerData.quests);
      
      // IMPORTANT: Save the updated quest data to database
      try {
        await savePlayerData(userId, playerData);
        console.log(`[GAME SERVER] Saved categorized quest data for ${username}`);
      } catch (error) {
        console.error(`[GAME SERVER] Failed to save quest data for ${username}:`, error);
      }
      
      // Migrate skills if missing or empty
      if (!playerData.skills || Object.keys(playerData.skills).length === 0) {
        console.log(`[GAME SERVER] Migrating skills for ${username}`);
        const skillData = skillSystem.initializePlayerData(userId);
        playerData.skills = skillData;
        migrated = true;
        migrationLog.push('Added skill data');
      }
      
      // Migrate dungeons if missing or empty
      if (!playerData.dungeonSystem || !playerData.dungeonSystem.availableDungeons || 
          (playerData.dungeonSystem.availableDungeons && playerData.dungeonSystem.availableDungeons.length === 0)) {
        console.log(`[GAME SERVER] Migrating dungeons for ${username}`);
        const availableDungeons = dungeonSystem.getAllDungeons();
        playerData.dungeonSystem = {
          availableDungeons: availableDungeons.map(d => ({
            id: d.id,
            name: d.name,
            difficulty: d.difficulty,
            minLevel: d.minLevel || 1,
            maxPlayers: d.maxPlayers || 4,
            description: d.description
          })),
          completedDungeons: [],
          currentInstance: null,
          dungeonProgress: {}
        };
        migrated = true;
        migrationLog.push(`Added ${availableDungeons.length} available dungeons`);
      }
      
      // Migrate crafting if missing or empty (this field might not exist at all)
      if (!playerData.crafting || Object.keys(playerData.crafting).length === 0) {
        console.log(`[GAME SERVER] Migrating crafting for ${username}`);
        const craftingData = craftingSystem.initializePlayerData(userId);
        playerData.crafting = craftingData;
        migrated = true;
        migrationLog.push('Added crafting data');
      }
      
      // Initialize idle system data
      const idleData = idleSystem.initializePlayerData(userId);
      if (!playerData.idleSystem) {
        playerData.idleSystem = {
          lastActive: new Date().toISOString(),
          totalOfflineTime: 0,
          totalIdleCredits: 0
        };
        migrated = true;
        migrationLog.push('Added idle system data');
      }
      
      // Save if migration occurred
      if (migrated) {
        await playerData.save();
        console.log(`[GAME SERVER] Migration completed for ${username}: ${migrationLog.join(', ')}`);
      }
      
      // Update existing player login info
      playerData.username = username;
      playerData.lastLogin = new Date();
      await playerData.save();
    }
    
    return playerData;
  } catch (error) {
    console.error('[GAME SERVER] Error loading player data:', error);
    return null;
  }
}

// Save player data to database
async function savePlayerData(userId, playerData) {
  try {
    // Check if database is connected
    if (mongoose.connection.readyState !== 1) {
      console.error('[GAME SERVER] Database not connected, cannot save player data');
      return false;
    }
    
    await PlayerData.findOneAndUpdate(
      { userId },
      playerData,
      { upsert: true, new: true }
    );
    console.log(`[GAME SERVER] Saved player data for ${playerData.username}`);
    return true;
  } catch (error) {
    console.error('[GAME SERVER] Error saving player data:', error);
    return false;
  }
}

// Update player count on API server
async function updatePlayerCountOnAPI() {
  try {
    const apiServerUrl = 'http://localhost:3001';
    const currentPlayers = connectedClients.size;
    
    console.log(`[GAME SERVER] Updating player count: ${currentPlayers} players`);
    
    const response = await fetch(`${apiServerUrl}/api/servers/update-status/devgame-server-3002`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        currentPlayers: currentPlayers,
        status: currentPlayers > 0 ? 'active' : 'waiting'
      })
    });
    
    if (response.ok) {
      const result = await response.json();
      console.log(`[GAME SERVER] Player count updated:`, result);
    } else {
      console.error(`[GAME SERVER] Failed to update player count: ${response.status}`);
    }
  } catch (error) {
    console.error('[GAME SERVER] Error updating player count:', error);
  }
}

// Start server
const PORT = process.env.PORT || 3002;

async function startServer() {
  try {
    console.log('[GAME SERVER] Attempting to connect to database...');
    
    // Connect to database
    await connectDB();
    
    console.log('[GAME SERVER] Database connection established');
    
    server.listen(PORT, async () => {
      console.log(`[GAME SERVER] Game server running on port ${PORT}`);
      console.log(`[GAME SERVER] Socket.IO ready for multiplayer connections`);
      
      // Register with API server
      await registerWithAPIServer();
      
      // Start periodic player count updates
      setInterval(updatePlayerCountOnAPI, 30000); // Update every 30 seconds
      
      // Start online idle rewards generation (every 10 seconds)
      setInterval(async () => {
        for (const [socketId, clientData] of connectedClients.entries()) {
          if (clientData.userId && clientData.playerData) {
            try {
              // Update playTime for active players
              const sessionTime = clientData.playerData.updatePlayTime();
              console.log(`[GAME SERVER] Updated playTime for ${clientData.username}: +${sessionTime}ms, Total: ${clientData.playerData.stats.playTime}ms`);
              
              // Send playTime update to client
              io.to(socketId).emit('playTimeUpdated', {
                playTime: clientData.playerData.stats.playTime,
                sessionTime: sessionTime
              });
              
              const onlineRewards = idleSystem.generateOnlineIdleRewards(clientData.userId, 10000); // 10 seconds
              
              if (onlineRewards.credits > 0) {
                // Update player data with online rewards
                clientData.playerData.stats.credits = (clientData.playerData.stats.credits || 0) + onlineRewards.credits;
                clientData.playerData.stats.experience = (clientData.playerData.stats.experience || 0) + onlineRewards.experience;
                
                // Send update to client
                io.to(socketId).emit('onlineIdleRewards', {
                  credits: onlineRewards.credits,
                  experience: onlineRewards.experience,
                  newBalance: clientData.playerData.stats.credits,
                  playTime: clientData.playerData.stats.playTime
                });
              }
            } catch (error) {
              console.error(`[GAME SERVER] Error generating online idle rewards for ${socketId}:`, error);
            }
          }
        }
      }, 10000); // Every 10 seconds
    });
  } catch (error) {
    console.error('[GAME SERVER] Failed to start server:', error);
    process.exit(1);
  }
}

// Register this GameServer with the API server
async function registerWithAPIServer() {
  try {
    // Force use of local API server for development
    const apiServerUrl = 'http://localhost:3001';
    const gameServerUrl = 'https://dev.gameserver.galaxystrike.online';
    
    const serverData = {
      serverId: `devgame-server-${PORT}`,
      name: 'Dev Game Server',
      type: 'public', // Must be 'public' or 'private' according to model
      region: 'Europe',
      maxPlayers: 100, // Hardcoded to allow 100 players
      currentPlayers: 0,
      gameServerUrl: gameServerUrl,
      owner: {
        userId: 'developer',
        username: 'Developer'
      }
    };
    
    console.log(`[GAME SERVER] Registering with API server at ${apiServerUrl}`);
    console.log(`[GAME SERVER] Server data:`, serverData);
    
    const response = await fetch(`${apiServerUrl}/api/servers/register`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(serverData)
    });
    
    if (response.ok) {
      const result = await response.json();
      console.log(`[GAME SERVER] Successfully registered with API server:`, result);
    } else {
      const errorText = await response.text();
      console.error(`[GAME SERVER] Failed to register with API server: ${response.status}`);
      console.error(`[GAME SERVER] Error response:`, errorText);
    }
  } catch (error) {
    console.error('[GAME SERVER] Error registering with API server:', error);
  }
}

startServer();

module.exports = { app, server, io, gameInstances, connectedClients };
