import express from 'express';
import cors from 'cors';
import helmet from 'helmet';
import rateLimit from 'express-rate-limit';
import dotenv from 'dotenv';
import mongoose from 'mongoose';
import passport from 'passport';
import session from 'express-session';
import swaggerUi from 'swagger-ui-express';
import swaggerJsdoc from 'swagger-jsdoc';
import { connectDB } from './config/db';
import routes from './routes';
import path from 'path';
import { fileURLToPath } from 'url';
import fs from 'fs';
import { EvaluationService } from './services/evaluationService';
import { MonitoringService } from './services/monitoringService';
import { TenantUsageService } from './services/tenantUsageService';
import { EquifaxCleanupService } from './services/equifaxCleanupService';
import { DbBackupService } from './services/dbBackupService';
import ELKService from './services/elkService';
import { elkLoggingMiddleware, elkErrorMiddleware, elkPerformanceMiddleware } from './middleware/elkMiddleware';
import './config/passport'; // Initialize passport strategies

// Load environment variables
const __filename = fileURLToPath(import.meta.url); // Define __filename first
const __dirname = path.dirname(__filename); // Then __dirname
const envPath = path.resolve(__dirname, '../.env');
const devEnvPath = path.resolve(__dirname, '../_env_dev');

if (fs.existsSync(envPath)) {
  dotenv.config({ path: envPath });
  ELKService.info('Environment variables loaded from server/.env');
} else if (fs.existsSync(devEnvPath)) {
  dotenv.config({ path: devEnvPath });
  ELKService.info('Environment variables loaded from server/_env_dev');
} else {
  dotenv.config();
  ELKService.warn('No env file found; relying on process environment variables');
}

// Create Express app
const app = express();
ELKService.info('Express app created');

// If you are behind a proxy (like Nginx), set this to trust the X-Forwarded-For header.
// The value '1' means it trusts the first hop (your Nginx proxy).
// Adjust if you have more proxies.
app.set('trust proxy', 1);
ELKService.info('Trust proxy set to 1');
app.use((req, res, next) => {
  if(req.originalUrl !== '/api/health') {
    console.log(`[REQ] method: ${req.method} > ${req.originalUrl}`);
  }
  next();
});
// Enable CORS for all origins in development
app.use(cors({
  origin: true, // Allow all origins
  credentials: true,
  methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS', 'PATCH'],
  allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With', 'Accept'],
}));
ELKService.info('CORS middleware enabled with permissive settings');

// Basic security headers
app.use(helmet({
  contentSecurityPolicy: false, // CSP is disabled
  crossOriginEmbedderPolicy: false, // Keep as false unless you specifically need COEP
  crossOriginResourcePolicy: false  // Keep as false unless you specifically need CORP
}));
ELKService.info('Helmet middleware enabled');

// Session configuration for OAuth
app.use(session({
  secret: process.env.SESSION_SECRET || 'your-session-secret',
  resave: false,
  saveUninitialized: false,
  cookie: {
    secure: process.env.NODE_ENV === 'production',
    maxAge: 24 * 60 * 60 * 1000 // 24 hours
  }
}));
ELKService.info('Session middleware enabled');

// Initialize Passport
app.use(passport.initialize());
app.use(passport.session());
ELKService.info('Passport middleware enabled');

// ELK logging middleware
app.use(elkLoggingMiddleware);
app.use(elkPerformanceMiddleware);
ELKService.info('ELK logging and performance middleware enabled');

// Body parsers
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
ELKService.info('JSON and URL-encoded body parsers enabled');

// Rate limiting
/*
const limiter = rateLimit({
  windowMs: Number(process.env.RATE_LIMIT_WINDOW_MS) || 900000, // 15 minutes
  max: Number(process.env.RATE_LIMIT_MAX_REQUESTS) || 10000, // Limit each IP to 100 requests per windowMs
  message: 'Too many requests from this IP, please try again later.'
});
app.use(limiter);
*/
ELKService.info('Rate limiting middleware enabled');

// Swagger definition
const swaggerOptions = {
  definition: {
    openapi: '3.0.0',
    info: {
      title: 'DuXiter API Documentation',
      version: '1.0.0',
      description: 'API documentation for DuXiter application',
    },
    servers: [
      {
        url: `http://localhost:${process.env.PORT || 3010}/api`,
        description: 'Local Development Server',
      },
      {
        url: '/api',
        description: 'Production Server',
      },
    ],
    components: {
      securitySchemes: {
        bearerAuth: {
          type: 'http',
          scheme: 'bearer',
          bearerFormat: 'JWT',
        },
      },
    },
  },
  apis: [
    path.join(__dirname, './routes/*.ts'),
    path.join(__dirname, './routes/*.js'),
    path.join(__dirname, './models/*.ts'),
    path.join(__dirname, './models/*.js'),
  ],
};

