/**
 * Rule Controller
 * ERP Transportistas
 *
 * REST API endpoints for dispatch and escalation rules.
 * Module: MAI-005 Despacho
 * Adapted from: erp-mecanicas-diesel MMD-011 RuleController
 */

import { Router, Request, Response, NextFunction } from 'express';
import { DataSource } from 'typeorm';
import { RuleService } from '../services/rule.service';

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

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

  // ==========================================
  // Reglas de Despacho
  // ==========================================

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

  /**
   * List dispatch rules
   * GET /api/despacho/reglas/despacho
   */
  router.get('/despacho', async (req: TenantRequest, res: Response) => {
    try {
      const soloActivas = req.query.soloActivas === 'true';
      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.listarReglasDespacho(req.tenantId!, soloActivas, paginacion);
      res.json(resultado);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * Get matching dispatch rules for viaje
   * POST /api/despacho/reglas/despacho/coincidentes
   */
  router.post('/despacho/coincidentes', async (req: TenantRequest, res: Response) => {
    try {
      const { tipoViaje, categoriaViaje } = req.body;
      const reglas = await service.getReglasDespachoCoincidentes(
        req.tenantId!,
        tipoViaje,
        categoriaViaje
      );
      res.json(reglas);
    } catch (error) {
      res.status(400).json({ error: (error as Error).message });
    }
  });

  /**
   * Evaluate rules for assignment
   * POST /api/despacho/reglas/despacho/evaluar
   */
  router.post('/despacho/evaluar', async (req: TenantRequest, res: Response) => {
    try {
      const coincidentes = await service.evaluarReglas(req.tenantId!, req.body);
      res.json(coincidentes);
    } catch (error) {
      res.status(400).json({ error: (error as Error).message });
    }
  });

  /**
   * Get dispatch rule by ID
   * GET /api/despacho/reglas/despacho/:id
   */
  router.get('/despacho/:id', async (req: TenantRequest, res: Response) => {
    try {
      const regla = await service.getReglaDespachoById(req.tenantId!, req.params.id);
      if (!regla) {
        return res.status(404).json({ error: 'Regla de despacho no encontrada' });
      }
      res.json(regla);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * Update dispatch rule
   * PATCH /api/despacho/reglas/despacho/:id
   */
  router.patch('/despacho/:id', async (req: TenantRequest, res: Response) => {
    try {
      const regla = await service.actualizarReglaDespacho(req.tenantId!, req.params.id, req.body);
      if (!regla) {
        return res.status(404).json({ error: 'Regla de despacho no encontrada' });
      }
      res.json(regla);
    } catch (error) {
      res.status(400).json({ error: (error as Error).message });
    }
  });

  /**
   * Delete dispatch rule
   * DELETE /api/despacho/reglas/despacho/:id
   */
  router.delete('/despacho/:id', async (req: TenantRequest, res: Response) => {
    try {
      const success = await service.eliminarReglaDespacho(req.tenantId!, req.params.id);
      if (!success) {
        return res.status(404).json({ error: 'Regla de despacho no encontrada' });
      }
      res.status(204).send();
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  // ==========================================
  // Reglas de Escalamiento
  // ==========================================

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

  /**
   * List escalation rules
   * GET /api/despacho/reglas/escalamiento
   */
  router.get('/escalamiento', async (req: TenantRequest, res: Response) => {
    try {
      const soloActivas = req.query.soloActivas === 'true';
      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.listarReglasEscalamiento(req.tenantId!, soloActivas, paginacion);
      res.json(resultado);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * Get triggered escalation rules
   * POST /api/despacho/reglas/escalamiento/disparadas
   */
  router.post('/escalamiento/disparadas', async (req: TenantRequest, res: Response) => {
    try {
      const { minutosTranscurridos, estadoViaje, prioridadViaje } = req.body;
      const reglas = await service.getReglasEscalamientoDisparadas(
        req.tenantId!,
        minutosTranscurridos,
        estadoViaje,
        prioridadViaje
      );
      res.json(reglas);
    } catch (error) {
      res.status(400).json({ error: (error as Error).message });
    }
  });

  /**
   * Get escalation rule by ID
   * GET /api/despacho/reglas/escalamiento/:id
   */
  router.get('/escalamiento/:id', async (req: TenantRequest, res: Response) => {
    try {
      const regla = await service.getReglaEscalamientoById(req.tenantId!, req.params.id);
      if (!regla) {
        return res.status(404).json({ error: 'Regla de escalamiento no encontrada' });
      }
      res.json(regla);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * Update escalation rule
   * PATCH /api/despacho/reglas/escalamiento/:id
   */
  router.patch('/escalamiento/:id', async (req: TenantRequest, res: Response) => {
    try {
      const regla = await service.actualizarReglaEscalamiento(req.tenantId!, req.params.id, req.body);
      if (!regla) {
        return res.status(404).json({ error: 'Regla de escalamiento no encontrada' });
      }
      res.json(regla);
    } catch (error) {
      res.status(400).json({ error: (error as Error).message });
    }
  });

  /**
   * Delete escalation rule
   * DELETE /api/despacho/reglas/escalamiento/:id
   */
  router.delete('/escalamiento/:id', async (req: TenantRequest, res: Response) => {
    try {
      const success = await service.eliminarReglaEscalamiento(req.tenantId!, req.params.id);
      if (!success) {
        return res.status(404).json({ error: 'Regla de escalamiento no encontrada' });
      }
      res.status(204).send();
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  return router;
}
