// Load logger first to catch any errors during startup
const logger = require('./config/logger');

// Set up global error handlers BEFORE any other imports
process.on('uncaughtException', (error) => {
    logger.logUncaughtException(error);
    // Give time for logs to be written before exiting
    setTimeout(() => {
        process.exit(1);
    }, 1000);
});

process.on('unhandledRejection', (reason, promise) => {
    logger.logUnhandledRejection(reason, promise);
});

// Log application startup
logger.info('=== EMS Backend Application Starting ===');

try {
    require('dotenv').config();
    const express = require('express');
    const bodyParser = require('body-parser');
    const cors = require('cors');
    const http = require('http');
    const setupWebSocket = require('./config/websocket');
    const websocketMiddleware = require('./middleware/websocketMiddleware');

    // Import routes
    const authRoutes = require('./routes/authRoutes');
    const ambulanceRequestRoutes = require('./routes/ambulanceRequestRoutes');
    const notificationRoutes = require('./routes/notificationRoutes');
    const statusRoutes = require('./routes/statusRoutes');
    const masmSchemeRoutes = require('./routes/masmSchemeRoutes');
    const userRoutes = require('./routes/userRoutes');
    const ambulanceRoutes = require('./routes/ambulanceRoutes');
    const driverRoutes = require('./routes/driverRoutes');
    const clientRoutes = require('./routes/clientRoutes');
    const dispatchRoutes = require('./routes/dispatchRoutes');
    const deviceTokenRoutes = require('./routes/deviceTokenRoutes');
    const incidentTypeRoutes = require('./routes/incidentTypeRoutes');
    const incidentDetailsRoutes = require('./routes/incidentDetailsRoutes');
    const patientReportRoutes = require('./routes/patientReportRoutes');
    const patientReportEmailRoutes = require('./routes/patientReportEmailRoutes');
    const approvedHealthCareEmailRoutes = require('./routes/approvedHealthCareEmailRoutes');

    const app = express();
    const server = http.createServer(app);
    const port = process.env.PORT || 4000;
    const host = process.env.HOST || 'localhost';
    const protocol = process.env.APP_PROTOCOL || 'http';

    // Initialize WebSocket
    let sendNotification, broadcastDispatch, broadcastNewAmbulanceRequest, broadcastRequestAssigned;
    try {
        const wsSetup = setupWebSocket(server);
        sendNotification = wsSetup.sendNotification;
        broadcastDispatch = wsSetup.broadcastDispatch;
        broadcastNewAmbulanceRequest = wsSetup.broadcastNewAmbulanceRequest;
        broadcastRequestAssigned = wsSetup.broadcastRequestAssigned;
        logger.info('WebSocket server initialized successfully');
    } catch (error) {
        logger.error('Failed to initialize WebSocket server', error);
        // Continue without WebSocket if it fails
    }

    // Middleware
    // CORS disabled - allow all origins
    app.use(cors({
        origin: '*',
        methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
        allowedHeaders: ['Content-Type', 'Authorization'],
        credentials: false
    }));
    app.use(bodyParser.json());
    app.use(bodyParser.urlencoded({ extended: true }));

    // WebSocket middleware to inject sendNotification/broadcast into requests
    if (sendNotification && broadcastDispatch && broadcastNewAmbulanceRequest && broadcastRequestAssigned) {
        app.use(websocketMiddleware(sendNotification, broadcastDispatch, broadcastNewAmbulanceRequest, broadcastRequestAssigned));
    }

    // Debug middleware to log all requests
    app.use((req, res, next) => {
        console.log(`[${new Date().toISOString()}] ${req.method} ${req.path} - Original: ${req.originalUrl} - Base: ${req.baseUrl}`);
        next();
    });

    // Base path for all routes (matches PassengerBaseURI)
    const BASE_PATH = '/EMS-backend';

    // Handle both root paths (with and without base URI)
    const handleRoot = (req, res) => {
        res.json({
            message: 'EMS Backend API is running',
            version: '1.0.0',
            endpoints: {
                auth: BASE_PATH + '/register, ' + BASE_PATH + '/login, ' + BASE_PATH + '/verify-email, ' + BASE_PATH + '/resend-otp',
                ambulanceRequests: BASE_PATH + '/ambulance-requests',
                myAmbulanceRequests: BASE_PATH + '/ambulance-requests/my-requests (GET, requires Bearer token)',
                notifications: BASE_PATH + '/notifications',
                users: BASE_PATH + '/users',
                ambulances: BASE_PATH + '/ambulances',
                drivers: BASE_PATH + '/drivers',
                clients: BASE_PATH + '/clients',
                dispatch: BASE_PATH + '/dispatch',
                masmSchemes: BASE_PATH + '/masm-schemes',
                deviceTokens: BASE_PATH + '/device-tokens',
                status: BASE_PATH + '/update-status',
                incidentTypes: BASE_PATH + '/incident-types',
                incidentDetails: BASE_PATH + '/incident-details',
                patientReports: BASE_PATH + '/patient-reports',
                approvedHealthCareEmails: BASE_PATH + '/approved-health-care-emails'
            },
            baseUrl: req.protocol + '://' + req.get('host') + BASE_PATH
        });
    };

    // Root route
    app.get(BASE_PATH, handleRoot);
    app.get(BASE_PATH + '/', handleRoot);
    // Also handle root without base path (for testing/standalone)
    app.get('/', handleRoot);

    // Routes - all prefixed with BASE_PATH
    app.use(BASE_PATH, authRoutes);
    app.use(BASE_PATH + '/ambulance-requests', ambulanceRequestRoutes);
    app.use(BASE_PATH + '/notifications', notificationRoutes);
    app.use(BASE_PATH, statusRoutes);
    app.use(BASE_PATH + '/masm-schemes', masmSchemeRoutes);
    // Alias for backward compatibility (singular form)
    app.use(BASE_PATH + '/masm-scheme', masmSchemeRoutes);
    app.use(BASE_PATH + '/users', userRoutes);
    app.use(BASE_PATH + '/ambulances', ambulanceRoutes);
    app.use(BASE_PATH + '/drivers', driverRoutes);
    app.use(BASE_PATH + '/clients', clientRoutes);
    app.use(BASE_PATH + '/dispatch', dispatchRoutes);
    app.use(BASE_PATH + '/device-tokens', deviceTokenRoutes);
    app.use(BASE_PATH + '/incident-types', incidentTypeRoutes);
    app.use(BASE_PATH + '/incident-details', incidentDetailsRoutes);
    app.use(BASE_PATH + '/patient-reports', patientReportRoutes);
    app.use(BASE_PATH + '/patient-report-emails', patientReportEmailRoutes);
    app.use(BASE_PATH + '/approved-health-care-emails', approvedHealthCareEmailRoutes);

    // Error handling middleware
    app.use((err, req, res, next) => {
        // Log error with request details
        logger.error('Express error middleware caught an error', {
            message: err.message,
            stack: err.stack,
            url: req.originalUrl,
            method: req.method,
            headers: req.headers,
            body: req.body
        });

        res.status(500).json({
            error: 'Something went wrong!',
            message: process.env.NODE_ENV === 'production' ? 'Internal server error' : err.message
        });
    });

    // 404 handler
    app.use((req, res) => {
        res.status(404).json({ message: 'Endpoint not found' });
    });

    // Start server
    // For Passenger: Passenger will call app.listen() automatically - just export the app
    // For standalone: explicitly start the server
    if (!process.env.PASSENGER_APP_ENV && !process.env.PASSENGER_APP_ROOT) {
        // Function to check if port is available
        const checkPort = (port, callback) => {
            const net = require('net');
            const tester = net.createServer()
                .once('error', (err) => {
                    if (err.code === 'EADDRINUSE') {
                        callback(false);
                    } else {
                        callback(true);
                    }
                })
                .once('listening', () => {
                    tester.once('close', () => callback(true))
                        .close();
                })
                .listen(port);
        };

        // Check port availability before binding (with retry logic)
        let retryCount = 0;
        const maxRetries = 5;
        const retryDelay = 2000; // 2 seconds

        const attemptStart = () => {
            checkPort(port, (isAvailable) => {
                if (!isAvailable) {
                    retryCount++;
                    if (retryCount < maxRetries) {
                        logger.warn(`Port ${port} is in use. Retrying in ${retryDelay/1000}s... (${retryCount}/${maxRetries})`);
                        setTimeout(attemptStart, retryDelay);
                        return;
                    } else {
                        logger.error(`Port ${port} is still in use after ${maxRetries} attempts.`);
                        logger.error('This may indicate another instance is running or the port is held by another process.');
                        logger.error('Exiting to prevent restart loop. PM2 will retry with backoff.');
                        // Exit with code 1 to trigger PM2 backoff strategy
                        process.exit(1);
                        return;
                    }
                }

                // Port is available, start the server
                try {
                    server.listen(port, host, () => {
                        const url = `${protocol}://${host}${port ? `:${port}` : ''}`;
                        logger.info(`Server running at ${url}`);
                        logger.info(`Server successfully bound to port ${port}`);
                    });

                    server.on('error', (error) => {
                        if (error.code === 'EADDRINUSE') {
                            logger.error(`Port ${port} conflict detected during server.listen().`);
                            logger.error('This should not happen after port check. Exiting to prevent conflicts.');
                            // Exit with code 1 to trigger PM2 backoff
                            setTimeout(() => {
                                process.exit(1);
                            }, 1000);
                        } else {
                            logger.error('Server error occurred', error);
                            // For other errors, exit with code 1
                            setTimeout(() => {
                                process.exit(1);
                            }, 1000);
                        }
                    });

                    // Handle server close gracefully
                    server.on('close', () => {
                        logger.info('Server closed gracefully');
                    });
                } catch (error) {
                    if (error.code === 'EADDRINUSE') {
                        logger.error(`Port ${port} is already in use during bind attempt.`);
                        logger.error('Exiting to prevent conflicts. PM2 will retry with backoff.');
                        process.exit(1);
                    } else {
                        logger.error('Failed to start server', error);
                        process.exit(1);
                    }
                }
            }); // End of checkPort callback
        }; // End of attemptStart function

        // Start the attempt
        attemptStart();
    }

    logger.info('=== EMS Backend Application Initialized ===');

    // Initialize scheduled jobs
    try {
        const { scheduleDailySummaryEmail } = require('./jobs/dailySummaryJob');
        scheduleDailySummaryEmail();
        logger.info('Daily summary email job initialized');
    } catch (error) {
        logger.error('Failed to initialize scheduled jobs:', error);
    }

    // Export app for Passenger (Passenger will handle server startup)
    module.exports = app;
} catch (error) {
    logger.error('Failed to initialize application', error);
    process.exit(1);
}
