const express = require('express');
const helmet = require('helmet');
const cors = require('cors');
const rateLimit = require('express-rate-limit');
const compression = require('compression');
const swaggerUi = require('swagger-ui-express');
const swaggerDocument = require('./docs/swagger.json');
const { errorHandler } = require('./middleware/errorHandler');
const { requestLogger } = require('./middleware/requestLogger');
const { authenticateToken } = require('./middleware/auth');
const { validateEnv } = require('./utils/validateEnv');
const { rateLimiterRedis } = require('./middleware/rateLimiter');
const authRoutes = require('./routes/authRoutes');
const logger = require('./utils/logger');
const { connectDB } = require('./config/database');
const { connectRedis } = require('./config/redis');

validateEnv();

const app = express();

app.use(helmet());
app.use(compression());
app.use(cors({
  origin: process.env.ALLOWED_ORIGINS?.split(',') || '*',
  methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
  allowedHeaders: ['Content-Type', 'Authorization'],
  credentials: true,
  maxAge: 86400
}));
app.use(express.json({ limit: '10kb' }));

app.use(rateLimiterRedis);
app.use(requestLogger);

app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument, { explorer: true }));
app.use('/api/auth', authRoutes);
app.use('/api/protected', authenticateToken, protectedRoutes);

app.use(errorHandler);

const initializeServer = async () => {
  try {
    await connectDB();
    await connectRedis();
    
    const PORT = process.env.PORT || 3000;
    const server = app.listen(PORT, () => 
      logger.info(`Server running on port ${PORT} in ${process.env.NODE_ENV} mode`)
    );

    const gracefulShutdown = async (signal) => {
      logger.info(`${signal} received. Starting graceful shutdown...`);
      
      server.close(async () => {
        try {
          await Promise.all([
            sequelize.close(),
            redisClient.quit()
          ]);
          logger.info('All connections closed successfully');
          process.exit(0);
        } catch (error) {
          logger.error('Error during shutdown:', error);
          process.exit(1);
        }
      });

      setTimeout(() => {
        logger.error('Could not complete graceful shutdown, forcefully exiting...');
        process.exit(1);
      }, 10000);
    };

    process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));
    process.on('SIGINT', () => gracefulShutdown('SIGINT'));
    process.on('unhandledRejection', (err) => {
      logger.error('Unhandled Rejection:', err);
      gracefulShutdown('UNHANDLED_REJECTION');
    });
    process.on('uncaughtException', (err) => {
      logger.error('Uncaught Exception:', err);
      gracefulShutdown('UNCAUGHT_EXCEPTION');
    });

  } catch (error) {
    logger.error('Failed to initialize server:', error);
    process.exit(1);
  }
};

initializeServer();

module.exports = app;