require('dotenv').config();
const express = require('express');
const cors = require('cors');
const helmet = require('helmet');
const mongoSanitize = require('express-mongo-sanitize');
const hpp = require('hpp');
const compression = require('compression');
const swaggerUi = require('swagger-ui-express');
const swaggerJsdoc = require('swagger-jsdoc');
const path = require('path');

// Importar logger
const logger = require('./utils/logger');

// Importar middlewares de seguridad
const { 
  sanitizeInput, 
  preventSQLInjection, 
  preventNoSQLInjection,
  preventPathTraversal,
  validateContentType,
  preventHPP
} = require('./middlewares/security');

const { 
  ddosProtection, 
  detectAttackPatterns, 
  requestSizeLimit,
  slowlorisProtection 
} = require('./middlewares/ddosProtection');

const { 
  generalLimiter,
  authLimiter,
  createLimiter,
  searchLimiter 
} = require('./middlewares/rateLimiter');

const { requestLogger } = require('./middlewares/requestLogger');

// Importar middlewares existentes
const { errorHandler } = require('./middlewares/errorHandler');
const { notFound } = require('./middlewares/notFound');

// Importar rutas
const routes = require('./routes/index.routes');

// Importar base de datos
const { sequelize } = require('./models');

// Crear aplicación Express
const app = express();

// ============================================
// TRUST PROXY (importante para obtener IP real detrás de proxy/load balancer)
// ============================================
app.set('trust proxy', 1);

// ============================================
// SEGURIDAD - PRIMERA CAPA
// ============================================

// Protección DDoS básica
app.use(ddosProtection);

// Detectar patrones de ataque
app.use(detectAttackPatterns);

// Protección contra Slowloris
app.use(slowlorisProtection);

// Limitar tamaño de requests
app.use(requestSizeLimit(10 * 1024 * 1024)); // 10MB

// Helmet - Headers de seguridad
// 1. Configurar CSP para permitir recursos externos
app.use(helmet({
  contentSecurityPolicy: {
    directives: {
      defaultSrc: ["'self'"],
      styleSrc: ["'self'", "'unsafe-inline'", "https://fonts.googleapis.com", "https://cdnjs.cloudflare.com"],
      fontSrc: ["'self'", "https://fonts.gstatic.com", "https://cdnjs.cloudflare.com"],
      scriptSrc: ["'self'", "'unsafe-inline'", "https://cdnjs.cloudflare.com"],
      imgSrc: ["'self'", "data:", "https:", "http:"],
      connectSrc: ["'self'"]
    }
  }
}));

// 2. Middleware para MIME types correctos
app.use((req, res, next) => {
  if (req.path.endsWith('.css')) {
    res.type('text/css');
  } else if (req.path.endsWith('.js')) {
    res.type('application/javascript');
  }
  next();
});
// 3. Servir archivos estáticos
app.use(express.static(path.join(__dirname, '../public'), {
  setHeaders: (res, filepath) => {
    if (filepath.endsWith('.css')) {
      res.setHeader('Content-Type', 'text/css');
    } else if (filepath.endsWith('.js')) {
      res.setHeader('Content-Type', 'application/javascript');
    }
  }
}));

// ============================================
// CORS
// ============================================
// las rutas definidas del cors:
const lasrutas = [
  'http://localhost:4200',
  'http://127.0.0.1:4200',
  'http://localhost:4201',
  'http://127.0.0.1:4201',
  'https://grupohpsalud.jxdesignsolution.com',
  'http://grupohpsalud.jxdesignsolution.com/'
]
const corsOptions = {
  origin: (origin, callback) => {
    // Lista dura para desarrollo + lo que venga en .env para producción
    const devOrigins = lasrutas;
    const envOrigins = process.env.CORS_ORIGIN 
      ? process.env.CORS_ORIGIN.split(',').map(o => o.trim()) 
      : [];

    const allowedOrigins = process.env.NODE_ENV === 'production' 
      ? envOrigins 
      : [...devOrigins, ...envOrigins, '*']; // * solo en dev

    // Permitir siempre en desarrollo o si no hay origin (Postman, mobile, etc)
    if (process.env.NODE_ENV !== 'production' || !origin || allowedOrigins.includes('*') || allowedOrigins.includes(origin)) {
      return callback(null, true);
    }

    logger.security('CORS: Origen no permitido', { origin, allowedOrigins });
    return callback(new Error('No permitido por CORS'));
  },
  credentials: true,
  methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
  allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With', 'Accept'],
  exposedHeaders: ['X-Total-Count', 'X-Total-Pages'],
  maxAge: 86400,
};

app.use(cors(corsOptions));

