const express = require('express');
const http = require('http');
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 serverRoutes = require('./routes/servers');
const { errorHandler, notFound } = require('./middleware/errorHandler');
const GameServer = require('./models/GameServer');

// 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);

// Middleware
app.use(helmet());
app.use(compression());
const allowedOrigins = [
  "https://galaxystrike.online",
  "https://api.korvarix.com",
  "http://api.korvarix.com:3001",
  "https://dev.gameserver.galaxystrike.online",
  "http://localhost:3000",
  "http://localhost:3001",
  "http://localhost:3002",
  ...(process.env.CLIENT_URL ? [process.env.CLIENT_URL] : []),
];
app.use(cors({
  origin: (origin, callback) => {
    // Allow no-origin (Electron, mobile, curl) + whitelisted origins
    if (!origin || allowedOrigins.includes(origin)) return callback(null, true);
    return callback(null, false);
  },
  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 (more lenient for development)
const { RateLimiterMemory } = require('rate-limiter-flexible');
const limiter = new RateLimiterMemory({
  keyGenerator: (req) => req.ip,
  points: 1000, // limit each IP to 1000 requests per windowMs (increased from 100)
  duration: 60, // 1 minute window (reduced from 15 minutes)
  blockDuration: 60, // Block for 1 minute (reduced from 15 minutes)
});

app.use('/api/', async (req, res, next) => {
  try {
    // Skip rate limiting for localhost in development
    const isLocalhost = req.ip === '127.0.0.1' || req.ip === '::1' || req.hostname === 'localhost';
    
    if (!isLocalhost) {
      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 (rejRes) {
    // Handle rate limit exceeded
    const secs = Math.round(rejRes.msBeforeNext / 1000) || 1;
    res.set('Retry-After', String(secs));
    res.status(429).json({ error: 'Too many requests, please try again later.' });
  }
});

// Routes - API Server Only (Auth + Server Browser)
app.use('/api/auth', authRoutes);
app.use('/api/servers', serverRoutes);

// Manual cleanup endpoint (for testing)
app.post('/api/admin/cleanup-dead-servers', async (req, res) => {
  try {
    await cleanupDeadServers();
    res.json({ success: true, message: 'Dead server cleanup completed' });
  } catch (error) {
    logger.error('Manual cleanup error:', error);
    res.status(500).json({ success: false, error: 'Cleanup failed' });
  }
});

// Health check
app.get('/health', (req, res) => {
  res.status(200).json({ 
    status: 'API Server OK', 
    service: 'galaxystrikeonline-api',
    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-api',
    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' });
  }
});

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

// Clean up dead servers
async function cleanupDeadServers() {
  try {
    logger.info('[API SERVER] Starting dead server cleanup...');
    
    // Find servers that haven't been updated in the last 5 minutes
    const fiveMinutesAgo = new Date(Date.now() - 5 * 60 * 1000);
    
    const deadServers = await GameServer.find({
      lastActivity: { $lt: fiveMinutesAgo }
    });
    
    if (deadServers.length > 0) {
      logger.info(`[API SERVER] Found ${deadServers.length} potentially dead servers, checking...`);
      
      for (const server of deadServers) {
        const isAlive = await checkServerHealth(server.gameServerUrl);
        
        if (!isAlive) {
          logger.info(`[API SERVER] Removing dead server: ${server.name} (${server.serverId})`);
          await GameServer.deleteOne({ _id: server._id });
        } else {
          logger.info(`[API SERVER] Server ${server.name} is still alive, updating lastActivity`);
          server.lastActivity = new Date();
          await server.save();
        }
      }
    } else {
      logger.info('[API SERVER] No dead servers found');
    }
    
  } catch (error) {
    logger.error('[API SERVER] Error during dead server cleanup:', error);
  }
}

// Check if a server is healthy
async function checkServerHealth(serverUrl) {
  try {
    if (!serverUrl) {
      return false;
    }
    
    // Add /health endpoint to the URL
    const healthUrl = serverUrl.endsWith('/') ? `${serverUrl}health` : `${serverUrl}/health`;
    
    const response = await fetch(healthUrl, {
      method: 'GET',
      timeout: 5000 // 5 second timeout
    });
    
    return response.ok;
  } catch (error) {
    logger.warn(`[API SERVER] Health check failed for ${serverUrl}:`, error.message);
    return false;
  }
}

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

    // Start API server
    const PORT = process.env.PORT || 3000;
    server.listen(PORT, () => {
      logger.info(`API Server running on port ${PORT}`);
      logger.info('API Server handles: Authentication, Server Browser, User Data');
      
      // Start dead server cleanup (every 2 minutes)
      setInterval(cleanupDeadServers, 120000);
    });
  } catch (error) {
    logger.error('Failed to start API 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);
});

startServer();

module.exports = { app, server };
