import express, { Application, Request, Response, NextFunction } from 'express';
import cors from 'cors';
import helmet from 'helmet';
import compression from 'compression';
import morgan from 'morgan';
import { config } from './config/index.js';
import { logger } from './shared/utils/logger.js';
import { AppError, ApiResponse } from './shared/types/index.js';
import { setupSwagger } from './config/swagger.config.js';
import authRoutes from './modules/auth/auth.routes.js';
import mfaRoutes from './modules/auth/mfa.routes.js';
import apiKeysRoutes from './modules/auth/apiKeys.routes.js';
import usersRoutes from './modules/users/users.routes.js';
import auditRoutes from './modules/audit/audit.routes.js';
import featureFlagsRoutes from './modules/feature-flags/feature-flags.routes.js';
import { featureFlagsMiddleware } from './modules/feature-flags/middleware/feature-flags.middleware.js';
import { tenantsRoutes } from './modules/tenants/index.js';
import companiesRoutes from './modules/companies/companies.routes.js';
import coreRoutes from './modules/core/core.routes.js';
import partnersRoutes from './modules/partners/partners.routes.js';
import inventoryRoutes from './modules/inventory/inventory.routes.js';
import financialRoutes from './modules/financial/financial.routes.js';
import salesRoutes from './modules/ordenes-transporte/sales.routes.js';
import productsRoutes from './modules/gestion-flota/products.routes.js';
import projectsRoutes from './modules/viajes/projects.routes.js';
import gpsRoutes from './modules/gps/gps.routes.js';
import dispatchRoutes from './modules/dispatch/dispatch.routes.js';
import offlineRoutes from './modules/offline/offline.routes.js';
import { createWhatsAppRoutes } from './modules/whatsapp/index.js';
import { AppDataSource } from './config/typeorm.js';

const app: Application = express();

// Security middleware
app.use(helmet());
app.use(cors({
  origin: config.cors.origin,
  credentials: true,
}));

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

// Logging
const morganFormat = config.env === 'production' ? 'combined' : 'dev';
app.use(morgan(morganFormat, {
  stream: { write: (message) => logger.http(message.trim()) }
}));

// Swagger documentation
const apiPrefix = config.apiPrefix;
setupSwagger(app, apiPrefix);

// Health check
app.get('/health', (_req: Request, res: Response) => {
  res.json({ status: 'ok', timestamp: new Date().toISOString() });
});

// API routes - Core
app.use(`${apiPrefix}/auth`, authRoutes);
app.use(`${apiPrefix}/auth/mfa`, mfaRoutes);
app.use(`${apiPrefix}/auth/api-keys`, apiKeysRoutes);
app.use(`${apiPrefix}/users`, usersRoutes);
app.use(`${apiPrefix}/audit`, auditRoutes);
app.use(`${apiPrefix}/feature-flags`, featureFlagsRoutes);

app.use(featureFlagsMiddleware);
app.use(`${apiPrefix}/tenants`, tenantsRoutes);
app.use(`${apiPrefix}/companies`, companiesRoutes);
app.use(`${apiPrefix}/core`, coreRoutes);
app.use(`${apiPrefix}/partners`, partnersRoutes);
app.use(`${apiPrefix}/inventory`, inventoryRoutes);
app.use(`${apiPrefix}/financial`, financialRoutes);

// API routes - Transport
app.use(`${apiPrefix}/sales`, salesRoutes);
app.use(`${apiPrefix}/products`, productsRoutes);
app.use(`${apiPrefix}/projects`, projectsRoutes);

// API routes - GPS & Dispatch (Sprint S1+S2 - TASK-007)
app.use(`${apiPrefix}/gps`, gpsRoutes);
app.use(`${apiPrefix}/despacho`, dispatchRoutes);

// API routes - Offline Sync (Sprint S4 - TASK-007)
app.use(`${apiPrefix}/offline`, offlineRoutes);

// API routes - WhatsApp Notifications (Sprint S5 - TASK-007)
app.use(`${apiPrefix}/whatsapp`, createWhatsAppRoutes(AppDataSource));

// 404 handler
app.use((_req: Request, res: Response) => {
  const response: ApiResponse = {
    success: false,
    error: 'Endpoint no encontrado'
  };
  res.status(404).json(response);
});

// Global error handler
app.use((err: Error, _req: Request, res: Response, _next: NextFunction) => {
  logger.error('Unhandled error', {
    error: err.message,
    stack: err.stack,
    name: err.name
  });

  if (err instanceof AppError) {
    const response: ApiResponse = {
      success: false,
      error: err.message,
    };
    return res.status(err.statusCode).json(response);
  }

  // Generic error
  const response: ApiResponse = {
    success: false,
    error: config.env === 'production'
      ? 'Error interno del servidor'
      : err.message,
  };
  res.status(500).json(response);
});

export default app;