// Generate Swagger specification
const swaggerSpec = swaggerJsdoc(swaggerOptions);
ELKService.info('Swagger specification generated');

// Serve static files for PDF reports
app.use('/static', express.static(path.join(__dirname, '../static')));
ELKService.info('Static files middleware enabled for /static');

// Serve frontend build files
app.use(express.static(path.join(__dirname, '../../dist')));
ELKService.info('Frontend static files middleware enabled for /dist');

// Routes
app.use('/api', routes);
ELKService.info('API routes mounted under /api');

// Serve Swagger documentation
app.use('/api/docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec));
ELKService.info('Swagger UI served at /api/docs');

// Save Swagger JSON for external use
app.get('/api/docs.json', (req, res) => {
  res.setHeader('Content-Type', 'application/json');
  res.send(swaggerSpec);
});
ELKService.info('Swagger JSON available at /api/docs.json');

// Health check endpoint
app.get('/api/health', (req, res) => {
  res.json({ status: 'ok', message: 'Server is running' });
});
ELKService.info('Health check endpoint available at /api/health');

//catch all wrong api endpoints and print them
app.use('/api', (req, res) => {
  console.warn(`[API 404] method: ${req.method} > ${req.originalUrl}`);
  res.status(404).json({
    error: 'API endpoint not found',
    path: req.originalUrl
  });
});

// Catch-all handler for React Router (must be after API routes)
app.get('*', (req, res) => {
  res.sendFile(path.join(__dirname, '../../dist/index.html'));
});
ELKService.info('Catch-all route registered for React Router');

// CORS preflight
app.options('*', cors());
ELKService.info('CORS preflight handling enabled for all routes');

// ELK Error handling middleware
app.use(elkErrorMiddleware);

// Global error handling middleware
app.use((err: Error, req: express.Request, res: express.Response, next: express.NextFunction) => {
  console.error('=== GLOBAL ERROR HANDLER ===');
  console.error('Error:', err);
  console.error('Error message:', err.message);
  console.error('Error stack:', err.stack);
  console.error('Request URL:', req.url);
  console.error('Request method:', req.method);
  console.error('Request headers:', req.headers);
  console.error('Request body:', req.body);
  console.error('================================');

  ELKService.error('Unhandled error in global middleware', err);
  res.status(500).json({
    status: 'error',
    message: 'Something went wrong!',
    error: process.env.NODE_ENV === 'development' ? err.message : undefined,
    stack: process.env.NODE_ENV === 'development' ? err.stack : undefined
  });
});


ELKService.info('Global error handling middleware registered');

// Start server
const startServer = async () => {
  ELKService.info('Starting server...');
  try {
    // Test ELK connection
    const elkTest = await ELKService.testConnection();
    if (elkTest.success) {
      ELKService.info('ELK connection test successful');
    } else {
      ELKService.warn('ELK connection test failed', { message: elkTest.message });
    }

    await connectDB();
    ELKService.info('MongoDB connected successfully');

    // Initialize RabbitMQ and evaluation service (temporarily disabled for testing)
    try {
      await EvaluationService.initialize();
      ELKService.info('RabbitMQ service initialized successfully');
    } catch (error) {
      ELKService.warn('RabbitMQ service initialization failed, continuing without it', error as Error);
    }

    // Initialize monitoring service
    await MonitoringService.getInstance().initialize();
    ELKService.info('Monitoring service initialized successfully');

    // Initialize tenant usage service
    await TenantUsageService.getInstance().initialize();
    ELKService.info('Tenant usage service initialized successfully');

    // Initialize Equifax cleanup service (every 30 minutes)
    await EquifaxCleanupService.getInstance().initialize();
    ELKService.info('Equifax cleanup service initialized successfully');

    // Initialize DB backup service (daily)
    await DbBackupService.getInstance().initialize();
    ELKService.info('DB backup service initialized successfully');

    
    const port = process.env.PORT || 3001;
    app.listen(port, () => {
      ELKService.info(`Server is running on port ${port}`);
      ELKService.info(`API Documentation available at http://localhost:${port}/api/docs`);
      ELKService.logBusinessEvent('server_started', { port, environment: process.env.NODE_ENV || 'development' });
    });
  } catch (error) {
    ELKService.error('Failed to start server', error as Error);
    process.exit(1);
  }
};

// Only start server outside of test environment
if (process.env.NODE_ENV !== 'test') {
  startServer();
}

// Export app for testing
export { app };
