import 'dotenv/config';
import express, { Request, Response, NextFunction } from 'express';
import cors from 'cors';
import helmet from 'helmet';
import compression from 'compression';
import rateLimit from 'express-rate-limit';
import path from 'path';
import { fileURLToPath } from 'url';
import fs from 'fs';
import { createServer } from 'http';
import { initSocket } from './common/utils/socket.js';

// Import database
import db from './database/models/index.js';

// Import routes (Modular Monolith Structure)
// Import routes (Modular Monolith Structure)
import constitutionalRoutes from './modules/self-service/constitutional.routes.js';
import authRoutes from './modules/auth/auth.routes.js';
import onboardingRoutes from './modules/onboarding/onboarding.routes.js';
import selfServiceRoutes from './modules/self-service/self-service.routes.js';
import masterRoutes from './modules/master/master.routes.js';
import settlementRoutes from './modules/settlement/settlement.routes.js';
import collaborationRoutes from './modules/collaboration/collaboration.routes.js';
import resignationRoutes from './modules/self-service/resignation.routes.js';
import relocationRoutes from './modules/self-service/relocation.routes.js';
import outletRoutes from './modules/master/outlet.routes.js';
// New Modules
import adminRoutes from './modules/admin/admin.routes.js';
import opportunityRoutes from './modules/opportunity/opportunity.routes.js';
import assessmentRoutes from './modules/assessment/assessment.routes.js';
import fddRoutes from './modules/fdd/fdd.routes.js';
import loiRoutes from './modules/loi/loi.routes.js';
import loaRoutes from './modules/loa/loa.routes.js';
import eorRoutes from './modules/eor/eor.routes.js';
import dealerRoutes from './modules/dealer/dealer.routes.js';
import slaRoutes from './modules/sla/sla.routes.js';
import communicationRoutes from './modules/communication/communication.routes.js';
import auditRoutes from './modules/audit/audit.routes.js';
import questionnaireRoutes from './modules/onboarding/questionnaire.routes.js';
import prospectiveLoginRoutes from './modules/prospective-login/prospective-login.routes.js';
import terminationRoutes from './modules/termination/termination.routes.js';

// Import common middleware & utils
import errorHandler from './common/middleware/errorHandler.js';
import logger from './common/utils/logger.js';
import { getFrontendBaseUrl } from './common/utils/frontendUrl.js';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const frontendBuildPath = path.resolve(process.cwd(), 'build');
const frontendIndexPath = path.join(frontendBuildPath, 'index.html');
const hasFrontendBuild = fs.existsSync(frontendIndexPath);

// Initialize Express app
const app = express();
const httpServer = createServer(app);

// Initialize Socket.io
initSocket(httpServer);

// Security middleware
app.use(helmet({
    contentSecurityPolicy: {
        directives: {
            ...helmet.contentSecurityPolicy.getDefaultDirectives(),
            "frame-ancestors": ["'self'", getFrontendBaseUrl()],
        },
    },
    crossOriginEmbedderPolicy: false,
    crossOriginResourcePolicy: { policy: "cross-origin" }
}));
const allowedOrigins = new Set<string>([
    getFrontendBaseUrl(),
    'http://localhost:5173'
]);
app.use(cors({
    origin: (origin, callback) => {
        // Allow same-origin/browser requests without explicit Origin and known frontend origins.
        if (!origin || allowedOrigins.has(origin)) return callback(null, true);
        return callback(null, false);
    },
    credentials: true
}));

// Rate limiting
const limiter = rateLimit({
    windowMs: parseInt(process.env.RATE_LIMIT_WINDOW_MS || '900000'), // 15 minutes
    max: process.env.NODE_ENV === 'development' ? 100000 : parseInt(process.env.RATE_LIMIT_MAX_REQUESTS || '1000'),
    message: 'Too many requests from this IP, please try again later.'
});
app.use('/api/', limiter);

// Body parsing middleware
app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ extended: true, limit: '10mb' }));

// Compression
app.use(compression());

// Static files (uploaded documents)
app.use('/uploads', express.static(path.join(__dirname, '..', 'uploads')));

// Request logging
app.use((req: Request, res: Response, next: NextFunction) => {
    logger.info(`${req.method} ${req.path}`, {
        ip: req.ip,
        userAgent: req.get('user-agent')
    });
    next();
});

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

// API Routes (Modular)
app.use('/api/auth', authRoutes);
app.use('/api/onboarding', onboardingRoutes);
app.use('/api/master', masterRoutes);
app.use('/api/settlement', settlementRoutes);
app.use('/api/collaboration', collaborationRoutes);
app.use('/api/admin', adminRoutes);
app.use('/api/opportunity', opportunityRoutes);
app.use('/api/assessment', assessmentRoutes);
app.use('/api/fdd', fddRoutes);
app.use('/api/loi', loiRoutes);
app.use('/api/loa', loaRoutes);
app.use('/api/eor', eorRoutes);
app.use('/api/dealer', dealerRoutes);
app.use('/api/sla', slaRoutes);
app.use('/api/communication', communicationRoutes);
app.use('/api/audit', auditRoutes);
app.use('/api/questionnaire', questionnaireRoutes);
app.use('/api/prospective-login', prospectiveLoginRoutes);
app.use('/api/termination', terminationRoutes);

