/**
 * PermisoTrabajoController - Controller de permisos de trabajo HSE
 *
 * Endpoints REST para gestión de permisos de trabajo de alto riesgo.
 *
 * @module HSE
 */

import { Router, Request, Response, NextFunction } from 'express';
import { DataSource } from 'typeorm';
import {
  PermisoTrabajoService,
  CreatePermisoDto,
  PermisoFilters,
} from '../services/permiso-trabajo.service';
import { AuthMiddleware } from '../../auth/middleware/auth.middleware';
import { AuthService } from '../../auth/services/auth.service';
import { TipoPermisoTrabajo } from '../entities/tipo-permiso-trabajo.entity';
import { PermisoTrabajo, EstadoPermiso } from '../entities/permiso-trabajo.entity';
import { PermisoPersonal } from '../entities/permiso-personal.entity';
import { PermisoAutorizacion } from '../entities/permiso-autorizacion.entity';
import { PermisoChecklist } from '../entities/permiso-checklist.entity';
import { PermisoMonitoreo } from '../entities/permiso-monitoreo.entity';
import { PermisoEvento } from '../entities/permiso-evento.entity';
import { PermisoDocumento } from '../entities/permiso-documento.entity';
import { User } from '../../core/entities/user.entity';
import { Tenant } from '../../core/entities/tenant.entity';
import { RefreshToken } from '../../auth/entities/refresh-token.entity';

/**
 * Service context for multi-tenant operations
 */
interface ServiceContext {
  tenantId: string;
  userId?: string;
}

/**
 * Crear router de permisos de trabajo
 */
