#!/usr/bin/env node

/**
 * Hittok Backend - Main Entry Point
 * 
 * This file handles:
 * - Server startup
 * - Database connection
 * - WebSocket setup
 * - Process event handling
 */

require('dotenv').config();
const http = require('http');
const mongoose = require('mongoose');
const { Server } = require('socket.io');
const app = require('./app');
const { connectDB } = require('./config/db');

// Get port from environment
const port = process.env.PORT || 5000;

// Create HTTP server
const server = http.createServer();

// Parse allowed origins from environment variable
const allowedOrigins = process.env.FRONTEND_URLS ? 
  process.env.FRONTEND_URLS.split(',').map(url => url.trim()) : 
  ['http://localhost:3000', 'http://localhost:5173'];

// CORS configuration middleware
const corsMiddleware = (req, res, next) => {
  const origin = req.headers.origin;
  
  // Set CORS headers for all responses
  if (origin && allowedOrigins.includes(origin)) {
    res.setHeader('Access-Control-Allow-Origin', origin);
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE, OPTIONS');
    res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-Requested-With, X-CSRF-Token');
    res.setHeader('Access-Control-Allow-Credentials', 'true');
    res.setHeader('Access-Control-Expose-Headers', 'set-cookie');
    
    // Handle preflight requests
    if (req.method === 'OPTIONS') {
      res.setHeader('Access-Control-Max-Age', '86400'); // 24 hours
      res.statusCode = 204; // No content
      res.end();
      return;
    }
  }
  
  next();
};

// Apply CORS middleware to all routes
server.on('request', (req, res) => {
  corsMiddleware(req, res, () => {
    // For non-OPTIONS requests, continue to the Express app
    if (!req.url.startsWith('/socket.io/')) {
      return app(req, res);
    }
  });
});

// Create Socket.io server with CORS configuration
const io = new Server(server, {
  cors: {
    origin: allowedOrigins,
    methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
    allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With', 'X-CSRF-Token'],
    credentials: true
  },
  path: '/socket.io/'
});

// Socket.io connection handling
io.on('connection', (socket) => {
  console.log('New client connected');
  
  // Handle order status updates
  socket.on('orderStatusUpdate', (data) => {
    io.emit('orderStatusUpdated', data);
  });

  // Handle disconnection
  socket.on('disconnect', () => {
    console.log('Client disconnected');
  });
});

// Make io accessible to routes
app.set('io', io);

// Test database connection
async function testDbConnection() {
  try {
    const connection = mongoose.connection;
    
    // If not connected, wait for the 'open' event
    if (connection.readyState !== 1) { // 1 means connected
      await new Promise((resolve, reject) => {
        connection.once('open', resolve);
        connection.on('error', reject);
        
        // Set a timeout to prevent hanging
        setTimeout(() => {
          reject(new Error('Connection timeout'));
        }, 10000); // 10 seconds timeout
      });
    }
    
    // Test the connection with a ping
    await connection.db.admin().ping();
    console.log('✅ Database connection successful');
    return true;
  } catch (error) {
    console.error('❌ Database connection failed');
    console.error(error);
    return false;
  }
}

// Start the server
async function startServer() {
  try {
    // Connect to MongoDB
    console.log('Connecting to MongoDB...');
    await connectDB();
    
    // Test database connection
    const dbConnected = await testDbConnection();
    if (!dbConnected) {
      throw new Error('Failed to connect to database');
    }
    
    // Function to start the server on the specified port
    const startServerOnPort = (portToTry) => {
      return new Promise((resolve, reject) => {
        const serverInstance = server.listen(portToTry);
        
        serverInstance.on('listening', () => {
          console.log(`🚀 Server running on port ${portToTry} in ${process.env.NODE_ENV || 'development'} mode`);
          resolve(serverInstance);
        });
        
        serverInstance.on('error', (error) => {
          if (error.code === 'EADDRINUSE') {
            console.error(`❌ Port ${portToTry} is already in use.`);
            console.log('Please close any other instances of the server or check what is using port 5000.');
            console.log('To find and stop the process using port 5000, run:');
            console.log('  netstat -ano | findstr :5000');
            console.log('Then use the PID to terminate it:');
            console.log('  taskkill /PID <PID> /F');
            process.exit(1);
          } else {
            reject(error);
          }
        });
      });
    };
    
    // Start the server on the specified port
    console.log(`Starting server on port ${port}...`);
    await startServerOnPort(port);
  } catch (error) {
    console.error('Failed to start server:', error);
    process.exit(1);
  }
}

// Handle unhandled promise rejections
process.on('unhandledRejection', (err) => {
  console.error('UNHANDLED REJECTION! 💥 Shutting down...');
  console.error(err.name, err.message);
  
  // Close server & exit process
  server.close(() => {
    process.exit(1);
  });
});

// Handle uncaught exceptions
process.on('uncaughtException', (err) => {
  console.error('UNCAUGHT EXCEPTION! 💥 Shutting down...');
  console.error(err.name, err.message);
  
  // Close server & exit process
  server.close(() => {
    process.exit(1);
  });
});

// Handle SIGTERM (Heroku)
process.on('SIGTERM', () => {
  console.log('👋 SIGTERM RECEIVED. Shutting down gracefully');
  
  // Close MongoDB connection
  mongoose.connection.close(() => {
    console.log('MongoDB connection closed');
  });
  
  // Close HTTP server
  server.close(() => {
    console.log('💥 Process terminated!');
    process.exit(0);
  });
});

// Start the application
startServer();