// ============================================
// BODY PARSER CON LÍMITES
// ============================================
app.use(express.json({ 
  limit: '10mb',
  verify: (req, res, buf, encoding) => {
    // Verificar que el JSON sea válido
    try {
      JSON.parse(buf);
    } catch (e) {
      logger.security('JSON inválido recibido', {
        ip: req.ip,
        error: e.message
      });
      throw new Error('JSON inválido');
    }
  }
}));

app.use(express.urlencoded({ 
  extended: true, 
  limit: '10mb',
  parameterLimit: 1000 // Limitar número de parámetros
}));

// ============================================
// SEGURIDAD - SEGUNDA CAPA
// ============================================

// Sanitización de MongoDB (prevenir NoSQL injection)
app.use(mongoSanitize({
  replaceWith: '_',
  onSanitize: ({ req, key }) => {
    logger.security('NoSQL Injection attempt detected', {
      ip: req.ip,
      key,
      path: req.path
    });
  },
}));

// Prevenir HTTP Parameter Pollution
app.use(hpp({
  whitelist: ['filter', 'sort', 'page', 'limit', 'search'] // Parámetros permitidos duplicados
}));

// Validar Content-Type
app.use(validateContentType(['application/json', 'application/x-www-form-urlencoded', 'multipart/form-data']));

// Sanitizar inputs
app.use(sanitizeInput);

// Prevenir SQL Injection
app.use(preventSQLInjection);

// Prevenir NoSQL Injection (capa adicional)
app.use(preventNoSQLInjection);

// Prevenir Path Traversal
app.use(preventPathTraversal);

// Prevenir HPP (capa adicional)
app.use(preventHPP);

// ============================================
// COMPRESIÓN
// ============================================
app.use(compression({
  filter: (req, res) => {
    if (req.headers['x-no-compression']) {
      return false;
    }
    return compression.filter(req, res);
  },
  level: 6
}));

// ============================================
// LOGGING
// ============================================

// Logger de requests
app.use(requestLogger);

// ============================================
// RATE LIMITING
// ============================================

// Rate limiter general (aplicar a todas las rutas excepto health)
app.use((req, res, next) => {
  if (req.path === '/health') {
    return next();
  }
  generalLimiter(req, res, next);
});

// ============================================
// CONFIGURACIÓN DE SWAGGER
// ============================================

const swaggerOptions = {
  definition: {
    openapi: '3.0.0',
    info: {
      title: 'API Sistema Médico - Segura',
      version: '1.0.0',
      description: 'API REST segura para sistema de gestión médica con protección contra DDoS, SQL Injection, XSS y más',
      contact: {
        name: 'Soporte API',
        email: 'soporte@sistemamedico.com'
      },
      license: {
        name: 'MIT',
        url: 'https://opensource.org/licenses/MIT'
      }
    },
    servers: [
      {
        url: process.env.API_URL || 'http://localhost:3000',
        description: 'Servidor de desarrollo'
      },
      {
        url: process.env.API_URL_PROD || 'https://api.sistemamedico.com',
        description: 'Servidor de producción'
      }
    ],
    components: {
      securitySchemes: {
        bearerAuth: {
          type: 'http',
          scheme: 'bearer',
          bearerFormat: 'JWT',
          description: 'Ingrese el token JWT obtenido del login'
        }
      },
      schemas: {
        Error: {
          type: 'object',
          properties: {
            success: { type: 'boolean', example: false },
            message: { type: 'string', example: 'Error message' },
            error: { type: 'string', example: 'Error details' }
          }
        },
        Success: {
          type: 'object',
          properties: {
            success: { type: 'boolean', example: true },
            message: { type: 'string', example: 'Operation successful' },
            data: { type: 'object' }
          }
        },
        Pagination: {
          type: 'object',
          properties: {
            success: { type: 'boolean', example: true },
            message: { type: 'string', example: 'Data retrieved successfully' },
            totalItems: { type: 'integer', example: 100 },
            items: { type: 'array', items: { type: 'object' } },
            totalPages: { type: 'integer', example: 10 },
            currentPage: { type: 'integer', example: 1 },
            itemsPerPage: { type: 'integer', example: 10 }
          }
        }
      }
    },
    security: [{ bearerAuth: [] }],
    tags: [
      { name: 'Auth', description: 'Autenticación y autorización' },
      { name: 'Admin', description: 'Gestión de administradores' },
      { name: 'Doctor', description: 'Gestión de doctores' },
      { name: 'Cliente', description: 'Gestión de clientes/pacientes' },
      { name: 'Cita', description: 'Gestión de citas médicas' },
      { name: 'Security', description: 'Endpoints de seguridad' }
    ]
  },
  apis: ['./src/routes/*.js', './src/controllers/*.js']
};