export function createPermisoTrabajoController(dataSource: DataSource): Router {
  const router = Router();

  // Repositorios
  const tipoPermisoRepository = dataSource.getRepository(TipoPermisoTrabajo);
  const permisoRepository = dataSource.getRepository(PermisoTrabajo);
  const personalRepository = dataSource.getRepository(PermisoPersonal);
  const autorizacionRepository = dataSource.getRepository(PermisoAutorizacion);
  const checklistRepository = dataSource.getRepository(PermisoChecklist);
  const monitoreoRepository = dataSource.getRepository(PermisoMonitoreo);
  const eventoRepository = dataSource.getRepository(PermisoEvento);
  const documentoRepository = dataSource.getRepository(PermisoDocumento);
  const userRepository = dataSource.getRepository(User);
  const tenantRepository = dataSource.getRepository(Tenant);
  const refreshTokenRepository = dataSource.getRepository(RefreshToken);

  // Servicios
  const permisoService = new PermisoTrabajoService(
    tipoPermisoRepository,
    permisoRepository,
    personalRepository,
    autorizacionRepository,
    checklistRepository,
    monitoreoRepository,
    eventoRepository,
    documentoRepository
  );
  const authService = new AuthService(userRepository, tenantRepository, refreshTokenRepository as any);
  const authMiddleware = new AuthMiddleware(authService, dataSource);

  // Helper para crear contexto de servicio
  const getContext = (req: Request): ServiceContext => {
    if (!req.tenantId) {
      throw new Error('Tenant ID is required');
    }
    return {
      tenantId: req.tenantId,
      userId: req.user?.sub,
    };
  };

  /**
   * GET /permisos-trabajo/tipos
   * Listar tipos de permisos de trabajo
   */
  router.get('/tipos', authMiddleware.authenticate, async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const tipos = await permisoService.findTiposPermiso(getContext(req));
      res.status(200).json({ success: true, data: tipos });
    } catch (error) {
      next(error);
    }
  });

  /**
   * GET /permisos-trabajo
   * Listar permisos de trabajo con filtros
   */
  router.get('/', authMiddleware.authenticate, async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const tenantId = req.tenantId;
      if (!tenantId) {
        res.status(400).json({ error: 'Bad Request', message: 'Tenant ID required' });
        return;
      }

      const page = parseInt(req.query.page as string) || 1;
      const limit = Math.min(parseInt(req.query.limit as string) || 20, 100);

      const filters: PermisoFilters = {
        fraccionamientoId: req.query.fraccionamientoId as string,
        tipoPermisoId: req.query.tipoPermisoId as string,
        estado: req.query.estado as EstadoPermiso,
        solicitanteId: req.query.solicitanteId as string,
        vigentes: req.query.vigentes === 'true',
        dateFrom: req.query.dateFrom ? new Date(req.query.dateFrom as string) : undefined,
        dateTo: req.query.dateTo ? new Date(req.query.dateTo as string) : undefined,
      };

      const result = await permisoService.findPermisos(getContext(req), filters, page, limit);

      res.status(200).json({
        success: true,
        data: result.data,
        pagination: {
          total: result.total,
          page: result.page,
          limit: result.limit,
          totalPages: result.totalPages,
        },
      });
    } catch (error) {
      next(error);
    }
  });

  /**
   * GET /permisos-trabajo/stats
   * Obtener estadísticas de permisos
   */
  router.get('/stats', authMiddleware.authenticate, async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const tenantId = req.tenantId;
      if (!tenantId) {
        res.status(400).json({ error: 'Bad Request', message: 'Tenant ID required' });
        return;
      }

      const fraccionamientoId = req.query.fraccionamientoId as string;
      const stats = await permisoService.getStats(getContext(req), fraccionamientoId);
      res.status(200).json({ success: true, data: stats });
    } catch (error) {
      next(error);
    }
  });

  /**
   * GET /permisos-trabajo/:id
   * Obtener permiso con detalles
   */
  router.get('/:id', authMiddleware.authenticate, async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const tenantId = req.tenantId;
      if (!tenantId) {
        res.status(400).json({ error: 'Bad Request', message: 'Tenant ID required' });
        return;
      }

      const permiso = await permisoService.findPermisoWithDetails(getContext(req), req.params.id);
      if (!permiso) {
        res.status(404).json({ error: 'Not Found', message: 'Work permit not found' });
        return;
      }

      res.status(200).json({ success: true, data: permiso });
    } catch (error) {
      next(error);
    }
  });

  /**
   * POST /permisos-trabajo
   * Crear permiso de trabajo
   */
  router.post('/', authMiddleware.authenticate, authMiddleware.authorize('admin', 'engineer', 'resident'), async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const tenantId = req.tenantId;
      if (!tenantId) {
        res.status(400).json({ error: 'Bad Request', message: 'Tenant ID required' });
        return;
      }

      const dto: CreatePermisoDto = req.body;

      if (!dto.fraccionamientoId || !dto.tipoPermisoId || !dto.descripcionTrabajo || !dto.ubicacion || !dto.fechaInicioProgramada || !dto.fechaFinProgramada) {
        res.status(400).json({
          error: 'Bad Request',
          message: 'fraccionamientoId, tipoPermisoId, descripcionTrabajo, ubicacion, fechaInicioProgramada and fechaFinProgramada are required',
        });
        return;
      }

      dto.fechaInicioProgramada = new Date(dto.fechaInicioProgramada);
      dto.fechaFinProgramada = new Date(dto.fechaFinProgramada);
      const permiso = await permisoService.createPermiso(getContext(req), dto);
      res.status(201).json({ success: true, data: permiso });
    } catch (error) {
      next(error);
    }
  });

  /**
   * PATCH /permisos-trabajo/:id/estado
   * Actualizar estado del permiso
   */
  router.patch('/:id/estado', authMiddleware.authenticate, authMiddleware.authorize('admin', 'engineer', 'director'), async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const tenantId = req.tenantId;
      if (!tenantId) {
        res.status(400).json({ error: 'Bad Request', message: 'Tenant ID required' });
        return;
      }

      const { estado, motivo } = req.body;
      if (!estado) {
        res.status(400).json({ error: 'Bad Request', message: 'estado is required' });
        return;
      }

      const permiso = await permisoService.updatePermisoEstado(getContext(req), req.params.id, estado, motivo);
      if (!permiso) {
        res.status(404).json({ error: 'Not Found', message: 'Work permit not found' });
        return;
      }

      res.status(200).json({ success: true, data: permiso });
    } catch (error) {
      next(error);
    }
  });

  // ========== Personal Autorizado ==========

  /**
   * GET /permisos-trabajo/:id/personal
   * Obtener personal autorizado del permiso
   */
  router.get('/:id/personal', authMiddleware.authenticate, async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const personal = await permisoService.getPersonalByPermiso(getContext(req), req.params.id);
      res.status(200).json({ success: true, data: personal });
    } catch (error) {
      next(error);
    }
  });

  // ========== Autorizaciones ==========

  /**
   * GET /permisos-trabajo/:id/autorizaciones
   * Obtener autorizaciones del permiso
   */
  router.get('/:id/autorizaciones', authMiddleware.authenticate, async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const autorizaciones = await permisoService.getAutorizacionesByPermiso(getContext(req), req.params.id);
      res.status(200).json({ success: true, data: autorizaciones });
    } catch (error) {
      next(error);
    }
  });

  // ========== Checklist ==========

  /**
   * GET /permisos-trabajo/:id/checklist
   * Obtener checklist del permiso
   */
  router.get('/:id/checklist', authMiddleware.authenticate, async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const checklist = await permisoService.getChecklistByPermiso(getContext(req), req.params.id);
      res.status(200).json({ success: true, data: checklist });
    } catch (error) {
      next(error);
    }
  });

  // ========== Monitoreo ==========

  /**
   * GET /permisos-trabajo/:id/monitoreos
   * Obtener monitoreos del permiso
   */
  router.get('/:id/monitoreos', authMiddleware.authenticate, async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const monitoreos = await permisoService.getMonitoreosByPermiso(getContext(req), req.params.id);
      res.status(200).json({ success: true, data: monitoreos });
    } catch (error) {
      next(error);
    }
  });

  // ========== Eventos ==========

  /**
   * GET /permisos-trabajo/:id/eventos
   * Obtener eventos del permiso
   */
  router.get('/:id/eventos', authMiddleware.authenticate, async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const eventos = await permisoService.getEventosByPermiso(getContext(req), req.params.id);
      res.status(200).json({ success: true, data: eventos });
    } catch (error) {
      next(error);
    }
  });

  // ========== Documentos ==========

  /**
   * GET /permisos-trabajo/:id/documentos
   * Obtener documentos del permiso
   */
  router.get('/:id/documentos', authMiddleware.authenticate, async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const documentos = await permisoService.getDocumentosByPermiso(getContext(req), req.params.id);
      res.status(200).json({ success: true, data: documentos });
    } catch (error) {
      next(error);
    }
  });

  return router;
}

export default createPermisoTrabajoController;
