/**
 * WarehouseZoneController - Controlador de Zonas de Almacen
 *
 * Endpoints para gestion de zonas dentro de almacenes.
 * Las zonas permiten organizar el almacen en areas funcionales.
 *
 * @module Warehouses
 */

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

/**
 * Extract service context from request
 */
function getServiceContext(req: Request): ServiceContext {
  return {
    tenantId: req.headers['x-tenant-id'] as string,
    userId: (req as any).user?.id,
    companyId: req.headers['x-company-id'] as string,
  };
}

export function createWarehouseZoneController(dataSource: DataSource): Router {
  const router = Router();
  const service = new WarehouseZoneService(dataSource);

  // ==================== CRUD DE ZONAS ====================

  /**
   * GET /
   * Lista zonas con filtros y paginacion
   */
  router.get('/', async (req: Request, res: Response, _next: NextFunction): Promise<void> => {
    try {
      const ctx = getServiceContext(req);

      const filters = {
        warehouseId: req.query.warehouseId as string,
        zoneType: req.query.zoneType as any,
        isActive: req.query.isActive === 'true' ? true : req.query.isActive === 'false' ? false : 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(ctx, filters, pagination);
      res.json(result);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * GET /by-warehouse/:warehouseId
   * Lista zonas de un almacen especifico
   */
  router.get('/by-warehouse/:warehouseId', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const ctx = getServiceContext(req);

      const filters = {
        zoneType: req.query.zoneType as any,
        isActive: req.query.isActive === 'true' ? true : req.query.isActive === 'false' ? false : undefined,
        search: req.query.search as string,
      };

      const zones = await service.findByWarehouse(ctx, req.params.warehouseId, filters);
      res.json(zones);
    } catch (error) {
      next(error);
    }
  });

  /**
   * GET /by-warehouse/:warehouseId/active
   * Lista zonas activas de un almacen para dropdowns
   */
  router.get('/by-warehouse/:warehouseId/active', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const ctx = getServiceContext(req);

      const zones = await service.getActiveZones(ctx, req.params.warehouseId);
      res.json(zones);
    } catch (error) {
      next(error);
    }
  });

  /**
   * GET /by-warehouse/:warehouseId/statistics
   * Obtiene estadisticas de zonas de un almacen
   */
  router.get('/by-warehouse/:warehouseId/statistics', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const ctx = getServiceContext(req);

      const stats = await service.getStatistics(ctx, req.params.warehouseId);
      res.json(stats);
    } catch (error) {
      next(error);
    }
  });

  /**
   * GET /by-warehouse/:warehouseId/check-code/:code
   * Verifica si un codigo de zona esta disponible
   */
  router.get('/by-warehouse/:warehouseId/check-code/:code', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const ctx = getServiceContext(req);
      const excludeId = req.query.excludeId as string;

      const available = await service.isCodeAvailable(
        ctx,
        req.params.warehouseId,
        req.params.code,
        excludeId
      );
      res.json({ available });
    } catch (error) {
      next(error);
    }
  });

  /**
   * GET /by-warehouse/:warehouseId/by-code/:code
   * Obtiene una zona por codigo dentro de un almacen
   */
  router.get('/by-warehouse/:warehouseId/by-code/:code', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const ctx = getServiceContext(req);

      const zone = await service.findByCode(ctx, req.params.warehouseId, req.params.code);
      if (!zone) {
        res.status(404).json({ error: 'Zona no encontrada' });
        return;
      }

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

  /**
   * GET /:id
   * Obtiene una zona por ID
   */
  router.get('/:id', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const ctx = getServiceContext(req);

      const zone = await service.findById(ctx, req.params.id);
      if (!zone) {
        res.status(404).json({ error: 'Zona no encontrada' });
        return;
      }

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

  /**
   * POST /
   * Crea una nueva zona
   */
  router.post('/', async (req: Request, res: Response): Promise<void> => {
    try {
      const ctx = getServiceContext(req);

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

  /**
   * POST /by-warehouse/:warehouseId/bulk
   * Crea multiples zonas para un almacen
   */
  router.post('/by-warehouse/:warehouseId/bulk', async (req: Request, res: Response): Promise<void> => {
    try {
      const ctx = getServiceContext(req);

      if (!Array.isArray(req.body.zones)) {
        res.status(400).json({ error: 'Se requiere un array de zonas en el campo "zones"' });
        return;
      }

      const zones = await service.bulkCreate(ctx, req.params.warehouseId, req.body.zones);
      res.status(201).json(zones);
    } catch (error) {
      res.status(400).json({ error: (error as Error).message });
    }
  });

  /**
   * PUT /:id
   * Actualiza una zona
   */
  router.put('/:id', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const ctx = getServiceContext(req);

      const zone = await service.update(ctx, req.params.id, req.body);
      if (!zone) {
        res.status(404).json({ error: 'Zona no encontrada' });
        return;
      }

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

  /**
   * PATCH /:id/activate
   * Activa una zona
   */
  router.patch('/:id/activate', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const ctx = getServiceContext(req);

      const zone = await service.setActive(ctx, req.params.id, true);
      if (!zone) {
        res.status(404).json({ error: 'Zona no encontrada' });
        return;
      }

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

  /**
   * PATCH /:id/deactivate
   * Desactiva una zona
   */
  router.patch('/:id/deactivate', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const ctx = getServiceContext(req);

      const zone = await service.setActive(ctx, req.params.id, false);
      if (!zone) {
        res.status(404).json({ error: 'Zona no encontrada' });
        return;
      }

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

  /**
   * DELETE /:id
   * Elimina una zona
   */
  router.delete('/:id', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const ctx = getServiceContext(req);

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

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

  return router;
}