const swaggerSpec = swaggerJsdoc(swaggerOptions);

app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec, {
  explorer: true,
  customCss: '.swagger-ui .topbar { display: none }',
  customSiteTitle: 'API Sistema Médico - Documentación',
  swaggerOptions: {
    persistAuthorization: true,
    displayRequestDuration: true,
    filter: true,
    syntaxHighlight: { activate: true, theme: 'monokai' }
  }
}));

app.get('/api-docs.json', (req, res) => {
  res.setHeader('Content-Type', 'application/json');
  res.send(swaggerSpec);
});

// ============================================
// RUTAS
// ============================================

// Ruta de bienvenida
app.get('/', (req, res) => {
  res.sendFile(path.join(__dirname, '../public/index.html'));
});

// Health check
app.get('/health', async (req, res) => {
  try {
    await sequelize.authenticate();
    res.json({
      success: true,
      message: 'API funcionando correctamente',
      database: 'Conectada',
      timestamp: new Date().toISOString(),
      uptime: process.uptime(),
      environment: process.env.NODE_ENV || 'development',
      memory: {
        used: Math.round(process.memoryUsage().heapUsed / 1024 / 1024) + ' MB',
        total: Math.round(process.memoryUsage().heapTotal / 1024 / 1024) + ' MB'
      }
    });
  } catch (error) {
    logger.error('Health check failed', { error: error.message });
    res.status(503).json({
      success: false,
      message: 'Error en el servicio',
      database: 'Desconectada',
      error: error.message
    });
  }
});

// Endpoint de estadísticas de seguridad (solo para admins)
const { verifyToken } = require('./middlewares/auth');
const { getStats } = require('./middlewares/ddosProtection');

app.get('/security/stats', verifyToken, (req, res) => {
  // Verificar que sea admin
  if (req.user.type !== 'admin') {
    return res.status(403).json({
      success: false,
      message: 'Acceso denegado'
    });
  }

  const stats = getStats();
  res.json({
    success: true,
    data: stats
  });
});

// Rutas de la API con rate limiters específicos
app.use('/api/auth', authLimiter, routes);
app.use('/api/data', routes);
app.use('/api', routes);

// ============================================
// MANEJO DE ERRORES
// ============================================

// Ruta no encontrada
app.use(notFound);

// Manejador de errores global
app.use(errorHandler);

// ============================================
// INICIALIZACIÓN DEL SERVIDOR
// ============================================

const PORT = process.env.PORT || 3000;
const NODE_ENV = process.env.NODE_ENV || 'development';

const startServer = async () => {
  try {
    // Verificar conexión a la base de datos
    await sequelize.authenticate();
    logger.info('✅ Conexión a la base de datos establecida correctamente');
    // Sincronizar modelos (solo en desarrollo)
    if (NODE_ENV === 'development') {
      await sequelize.sync({ alter: false });
      logger.info('✅ Modelos sincronizados con la base de datos');
    }
    // Iniciar servidor
    const server = app.listen(PORT, () => {
      logger.info('='.repeat(60));
      logger.info('🚀 SERVIDOR INICIADO CORRECTAMENTE');
      logger.info('='.repeat(60));
      logger.info(`📍 Entorno: ${NODE_ENV}`);
      logger.info(`🌐 URL: http://localhost:${PORT}`);
      logger.info(`📚 Documentación: http://localhost:${PORT}/api-docs`);
      logger.info(`💚 Health Check: http://localhost:${PORT}/health`);
      logger.info(`🔒 Seguridad: DDoS Protection, Rate Limiting, SQL Injection Prevention`);
      logger.info('='.repeat(60));
    });
    // Configurar timeouts
    server.timeout = 30000; // 30 segundos
    server.keepAliveTimeout = 65000; // 65 segundos

  } catch (error) {
    logger.error('❌ Error al iniciar el servidor:', error);
    process.exit(1);
  }
};

// Manejo de errores no capturados
process.on('unhandledRejection', (reason, promise) => {
  logger.error('❌ Unhandled Rejection', { reason, promise });
  process.exit(1);
});

process.on('uncaughtException', (error) => {
  logger.error('❌ Uncaught Exception', { error: error.message, stack: error.stack });
  process.exit(1);
});

// Manejo de señales de terminación
process.on('SIGTERM', async () => {
  logger.info('⚠️  SIGTERM recibido. Cerrando servidor...');
  await sequelize.close();
  process.exit(0);
});

process.on('SIGINT', async () => {
  logger.info('⚠️  SIGINT recibido. Cerrando servidor...');
  await sequelize.close();
  process.exit(0);
});

// Iniciar el servidor
startServer();

module.exports = app;