// Self-Service Modules (Explicitly mounted for consolidation)
app.use('/api/self-service/resignations', resignationRoutes);
app.use('/api/self-service/relocation', relocationRoutes);
app.use('/api/self-service/constitutional', constitutionalRoutes);
app.use('/api/self-service', selfServiceRoutes);

// Backward Compatibility & Frontend Mapping Aliases
app.use('/api/applications', onboardingRoutes);
app.use('/api/constitutional-change', constitutionalRoutes);
app.use('/api/resignations', resignationRoutes);
app.use('/api/resignation', resignationRoutes);
app.use('/api/relocations', relocationRoutes);
app.use('/api/relocation', relocationRoutes);
app.use('/api/outlets', outletRoutes);
app.use('/api/dealers', dealerRoutes);
app.use('/api/finance', settlementRoutes);
app.use('/api/worknotes', collaborationRoutes);

// Serve React build from backend in single-domain deployments.
if (hasFrontendBuild) {
    app.use(express.static(frontendBuildPath));
}



// 404 handler
app.use((req: Request, res: Response) => {
    if (req.path.startsWith('/api')) {
        return res.status(404).json({
            success: false,
            message: 'Route not found'
        });
    }

    if (hasFrontendBuild) {
        return res.sendFile(frontendIndexPath);
    }

    return res.status(404).json({
        success: false,
        message: 'Route not found'
    });
});

// Global error handler
app.use(errorHandler as any);

// Database connection and server start
const PORT = process.env.PORT || 5000;

const startServer = async () => {
    try {
        // Test database connection
        await db.sequelize.authenticate();
        logger.info('Database connection established successfully');

        const { initializeSmtpConfig, isSmtpEnabled } = await import('./services/smtpConfig.service.js');
        const smtpConfig = await initializeSmtpConfig();
        const { resetEmailTransporter } = await import('./common/utils/email.service.js');
        resetEmailTransporter();
        logger.info(
            `SMTP: ${isSmtpEnabled() ? 'enabled' : 'disabled'} (source: ${smtpConfig.source}, host: ${smtpConfig.host})`
        );

        // Sync database (in development only)
        if (process.env.NODE_ENV === 'development') {
            // Temporarily disabling sync to resolve constraint errors during E2E testing
            // await db.sequelize.sync();
            logger.info('Database synchronization skipped (Manual Schema Management)');
        }

        // Start BullMQ Workers
        if (process.env.ENABLE_REDIS === 'true') {
            const { notificationWorker } = await import('./common/queues/notification.worker.js');
            const { slaWorker } = await import('./common/queues/sla.worker.js');
            const { offboardingLwdWorker } = await import('./common/queues/offboarding-lwd.worker.js');
            const { questionnaireReminderWorker } = await import('./common/queues/questionnaire-reminder.worker.js');
            const { scheduleSLACheck } = await import('./common/queues/sla.queue.js');
            const { scheduleOffboardingLwdReminders } = await import('./common/queues/offboarding-lwd.queue.js');
            const { scheduleQuestionnaireReminders } = await import('./common/queues/questionnaire-reminder.queue.js');
            
            await scheduleSLACheck(); // Register repeatable job
            await scheduleOffboardingLwdReminders();
            await scheduleQuestionnaireReminders();
            void notificationWorker;
            void slaWorker;
            void offboardingLwdWorker;
            void questionnaireReminderWorker;
            
            logger.info('BullMQ Workers initialized and repeatable jobs scheduled');
        } else {
            logger.info('⚙️  BullMQ (Redis) is disabled. Background jobs will not run.');
        }

        // Start server
        httpServer.listen(PORT, () => {
            logger.info(`🚀 Server running on port ${PORT}`);
            logger.info(`📍 Environment: ${process.env.NODE_ENV}`);
            logger.info(`🔗 API Base URL: http://localhost:${PORT}/api`);
            logger.info(`🔌 Socket.io initialized`);
            logger.info(`⚙️  BullMQ: ${process.env.ENABLE_REDIS === 'true' ? 'Active (Notifications/SLA)' : 'Disabled'}`);
        });
    } catch (error) {
        logger.error('Unable to start server:', error);
        process.exit(1);
    }
};

// Handle unhandled promise rejections
process.on('unhandledRejection', (err) => {
    logger.error('Unhandled Promise Rejection:', err);
    process.exit(1);
});

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

// Graceful shutdown
process.on('SIGTERM', async () => {
    logger.info('SIGTERM signal received: closing HTTP server');
    await db.sequelize.close();
    process.exit(0);
});

startServer();

export default app;
