/**
 * WorkOrderController - Controlador de Órdenes de Trabajo
 *
 * Endpoints para gestión de órdenes de trabajo de mantenimiento.
 *
 * @module Assets (MAE-015)
 */

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

export function createWorkOrderController(dataSource: DataSource): Router {
  const router = Router();
  const service = new WorkOrderService(dataSource);

  // ==================== CRUD DE ÓRDENES ====================

  /**
   * GET /
   * Lista órdenes de trabajo con filtros y paginación
   */
  router.get('/', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;

      const filters = {
        assetId: req.query.assetId as string,
        status: req.query.status as any,
        priority: req.query.priority as any,
        maintenanceType: req.query.maintenanceType as any,
        technicianId: req.query.technicianId as string,
        projectId: req.query.projectId as string,
        dateFrom: req.query.dateFrom ? new Date(req.query.dateFrom as string) : undefined,
        dateTo: req.query.dateTo ? new Date(req.query.dateTo as string) : undefined,
        search: req.query.search as string,
      };

      const pagination = {
        page: parseInt(req.query.page as string) || 1,
        limit: parseInt(req.query.limit as string) || 20,
      };

      const result = await service.findAll(tenantId, filters, pagination);
      res.json(result);
    } catch (error) {
      next(error);
    }
  });

  /**
   * GET /statistics
   * Obtiene estadísticas de órdenes de trabajo
   */
  router.get('/statistics', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;

      const stats = await service.getStatistics(tenantId);
      res.json(stats);
    } catch (error) {
      next(error);
    }
  });

  /**
   * GET /by-status
   * Obtiene órdenes agrupadas por estado
   */
  router.get('/by-status', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;

      const grouped = await service.getByStatus(tenantId);
      res.json(grouped);
    } catch (error) {
      next(error);
    }
  });

  /**
   * GET /by-number/:orderNumber
   * Obtiene una orden por número
   */
  router.get('/by-number/:orderNumber', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;

      const workOrder = await service.findByNumber(tenantId, req.params.orderNumber);
      if (!workOrder) {
        res.status(404).json({ error: 'Orden de trabajo no encontrada' });
        return;
      }

      res.json(workOrder);
    } catch (error) {
      next(error);
    }
  });

  /**
   * GET /overdue
   * Lista órdenes vencidas
   */
  router.get('/overdue', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;

      const orders = await service.getOverdue(tenantId);
      res.json(orders);
    } catch (error) {
      next(error);
    }
  });

  /**
   * GET /:id
   * Obtiene una orden de trabajo por ID
   */
  router.get('/:id', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;

      const workOrder = await service.findById(tenantId, req.params.id);
      if (!workOrder) {
        res.status(404).json({ error: 'Orden de trabajo no encontrada' });
        return;
      }

      res.json(workOrder);
    } catch (error) {
      next(error);
    }
  });

  /**
   * POST /
   * Crea una nueva orden de trabajo
   */
  router.post('/', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      const userId = (req as any).user?.id;

      const workOrder = await service.create(tenantId, req.body, userId);
      res.status(201).json(workOrder);
    } catch (error) {
      next(error);
    }
  });

  /**
   * PUT /:id
   * Actualiza una orden de trabajo
   */
  router.put('/:id', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      const userId = (req as any).user?.id;

      const workOrder = await service.update(tenantId, req.params.id, req.body, userId);
      if (!workOrder) {
        res.status(404).json({ error: 'Orden de trabajo no encontrada' });
        return;
      }

      res.json(workOrder);
    } catch (error) {
      next(error);
    }
  });

  /**
   * DELETE /:id
   * Elimina una orden de trabajo (soft delete)
   */
  router.delete('/:id', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      const userId = (req as any).user?.id;

      const deleted = await service.delete(tenantId, req.params.id, userId);
      if (!deleted) {
        res.status(404).json({ error: 'Orden de trabajo no encontrada' });
        return;
      }

      res.status(204).send();
    } catch (error) {
      next(error);
    }
  });

  // ==================== WORKFLOW ====================

  /**
   * POST /:id/start
   * Inicia una orden de trabajo
   */
  router.post('/:id/start', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      const userId = (req as any).user?.id;

      const workOrder = await service.start(tenantId, req.params.id, userId);
      if (!workOrder) {
        res.status(404).json({ error: 'Orden de trabajo no encontrada' });
        return;
      }

      res.json(workOrder);
    } catch (error) {
      next(error);
    }
  });

  /**
   * POST /:id/hold
   * Pone en espera una orden de trabajo
   */
  router.post('/:id/hold', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      const userId = (req as any).user?.id;
      const { reason } = req.body;

      const workOrder = await service.hold(tenantId, req.params.id, reason, userId);
      if (!workOrder) {
        res.status(404).json({ error: 'Orden de trabajo no encontrada' });
        return;
      }

      res.json(workOrder);
    } catch (error) {
      next(error);
    }
  });

  /**
   * POST /:id/resume
   * Reanuda una orden de trabajo en espera
   */
  router.post('/:id/resume', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      const userId = (req as any).user?.id;

      const workOrder = await service.resume(tenantId, req.params.id, userId);
      if (!workOrder) {
        res.status(404).json({ error: 'Orden de trabajo no encontrada' });
        return;
      }

      res.json(workOrder);
    } catch (error) {
      next(error);
    }
  });

  /**
   * POST /:id/complete
   * Completa una orden de trabajo
   */
  router.post('/:id/complete', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      const userId = (req as any).user?.id;

      const workOrder = await service.complete(tenantId, req.params.id, req.body, userId);
      if (!workOrder) {
        res.status(404).json({ error: 'Orden de trabajo no encontrada' });
        return;
      }

      res.json(workOrder);
    } catch (error) {
      next(error);
    }
  });

  /**
   * POST /:id/cancel
   * Cancela una orden de trabajo
   */
  router.post('/:id/cancel', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      const userId = (req as any).user?.id;
      const { reason } = req.body;

      const workOrder = await service.cancel(tenantId, req.params.id, reason, userId);
      if (!workOrder) {
        res.status(404).json({ error: 'Orden de trabajo no encontrada' });
        return;
      }

      res.json(workOrder);
    } catch (error) {
      next(error);
    }
  });

  // ==================== PARTES/REFACCIONES ====================

  /**
   * GET /:id/parts
   * Lista partes usadas en una orden de trabajo
   */
  router.get('/:id/parts', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;

      const parts = await service.getParts(tenantId, req.params.id);
      res.json(parts);
    } catch (error) {
      next(error);
    }
  });

  /**
   * POST /:id/parts
   * Agrega una parte a la orden de trabajo
   */
  router.post('/:id/parts', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      const userId = (req as any).user?.id;

      const part = await service.addPart(tenantId, req.params.id, req.body, userId);
      res.status(201).json(part);
    } catch (error) {
      next(error);
    }
  });

  /**
   * PUT /:id/parts/:partId
   * Actualiza una parte de la orden
   */
  router.put('/:id/parts/:partId', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      const userId = (req as any).user?.id;

      const part = await service.updatePart(tenantId, req.params.partId, req.body, userId);
      if (!part) {
        res.status(404).json({ error: 'Parte no encontrada' });
        return;
      }

      res.json(part);
    } catch (error) {
      next(error);
    }
  });

  /**
   * DELETE /:id/parts/:partId
   * Elimina una parte de la orden
   */
  router.delete('/:id/parts/:partId', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      const userId = (req as any).user?.id;

      const deleted = await service.removePart(tenantId, req.params.partId, userId);
      if (!deleted) {
        res.status(404).json({ error: 'Parte no encontrada' });
        return;
      }

      res.status(204).send();
    } catch (error) {
      next(error);
    }
  });

  // ==================== PLANES DE MANTENIMIENTO ====================

  /**
   * GET /plans
   * Lista planes de mantenimiento
   */
  router.get('/plans/list', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      const assetId = req.query.assetId as string;

      const plans = await service.getMaintenancePlans(tenantId, assetId);
      res.json(plans);
    } catch (error) {
      next(error);
    }
  });

  /**
   * POST /plans
   * Crea un plan de mantenimiento
   */
  router.post('/plans', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      const userId = (req as any).user?.id;

      const plan = await service.createMaintenancePlan(tenantId, req.body, userId);
      res.status(201).json(plan);
    } catch (error) {
      next(error);
    }
  });

  /**
   * POST /plans/:planId/generate
   * Genera órdenes de trabajo desde un plan
   */
  router.post('/plans/:planId/generate', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      const userId = (req as any).user?.id;

      const orders = await service.generateFromPlan(tenantId, req.params.planId, userId);
      res.status(201).json(orders);
    } catch (error) {
      next(error);
    }
  });

  return router;
}
