/**
 * Turno Controller
 * ERP Transportistas
 *
 * REST API endpoints for operator shifts.
 * Module: MAI-005 Despacho
 * Adapted from: erp-mecanicas-diesel MMD-011 ShiftController
 */

import { Router, Request, Response, NextFunction } from 'express';
import { DataSource } from 'typeorm';
import { TurnoService, FiltrosTurno } from '../services/turno.service';
import { TipoTurno } from '../entities/turno-operador.entity';

interface TenantRequest extends Request {
  tenantId?: string;
  userId?: string;
}

export function createTurnoController(dataSource: DataSource): Router {
  const router = Router();
  const service = new TurnoService(dataSource);

  const extractTenant = (req: TenantRequest, res: Response, next: NextFunction) => {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'Tenant ID es requerido' });
    }
    req.tenantId = tenantId;
    req.userId = req.headers['x-user-id'] as string;
    next();
  };

  router.use(extractTenant);

  /**
   * Create shift
   * POST /api/despacho/turnos
   */
  router.post('/', async (req: TenantRequest, res: Response) => {
    try {
      const turno = await service.crearTurno(req.tenantId!, {
        ...req.body,
        fechaTurno: new Date(req.body.fechaTurno),
        createdBy: req.userId,
      });
      res.status(201).json(turno);
    } catch (error) {
      res.status(400).json({ error: (error as Error).message });
    }
  });

  /**
   * List shifts with filters
   * GET /api/despacho/turnos
   */
  router.get('/', async (req: TenantRequest, res: Response) => {
    try {
      const filtros: FiltrosTurno = {
        operadorId: req.query.operadorId as string,
        tipoTurno: req.query.tipoTurno as TipoTurno,
        fechaDesde: req.query.fechaDesde ? new Date(req.query.fechaDesde as string) : undefined,
        fechaHasta: req.query.fechaHasta ? new Date(req.query.fechaHasta as string) : undefined,
        enGuardia: req.query.enGuardia === 'true' ? true : req.query.enGuardia === 'false' ? false : undefined,
        unidadAsignadaId: req.query.unidadAsignadaId as string,
        ausente: req.query.ausente === 'true' ? true : req.query.ausente === 'false' ? false : undefined,
      };

      const paginacion = {
        pagina: parseInt(req.query.pagina as string, 10) || 1,
        limite: Math.min(parseInt(req.query.limite as string, 10) || 20, 100),
      };

      const resultado = await service.listar(req.tenantId!, filtros, paginacion);
      res.json(resultado);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * Get shifts for date
   * GET /api/despacho/turnos/fecha/:fecha
   */
  router.get('/fecha/:fecha', async (req: TenantRequest, res: Response) => {
    try {
      const fecha = new Date(req.params.fecha);
      const excluirAusentes = req.query.excluirAusentes !== 'false';
      const turnos = await service.getTurnosPorFecha(req.tenantId!, fecha, excluirAusentes);
      res.json(turnos);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * Get available operators for date/time
   * GET /api/despacho/turnos/disponibles
   */
  router.get('/disponibles', async (req: TenantRequest, res: Response) => {
    try {
      const fecha = new Date(req.query.fecha as string);
      const hora = req.query.hora as string;
      const disponibilidad = await service.getOperadoresDisponibles(req.tenantId!, fecha, hora);
      res.json(disponibilidad);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * Get on-call operators for date
   * GET /api/despacho/turnos/en-guardia
   */
  router.get('/en-guardia', async (req: TenantRequest, res: Response) => {
    try {
      const fecha = new Date(req.query.fecha as string);
      const turnos = await service.getOperadoresEnGuardia(req.tenantId!, fecha);
      res.json(turnos);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * Get shifts for operator
   * GET /api/despacho/turnos/operador/:operadorId
   */
  router.get('/operador/:operadorId', async (req: TenantRequest, res: Response) => {
    try {
      const fechaDesde = req.query.fechaDesde ? new Date(req.query.fechaDesde as string) : undefined;
      const fechaHasta = req.query.fechaHasta ? new Date(req.query.fechaHasta as string) : undefined;
      const turnos = await service.getTurnosOperador(
        req.tenantId!,
        req.params.operadorId,
        fechaDesde,
        fechaHasta
      );
      res.json(turnos);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * Get shifts by unit
   * GET /api/despacho/turnos/unidad/:unidadId
   */
  router.get('/unidad/:unidadId', async (req: TenantRequest, res: Response) => {
    try {
      const fecha = new Date(req.query.fecha as string);
      const turnos = await service.getTurnosPorUnidad(req.tenantId!, req.params.unidadId, fecha);
      res.json(turnos);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * Generate weekly shifts
   * POST /api/despacho/turnos/generar-semanales
   */
  router.post('/generar-semanales', async (req: TenantRequest, res: Response) => {
    try {
      const {
        operadorId,
        fechaInicioSemana,
        tipoTurno,
        horaInicio,
        horaFin,
        diasSemana,
      } = req.body;

      const turnos = await service.generarTurnosSemanales(
        req.tenantId!,
        operadorId,
        new Date(fechaInicioSemana),
        tipoTurno,
        horaInicio,
        horaFin,
        diasSemana,
        req.userId
      );
      res.status(201).json(turnos);
    } catch (error) {
      res.status(400).json({ error: (error as Error).message });
    }
  });

  /**
   * Get shift by ID
   * GET /api/despacho/turnos/:id
   */
  router.get('/:id', async (req: TenantRequest, res: Response) => {
    try {
      const turno = await service.getById(req.tenantId!, req.params.id);
      if (!turno) {
        return res.status(404).json({ error: 'Turno no encontrado' });
      }
      res.json(turno);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * Update shift
   * PATCH /api/despacho/turnos/:id
   */
  router.patch('/:id', async (req: TenantRequest, res: Response) => {
    try {
      const turno = await service.actualizarTurno(req.tenantId!, req.params.id, req.body);
      if (!turno) {
        return res.status(404).json({ error: 'Turno no encontrado' });
      }
      res.json(turno);
    } catch (error) {
      res.status(400).json({ error: (error as Error).message });
    }
  });

  /**
   * Start shift
   * POST /api/despacho/turnos/:id/iniciar
   */
  router.post('/:id/iniciar', async (req: TenantRequest, res: Response) => {
    try {
      const turno = await service.iniciarTurno(req.tenantId!, req.params.id);
      if (!turno) {
        return res.status(404).json({ error: 'Turno no encontrado' });
      }
      res.json(turno);
    } catch (error) {
      res.status(400).json({ error: (error as Error).message });
    }
  });

  /**
   * End shift
   * POST /api/despacho/turnos/:id/finalizar
   */
  router.post('/:id/finalizar', async (req: TenantRequest, res: Response) => {
    try {
      const turno = await service.finalizarTurno(req.tenantId!, req.params.id);
      if (!turno) {
        return res.status(404).json({ error: 'Turno no encontrado' });
      }
      res.json(turno);
    } catch (error) {
      res.status(400).json({ error: (error as Error).message });
    }
  });

  /**
   * Mark absent
   * POST /api/despacho/turnos/:id/ausente
   */
  router.post('/:id/ausente', async (req: TenantRequest, res: Response) => {
    try {
      const { motivo } = req.body;
      const turno = await service.marcarAusente(req.tenantId!, req.params.id, motivo);
      if (!turno) {
        return res.status(404).json({ error: 'Turno no encontrado' });
      }
      res.json(turno);
    } catch (error) {
      res.status(400).json({ error: (error as Error).message });
    }
  });

  /**
   * Assign unit to shift
   * POST /api/despacho/turnos/:id/asignar-unidad
   */
  router.post('/:id/asignar-unidad', async (req: TenantRequest, res: Response) => {
    try {
      const { unidadId } = req.body;
      const turno = await service.asignarUnidadATurno(req.tenantId!, req.params.id, unidadId);
      if (!turno) {
        return res.status(404).json({ error: 'Turno no encontrado' });
      }
      res.json(turno);
    } catch (error) {
      res.status(400).json({ error: (error as Error).message });
    }
  });

  /**
   * Delete shift
   * DELETE /api/despacho/turnos/:id
   */
  router.delete('/:id', async (req: TenantRequest, res: Response) => {
    try {
      const success = await service.eliminarTurno(req.tenantId!, req.params.id);
      if (!success) {
        return res.status(404).json({ error: 'Turno no encontrado' });
      }
      res.status(204).send();
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  return router;
}
