/**
 * AssetController - Controlador de Activos
 *
 * Endpoints para gestión de activos fijos, maquinaria y equipos.
 *
 * @module Assets (MAE-015)
 */

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

export function createAssetController(dataSource: DataSource): Router {
  const router = Router();
  const service = new AssetService(dataSource);

  // ==================== CRUD DE ACTIVOS ====================

  /**
   * GET /
   * Lista activos 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 = {
        assetType: req.query.assetType as any,
        status: req.query.status as any,
        ownershipType: req.query.ownershipType as any,
        categoryId: req.query.categoryId as string,
        projectId: req.query.projectId as string,
        search: req.query.search as string,
        tags: req.query.tags ? (req.query.tags as string).split(',') : undefined,
      };

      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) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

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

      const stats = await service.getStatistics(tenantId);
      res.json(stats);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * GET /maintenance-due
   * Lista activos que requieren mantenimiento
   */
  router.get('/maintenance-due', async (req: Request, res: Response) => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;

      const assets = await service.getAssetsNeedingMaintenance(tenantId);
      res.json(assets);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * GET /search
   * Búsqueda de activos para autocomplete
   */
  router.get('/search', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      const query = req.query.q as string;
      const limit = parseInt(req.query.limit as string) || 10;

      if (!query) {
        res.status(400).json({ error: 'Se requiere parámetro de búsqueda (q)' });
        return;
      }

      const assets = await service.search(tenantId, query, limit);
      res.json(assets);
    } catch (error) {
      next(error);
    }
  });

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

      const asset = await service.findByCode(tenantId, req.params.code);
      if (!asset) {
        res.status(404).json({ error: 'Activo no encontrado' });
        return;
      }

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

  /**
   * GET /:id
   * Obtiene un activo 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 asset = await service.findById(tenantId, req.params.id);
      if (!asset) {
        res.status(404).json({ error: 'Activo no encontrado' });
        return;
      }

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

  /**
   * POST /
   * Crea un nuevo activo
   */
  router.post('/', async (req: Request, res: Response) => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      const userId = (req as any).user?.id;

      const asset = await service.create(tenantId, req.body, userId);
      res.status(201).json(asset);
    } catch (error) {
      res.status(400).json({ error: (error as Error).message });
    }
  });

  /**
   * PUT /:id
   * Actualiza un activo
   */
  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 asset = await service.update(tenantId, req.params.id, req.body, userId);
      if (!asset) {
        res.status(404).json({ error: 'Activo no encontrado' });
        return;
      }

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

  /**
   * PATCH /:id/status
   * Actualiza el estado de un activo
   */
  router.patch('/:id/status', 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 { status } = req.body;

      if (!status) {
        res.status(400).json({ error: 'Se requiere el nuevo estado' });
        return;
      }

      const asset = await service.updateStatus(tenantId, req.params.id, status, userId);
      if (!asset) {
        res.status(404).json({ error: 'Activo no encontrado' });
        return;
      }

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

  /**
   * PATCH /:id/usage
   * Actualiza métricas de uso (horas/kilómetros)
   */
  router.patch('/:id/usage', 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 { hours, kilometers } = req.body;

      const asset = await service.updateUsage(tenantId, req.params.id, hours, kilometers, userId);
      if (!asset) {
        res.status(404).json({ error: 'Activo no encontrado' });
        return;
      }

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

  /**
   * DELETE /:id
   * Elimina un activo (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: 'Activo no encontrado' });
        return;
      }

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

  // ==================== ASIGNACIONES ====================

  /**
   * GET /:id/assignment
   * Obtiene la asignación actual de un activo
   */
  router.get('/:id/assignment', async (req: Request, res: Response) => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;

      const assignment = await service.getCurrentAssignment(tenantId, req.params.id);
      res.json(assignment);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * GET /:id/assignments
   * Obtiene el historial de asignaciones de un activo
   */
  router.get('/:id/assignments', async (req: Request, res: Response) => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;

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

      const history = await service.getAssignmentHistory(tenantId, req.params.id, pagination);
      res.json(history);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * POST /:id/assign
   * Asigna un activo a un proyecto
   */
  router.post('/:id/assign', async (req: Request, res: Response) => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      const userId = (req as any).user?.id;

      const dto = {
        ...req.body,
        assetId: req.params.id,
      };

      const assignment = await service.assignToProject(tenantId, dto, userId);
      res.status(201).json(assignment);
    } catch (error) {
      res.status(400).json({ error: (error as Error).message });
    }
  });

  /**
   * POST /:id/return
   * Retorna un activo de un proyecto
   */
  router.post('/:id/return', 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 { endDate } = req.body;

      const result = await service.returnFromProject(
        tenantId,
        req.params.id,
        endDate ? new Date(endDate) : new Date(),
        userId
      );

      if (!result) {
        res.status(400).json({ error: 'No hay asignación activa para este activo' });
        return;
      }

      res.json({ success: true, message: 'Activo retornado exitosamente' });
    } catch (error) {
      next(error);
    }
  });

  // ==================== CATEGORÍAS ====================

  /**
   * GET /categories
   * Lista categorías de activos
   */
  router.get('/categories/list', async (req: Request, res: Response) => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;

      const categories = await service.getCategories(tenantId);
      res.json(categories);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * POST /categories
   * Crea una nueva categoría
   */
  router.post('/categories', async (req: Request, res: Response) => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      const userId = (req as any).user?.id;

      const category = await service.createCategory(tenantId, req.body, userId);
      res.status(201).json(category);
    } catch (error) {
      res.status(400).json({ error: (error as Error).message });
    }
  });

  return router;
}
