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 rateLimit = require('rate-limiter-flexible');
require('dotenv').config();

const logger = require('./utils/logger');
const connectDB = require('./config/database');
const authRoutes = require('./routes/auth');
const gameRoutes = require('./routes/game');
const serverRoutes = require('./routes/servers');
const { initializeGameSystems } = require('./systems/GameSystem');
const SocketHandlers = require('./socket/socketHandlers');
const { errorHandler, notFound } = require('./middleware/errorHandler');

// Override console.error to properly log error objects
const originalConsoleError = console.error;
console.error = (...args) => {
  args.forEach(arg => {
    if (arg instanceof Error) {
      logger.error('Console Error:', {
        message: arg.message,
        stack: arg.stack,
        name: arg.name
      });
    } else if (typeof arg === 'object' && arg !== null) {
      logger.error('Console Error Object:', arg);
    } else {
      logger.error('Console Error:', arg);
    }
  });
};

const app = express();
const server = http.createServer(app);
const io = socketIo(server, {
  cors: {
    origin: ["https://galaxystrike.online", "https://api.korvarix.com", "http://api.korvarix.com:3001"],
    methods: ["GET", "POST"]
  }
});

// Middleware
app.use(helmet());
app.use(compression());
app.use(cors({
  origin: ["https://galaxystrike.online", "https://api.korvarix.com", "http://api.korvarix.com:3001"],
  credentials: true
}));
app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ extended: true }));

// Static file serving
app.use(express.static('../Website/dist'));

// Rate limiting
const { RateLimiterMemory } = require('rate-limiter-flexible');
const limiter = new RateLimiterMemory({
  keyGenerator: (req) => req.ip,
  points: 100, // limit each IP to 100 requests per windowMs
  duration: 900, // 15 minutes
  blockDuration: 900, // Block for 15 minutes
});
app.use('/api/', async (req, res, next) => {
  try {
    const resLimiter = await limiter.consume(req.ip);
    if (!resLimiter.remainingPoints) {
      return res.status(429).json({ error: 'Too many requests, please try again later.' });
    }
    next();
  } catch (error) {
    next();
  }
});

// Routes
app.use('/api/auth', authRoutes);
app.use('/api/game', gameRoutes);
app.use('/api/servers', serverRoutes);

// Health check
app.get('/health', (req, res) => {
  res.status(200).json({ 
    status: 'OK', 
    timestamp: new Date().toISOString(),
    uptime: process.uptime()
  });
});

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

// Fallback route for SPA - only serve index.html for non-API routes
app.get('*', (req, res) => {
  // Don't try to serve index.html for API routes
  if (req.path.startsWith('/api/')) {
    return res.status(404).json({ error: 'API endpoint not found' });
  }
  
  // Try dist first (for built files), fallback to public (for development)
  const distPath = require('path').resolve(__dirname, '../dist/index.html');
  const publicPath = require('path').resolve(__dirname, '../public/index.html');
  
  const fs = require('fs');
  if (fs.existsSync(distPath)) {
    res.sendFile(distPath);
  } else if (fs.existsSync(publicPath)) {
    res.sendFile(publicPath);
  } else {
    res.status(404).json({ error: 'Frontend not found' });
  }
});

// Socket.IO connection handling
const socketHandlers = new SocketHandlers(io);

io.on('connection', (socket) => {
  socketHandlers.handleConnection(socket);
});

// Error handling
app.use(notFound);
app.use(errorHandler);

// Initialize database and game systems
async function startServer() {
  try {
    // Connect to database
    await connectDB();
    logger.info('Database connected successfully');

    // Initialize game systems
    await initializeGameSystems();
    logger.info('Game systems initialized');

    // Check for duplicate accounts in database
    logger.info('Checking for duplicate accounts in database...');
    const socketHandlers = new SocketHandlers(io);
    const duplicateCheck = await socketHandlers.checkForDuplicateAccounts();
    
    if (duplicateCheck.error) {
      logger.error('Error checking duplicate accounts:', duplicateCheck.error);
    } else {
      logger.info('Duplicate account check completed successfully');
    }

    // Start server
    const PORT = process.env.PORT || 3003; // Combined Server on port 3003
    server.listen(PORT, () => {
      logger.info(`Combined Server running on port ${PORT}`);
      logger.info('Combined Server handles: Authentication, Server Browser, Multiplayer, User Management');
      
      // Log connection statistics every 5 minutes
      setInterval(() => {
        const stats = socketHandlers.getConnectionStats();
        logger.info('Connection stats:', stats);
      }, 300000);
    });
  } catch (error) {
    logger.error('Failed to start server:', error);
    process.exit(1);
  }
}

// Handle uncaught errors
process.on('uncaughtException', (error) => {
  logger.error('Uncaught Exception:', error);
});

process.on('unhandledRejection', (reason, promise) => {
  logger.error('Unhandled Rejection at:', promise, 'reason:', reason);
});

// Handle HTTP server errors
server.on('error', (error) => {
  logger.error('HTTP Server error:', error);
});

// Handle Socket.IO errors
io.on('error', (error) => {
  logger.error('Socket.IO error:', error);
});

startServer();

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