/**
 * Dispatch Controller
 * ERP Transportistas
 *
 * REST API endpoints for dispatch operations.
 * Module: MAI-005 Despacho
 * Adapted from: erp-mecanicas-diesel MMD-011 Dispatch Center
 */

import { Router, Request, Response, NextFunction } from 'express';
import { DataSource } from 'typeorm';
import { DispatchService } from '../services/dispatch.service';
import { EstadoUnidadEnum, CapacidadUnidad } from '../entities/estado-unidad.entity';

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

export function createDispatchController(dataSource: DataSource): Router {
  const router = Router();
  const service = new DispatchService(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);

  // ==========================================
  // Tablero Despacho
  // ==========================================

  /**
   * Create dispatch board
   * POST /api/despacho/tablero
   */
  router.post('/tablero', async (req: TenantRequest, res: Response) => {
    try {
      const tablero = await service.crearTablero(req.tenantId!, {
        ...req.body,
        createdBy: req.userId,
      });
      res.status(201).json(tablero);
    } catch (error) {
      res.status(400).json({ error: (error as Error).message });
    }
  });

  /**
   * Get active dispatch board
   * GET /api/despacho/tablero
   */
  router.get('/tablero', async (req: TenantRequest, res: Response) => {
    try {
      const tablero = await service.getTableroActivo(req.tenantId!);
      if (!tablero) {
        return res.status(404).json({ error: 'No se encontro tablero de despacho activo' });
      }
      res.json(tablero);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  // ==========================================
  // Estado Unidades
  // ==========================================

  /**
   * Create unit status
   * POST /api/despacho/unidades
   */
  router.post('/unidades', async (req: TenantRequest, res: Response) => {
    try {
      const estadoUnidad = await service.crearEstadoUnidad(req.tenantId!, req.body);
      res.status(201).json(estadoUnidad);
    } catch (error) {
      res.status(400).json({ error: (error as Error).message });
    }
  });

  /**
   * Get all units
   * GET /api/despacho/unidades
   */
  router.get('/unidades', async (req: TenantRequest, res: Response) => {
    try {
      const incluirOffline = req.query.incluirOffline !== 'false';
      const unidades = await service.getTodasUnidades(req.tenantId!, incluirOffline);
      res.json(unidades);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * Get available units
   * GET /api/despacho/unidades/disponibles
   */
  router.get('/unidades/disponibles', async (req: TenantRequest, res: Response) => {
    try {
      const filtros = {
        capacidadUnidad: req.query.capacidad as CapacidadUnidad,
        puedeRemolcar: req.query.puedeRemolcar === 'true',
        tieneUbicacion: req.query.tieneUbicacion === 'true',
        esRefrigerada: req.query.esRefrigerada === 'true' ? true : undefined,
      };
      const unidades = await service.getUnidadesDisponibles(req.tenantId!, filtros);
      res.json(unidades);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * Get dispatch stats
   * GET /api/despacho/estadisticas
   */
  router.get('/estadisticas', async (req: TenantRequest, res: Response) => {
    try {
      const stats = await service.getEstadisticasDespacho(req.tenantId!);
      res.json(stats);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * Get unit status by unit ID
   * GET /api/despacho/unidades/:unidadId
   */
  router.get('/unidades/:unidadId', async (req: TenantRequest, res: Response) => {
    try {
      const estadoUnidad = await service.getEstadoUnidad(req.tenantId!, req.params.unidadId);
      if (!estadoUnidad) {
        return res.status(404).json({ error: 'Estado de unidad no encontrado' });
      }
      res.json(estadoUnidad);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * Update unit status
   * PATCH /api/despacho/unidades/:unidadId
   */
  router.patch('/unidades/:unidadId', async (req: TenantRequest, res: Response) => {
    try {
      const estadoUnidad = await service.actualizarEstadoUnidad(
        req.tenantId!,
        req.params.unidadId,
        req.body
      );
      if (!estadoUnidad) {
        return res.status(404).json({ error: 'Estado de unidad no encontrado' });
      }
      res.json(estadoUnidad);
    } catch (error) {
      res.status(400).json({ error: (error as Error).message });
    }
  });

  /**
   * Update unit position (from GPS)
   * PATCH /api/despacho/unidades/:unidadId/posicion
   */
  router.patch('/unidades/:unidadId/posicion', async (req: TenantRequest, res: Response) => {
    try {
      const { latitud, longitud, posicionId } = req.body;
      const estadoUnidad = await service.actualizarEstadoUnidad(req.tenantId!, req.params.unidadId, {
        ultimaPosicionLat: latitud,
        ultimaPosicionLng: longitud,
        ultimaPosicionId: posicionId,
      });
      if (!estadoUnidad) {
        return res.status(404).json({ error: 'Estado de unidad no encontrado' });
      }
      res.json(estadoUnidad);
    } catch (error) {
      res.status(400).json({ error: (error as Error).message });
    }
  });

  // ==========================================
  // Assignment Operations
  // ==========================================

  /**
   * Assign viaje to unit
   * POST /api/despacho/asignar
   */
  router.post('/asignar', async (req: TenantRequest, res: Response) => {
    try {
      const { viajeId, unidadId, operadorIds, notas } = req.body;
      const estadoUnidad = await service.asignarViaje(
        req.tenantId!,
        viajeId,
        { unidadId, operadorIds, notas },
        req.userId!
      );
      res.json(estadoUnidad);
    } catch (error) {
      res.status(400).json({ error: (error as Error).message });
    }
  });

  /**
   * Reassign viaje to different unit
   * POST /api/despacho/reasignar
   */
  router.post('/reasignar', async (req: TenantRequest, res: Response) => {
    try {
      const { viajeId, unidadId, operadorIds, razon } = req.body;
      const estadoUnidad = await service.reasignarViaje(
        req.tenantId!,
        viajeId,
        { unidadId, operadorIds },
        razon,
        req.userId!
      );
      res.json(estadoUnidad);
    } catch (error) {
      res.status(400).json({ error: (error as Error).message });
    }
  });

  /**
   * Suggest best assignment for viaje
   * POST /api/despacho/sugerir
   */
  router.post('/sugerir', async (req: TenantRequest, res: Response) => {
    try {
      const {
        viajeId,
        origenLat,
        origenLng,
        tipoCarga,
        pesoKg,
        distanciaRutaKm,
        requiereFrio,
        requiereLicenciaFederal,
        requiereCertificadoMP,
      } = req.body;
      const sugerencias = await service.sugerirMejorAsignacion(req.tenantId!, {
        viajeId,
        origenLat,
        origenLng,
        tipoCarga,
        pesoKg,
        distanciaRutaKm,
        requiereFrio,
        requiereLicenciaFederal,
        requiereCertificadoMP,
      });
      res.json(sugerencias);
    } catch (error) {
      res.status(400).json({ error: (error as Error).message });
    }
  });

  /**
   * Mark unit as en route
   * POST /api/despacho/unidades/:unidadId/en-ruta
   */
  router.post('/unidades/:unidadId/en-ruta', async (req: TenantRequest, res: Response) => {
    try {
      const estadoUnidad = await service.marcarEnRuta(
        req.tenantId!,
        req.params.unidadId,
        req.userId!
      );
      if (!estadoUnidad) {
        return res.status(404).json({ error: 'Unidad no encontrada o sin viaje activo' });
      }
      res.json(estadoUnidad);
    } catch (error) {
      res.status(400).json({ error: (error as Error).message });
    }
  });

  /**
   * Mark unit as on site
   * POST /api/despacho/unidades/:unidadId/en-sitio
   */
  router.post('/unidades/:unidadId/en-sitio', async (req: TenantRequest, res: Response) => {
    try {
      const estadoUnidad = await service.marcarEnSitio(
        req.tenantId!,
        req.params.unidadId,
        req.userId!
      );
      if (!estadoUnidad) {
        return res.status(404).json({ error: 'Unidad no encontrada o sin viaje activo' });
      }
      res.json(estadoUnidad);
    } catch (error) {
      res.status(400).json({ error: (error as Error).message });
    }
  });

  /**
   * Complete viaje and mark unit as returning
   * POST /api/despacho/unidades/:unidadId/completar
   */
  router.post('/unidades/:unidadId/completar', async (req: TenantRequest, res: Response) => {
    try {
      const estadoUnidad = await service.completarViaje(
        req.tenantId!,
        req.params.unidadId,
        req.userId!
      );
      if (!estadoUnidad) {
        return res.status(404).json({ error: 'Unidad no encontrada o sin viaje activo' });
      }
      res.json(estadoUnidad);
    } catch (error) {
      res.status(400).json({ error: (error as Error).message });
    }
  });

  /**
   * Release unit (make available)
   * POST /api/despacho/unidades/:unidadId/liberar
   */
  router.post('/unidades/:unidadId/liberar', async (req: TenantRequest, res: Response) => {
    try {
      const estadoUnidad = await service.liberarUnidad(req.tenantId!, req.params.unidadId);
      if (!estadoUnidad) {
        return res.status(404).json({ error: 'Unidad no encontrada' });
      }
      res.json(estadoUnidad);
    } catch (error) {
      res.status(400).json({ error: (error as Error).message });
    }
  });

  // ==========================================
  // Dispatch Logs
  // ==========================================

  /**
   * Get dispatch logs for viaje
   * GET /api/despacho/logs/viaje/:viajeId
   */
  router.get('/logs/viaje/:viajeId', async (req: TenantRequest, res: Response) => {
    try {
      const logs = await service.getLogsViaje(req.tenantId!, req.params.viajeId);
      res.json(logs);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * Get recent dispatch logs
   * GET /api/despacho/logs
   */
  router.get('/logs', async (req: TenantRequest, res: Response) => {
    try {
      const limite = parseInt(req.query.limite as string, 10) || 50;
      const logs = await service.getLogsRecientes(req.tenantId!, Math.min(limite, 200));
      res.json(logs);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  return router;
}
