/**
 * WarehouseController - Controlador de Almacenes
 *
 * Endpoints para gestion de almacenes.
 * Soporta multi-tenant via header x-tenant-id.
 *
 * @module Warehouses
 */

import { Router, Request, Response, NextFunction } from 'express';
import { DataSource } from 'typeorm';
import { WarehouseService, 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 createWarehouseController(dataSource: DataSource): Router {
  const router = Router();
  const service = new WarehouseService(dataSource);

  // ==================== CRUD DE ALMACENES ====================

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

      const filters = {
        warehouseType: req.query.warehouseType as any,
        branchId: req.query.branchId as string,
        companyId: req.query.companyId as string,
        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 /statistics
   * Obtiene estadisticas de almacenes
   */
  router.get('/statistics', async (req: Request, res: Response): Promise<void> => {
    try {
      const ctx = getServiceContext(req);

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

  /**
   * GET /active
   * Lista almacenes activos para dropdowns
   */
  router.get('/active', async (req: Request, res: Response): Promise<void> => {
    try {
      const ctx = getServiceContext(req);

      const warehouses = await service.getActiveWarehouses(ctx);
      res.json(warehouses);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * GET /default
   * Obtiene el almacen por defecto
   */
  router.get('/default', async (req: Request, res: Response): Promise<void> => {
    try {
      const ctx = getServiceContext(req);

      const warehouse = await service.findDefault(ctx);
      res.json(warehouse);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * GET /search
   * Busqueda de almacenes para autocomplete
   */
  router.get('/search', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const ctx = getServiceContext(req);
      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 parametro de busqueda (q)' });
        return;
      }

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

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

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

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

  /**
   * GET /by-branch/:branchId
   * Obtiene almacenes por sucursal
   */
  router.get('/by-branch/:branchId', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const ctx = getServiceContext(req);

      const warehouses = await service.findByBranch(ctx, req.params.branchId);
      res.json(warehouses);
    } catch (error) {
      next(error);
    }
  });

  /**
   * GET /check-code/:code
   * Verifica si un codigo esta disponible
   */
  router.get('/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.code, excludeId);
      res.json({ available });
    } catch (error) {
      next(error);
    }
  });

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

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

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

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

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

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

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

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

  /**
   * PATCH /:id/set-default
   * Establece un almacen como predeterminado
   */
  router.patch('/:id/set-default', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const ctx = getServiceContext(req);

      const warehouse = await service.setAsDefault(ctx, req.params.id);
      if (!warehouse) {
        res.status(404).json({ error: 'Almacen no encontrado' });
        return;
      }

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

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

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

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

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

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

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

  /**
   * DELETE /:id
   * Elimina un almacen (soft delete)
   */
  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: 'Almacen no encontrado' });
        return;
      }

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

  return router;
}
