import { Response, NextFunction } from 'express';
import { z } from 'zod';
import { productsService, CreateProductDto, UpdateProductDto, ProductFilters } from './products.service.js';
import { warehousesService, CreateWarehouseDto, UpdateWarehouseDto, WarehouseFilters } from './warehouses.service.js';
import { locationsService, CreateLocationDto, UpdateLocationDto, LocationFilters } from './locations.service.js';
import { pickingsService, CreatePickingDto, PickingFilters } from './pickings.service.js';
import { lotsService, CreateLotDto, UpdateLotDto, LotFilters } from './lots.service.js';
import { adjustmentsService, CreateAdjustmentDto, UpdateAdjustmentDto, CreateAdjustmentLineDto, UpdateAdjustmentLineDto, AdjustmentFilters } from './adjustments.service.js';
import { AuthenticatedRequest } from '../../shared/middleware/auth.middleware.js';
import { ValidationError } from '../../shared/errors/index.js';

// Product schemas
const createProductSchema = z.object({
  name: z.string().min(1, 'El nombre es requerido').max(255),
  code: z.string().max(100).optional(),
  barcode: z.string().max(100).optional(),
  description: z.string().optional(),
  productType: z.enum(['storable', 'consumable', 'service']).default('storable'),
  tracking: z.enum(['none', 'lot', 'serial']).default('none'),
  categoryId: z.string().uuid().optional(),
  uomId: z.string().uuid({ message: 'La unidad de medida es requerida' }),
  purchaseUomId: z.string().uuid().optional(),
  costPrice: z.number().min(0).default(0),
  listPrice: z.number().min(0).default(0),
  valuationMethod: z.enum(['standard', 'fifo', 'average']).default('fifo'),
  weight: z.number().min(0).optional(),
  volume: z.number().min(0).optional(),
  canBeSold: z.boolean().default(true),
  canBePurchased: z.boolean().default(true),
  imageUrl: z.string().url().max(500).optional(),
});

const updateProductSchema = z.object({
  name: z.string().min(1).max(255).optional(),
  barcode: z.string().max(100).optional().nullable(),
  description: z.string().optional().nullable(),
  tracking: z.enum(['none', 'lot', 'serial']).optional(),
  categoryId: z.string().uuid().optional().nullable(),
  uomId: z.string().uuid().optional(),
  purchaseUomId: z.string().uuid().optional().nullable(),
  costPrice: z.number().min(0).optional(),
  listPrice: z.number().min(0).optional(),
  valuationMethod: z.enum(['standard', 'fifo', 'average']).optional(),
  weight: z.number().min(0).optional().nullable(),
  volume: z.number().min(0).optional().nullable(),
  canBeSold: z.boolean().optional(),
  canBePurchased: z.boolean().optional(),
  imageUrl: z.string().url().max(500).optional().nullable(),
  active: z.boolean().optional(),
});

const productQuerySchema = z.object({
  search: z.string().optional(),
  categoryId: z.string().uuid().optional(),
  productType: z.enum(['storable', 'consumable', 'service']).optional(),
  canBeSold: z.coerce.boolean().optional(),
  canBePurchased: z.coerce.boolean().optional(),
  active: z.coerce.boolean().optional(),
  page: z.coerce.number().int().positive().default(1),
  limit: z.coerce.number().int().positive().max(100).default(20),
});

// Warehouse schemas
const createWarehouseSchema = z.object({
  companyId: z.string().uuid({ message: 'La empresa es requerida' }),
  name: z.string().min(1, 'El nombre es requerido').max(255),
  code: z.string().min(1).max(20),
  addressId: z.string().uuid().optional(),
  isDefault: z.boolean().default(false),
});

const updateWarehouseSchema = z.object({
  name: z.string().min(1).max(255).optional(),
  addressId: z.string().uuid().optional().nullable(),
  isDefault: z.boolean().optional(),
  active: z.boolean().optional(),
});

const warehouseQuerySchema = z.object({
  companyId: z.string().uuid().optional(),
  active: z.coerce.boolean().optional(),
  page: z.coerce.number().int().positive().default(1),
  limit: z.coerce.number().int().positive().max(100).default(50),
});

// Location schemas
const createLocationSchema = z.object({
  warehouse_id: z.string().uuid().optional(),
  name: z.string().min(1, 'El nombre es requerido').max(255),
  location_type: z.enum(['internal', 'supplier', 'customer', 'inventory', 'production', 'transit']),
  parent_id: z.string().uuid().optional(),
  is_scrap_location: z.boolean().default(false),
  is_return_location: z.boolean().default(false),
});

const updateLocationSchema = z.object({
  name: z.string().min(1).max(255).optional(),
  parent_id: z.string().uuid().optional().nullable(),
  is_scrap_location: z.boolean().optional(),
  is_return_location: z.boolean().optional(),
  active: z.boolean().optional(),
});

const locationQuerySchema = z.object({
  warehouse_id: z.string().uuid().optional(),
  location_type: z.enum(['internal', 'supplier', 'customer', 'inventory', 'production', 'transit']).optional(),
  active: z.coerce.boolean().optional(),
  page: z.coerce.number().int().positive().default(1),
  limit: z.coerce.number().int().positive().max(100).default(50),
});

// Picking schemas
const stockMoveLineSchema = z.object({
  product_id: z.string().uuid({ message: 'El producto es requerido' }),
  product_uom_id: z.string().uuid({ message: 'La UdM es requerida' }),
  product_qty: z.number().positive({ message: 'La cantidad debe ser mayor a 0' }),
  lot_id: z.string().uuid().optional(),
  location_id: z.string().uuid({ message: 'La ubicación origen es requerida' }),
  location_dest_id: z.string().uuid({ message: 'La ubicación destino es requerida' }),
});

const createPickingSchema = z.object({
  company_id: z.string().uuid({ message: 'La empresa es requerida' }),
  name: z.string().min(1, 'El nombre es requerido').max(100),
  picking_type: z.enum(['incoming', 'outgoing', 'internal']),
  location_id: z.string().uuid({ message: 'La ubicación origen es requerida' }),
  location_dest_id: z.string().uuid({ message: 'La ubicación destino es requerida' }),
  partner_id: z.string().uuid().optional(),
  scheduled_date: z.string().optional(),
  origin: z.string().max(255).optional(),
  notes: z.string().optional(),
  moves: z.array(stockMoveLineSchema).min(1, 'Debe incluir al menos un movimiento'),
});

const pickingQuerySchema = z.object({
  company_id: z.string().uuid().optional(),
  picking_type: z.enum(['incoming', 'outgoing', 'internal']).optional(),
  status: z.enum(['draft', 'waiting', 'confirmed', 'assigned', 'done', 'cancelled']).optional(),
  partner_id: z.string().uuid().optional(),
  date_from: z.string().optional(),
  date_to: z.string().optional(),
  search: z.string().optional(),
  page: z.coerce.number().int().positive().default(1),
  limit: z.coerce.number().int().positive().max(100).default(20),
});

// Lot schemas
const createLotSchema = z.object({
  product_id: z.string().uuid({ message: 'El producto es requerido' }),
  name: z.string().min(1, 'El nombre del lote es requerido').max(100),
  ref: z.string().max(100).optional(),
  manufacture_date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional(),
  expiration_date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional(),
  removal_date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional(),
  alert_date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional(),
  notes: z.string().optional(),
});

const updateLotSchema = z.object({
  ref: z.string().max(100).optional().nullable(),
  manufacture_date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional().nullable(),
  expiration_date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional().nullable(),
  removal_date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional().nullable(),
  alert_date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional().nullable(),
  notes: z.string().optional().nullable(),
});

const lotQuerySchema = z.object({
  product_id: z.string().uuid().optional(),
  expiring_soon: z.coerce.boolean().optional(),
  expired: z.coerce.boolean().optional(),
  search: z.string().optional(),
  page: z.coerce.number().int().positive().default(1),
  limit: z.coerce.number().int().positive().max(100).default(50),
});

// Adjustment schemas
const adjustmentLineSchema = z.object({
  product_id: z.string().uuid({ message: 'El producto es requerido' }),
  location_id: z.string().uuid({ message: 'La ubicación es requerida' }),
  lot_id: z.string().uuid().optional(),
  counted_qty: z.number().min(0),
  uom_id: z.string().uuid({ message: 'La UdM es requerida' }),
  notes: z.string().optional(),
});

const createAdjustmentSchema = z.object({
  company_id: z.string().uuid({ message: 'La empresa es requerida' }),
  location_id: z.string().uuid({ message: 'La ubicación es requerida' }),
  date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional(),
  notes: z.string().optional(),
  lines: z.array(adjustmentLineSchema).min(1, 'Debe incluir al menos una línea'),
});

const updateAdjustmentSchema = z.object({
  location_id: z.string().uuid().optional(),
  date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional(),
  notes: z.string().optional().nullable(),
});

const createAdjustmentLineSchema = z.object({
  product_id: z.string().uuid({ message: 'El producto es requerido' }),
  location_id: z.string().uuid({ message: 'La ubicación es requerida' }),
  lot_id: z.string().uuid().optional(),
  counted_qty: z.number().min(0),
  uom_id: z.string().uuid({ message: 'La UdM es requerida' }),
  notes: z.string().optional(),
});

const updateAdjustmentLineSchema = z.object({
  counted_qty: z.number().min(0).optional(),
  notes: z.string().optional().nullable(),
});

const adjustmentQuerySchema = z.object({
  company_id: z.string().uuid().optional(),
  location_id: z.string().uuid().optional(),
  status: z.enum(['draft', 'confirmed', 'done', 'cancelled']).optional(),
  date_from: z.string().optional(),
  date_to: z.string().optional(),
  search: z.string().optional(),
  page: z.coerce.number().int().positive().default(1),
  limit: z.coerce.number().int().positive().max(100).default(20),
});

class InventoryController {
  // ========== PRODUCTS ==========
  async getProducts(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const queryResult = productQuerySchema.safeParse(req.query);
      if (!queryResult.success) {
        throw new ValidationError('Parámetros de consulta inválidos', queryResult.error.errors);
      }

      const filters = queryResult.data as ProductFilters;
      const result = await productsService.findAll(req.tenantId!, filters);

      res.json({
        success: true,
        data: result.data,
        meta: {
          total: result.total,
          page: filters.page,
          limit: filters.limit,
          totalPages: Math.ceil(result.total / (filters.limit || 20)),
        },
      });
    } catch (error) {
      next(error);
    }
  }

  async getProduct(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const product = await productsService.findById(req.params.id, req.tenantId!);
      res.json({ success: true, data: product });
    } catch (error) {
      next(error);
    }
  }

  async createProduct(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const parseResult = createProductSchema.safeParse(req.body);
      if (!parseResult.success) {
        throw new ValidationError('Datos de producto inválidos', parseResult.error.errors);
      }

      const dto = parseResult.data as CreateProductDto;
      const product = await productsService.create(dto, req.tenantId!, req.user!.userId);

      res.status(201).json({
        success: true,
        data: product,
        message: 'Producto creado exitosamente',
      });
    } catch (error) {
      next(error);
    }
  }

  async updateProduct(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const parseResult = updateProductSchema.safeParse(req.body);
      if (!parseResult.success) {
        throw new ValidationError('Datos de producto inválidos', parseResult.error.errors);
      }

      const dto = parseResult.data as UpdateProductDto;
      const product = await productsService.update(req.params.id, dto, req.tenantId!, req.user!.userId);

      res.json({
        success: true,
        data: product,
        message: 'Producto actualizado exitosamente',
      });
    } catch (error) {
      next(error);
    }
  }

  async deleteProduct(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      await productsService.delete(req.params.id, req.tenantId!, req.user!.userId);
      res.json({ success: true, message: 'Producto eliminado exitosamente' });
    } catch (error) {
      next(error);
    }
  }

  async getProductStock(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const stock = await productsService.getStock(req.params.id, req.tenantId!);
      res.json({ success: true, data: stock });
    } catch (error) {
      next(error);
    }
  }

  // ========== WAREHOUSES ==========
  async getWarehouses(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const queryResult = warehouseQuerySchema.safeParse(req.query);
      if (!queryResult.success) {
        throw new ValidationError('Parámetros de consulta inválidos', queryResult.error.errors);
      }

      const filters: WarehouseFilters = queryResult.data;
      const result = await warehousesService.findAll(req.tenantId!, filters);

      res.json({
        success: true,
        data: result.data,
        meta: {
          total: result.total,
          page: filters.page,
          limit: filters.limit,
          totalPages: Math.ceil(result.total / (filters.limit || 50)),
        },
      });
    } catch (error) {
      next(error);
    }
  }

  async getWarehouse(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const warehouse = await warehousesService.findById(req.params.id, req.tenantId!);
      res.json({ success: true, data: warehouse });
    } catch (error) {
      next(error);
    }
  }

  async createWarehouse(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const parseResult = createWarehouseSchema.safeParse(req.body);
      if (!parseResult.success) {
        throw new ValidationError('Datos de almacén inválidos', parseResult.error.errors);
      }

      const dto: CreateWarehouseDto = parseResult.data;
      const warehouse = await warehousesService.create(dto, req.tenantId!, req.user!.userId);

      res.status(201).json({
        success: true,
        data: warehouse,
        message: 'Almacén creado exitosamente',
      });
    } catch (error) {
      next(error);
    }
  }

  async updateWarehouse(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const parseResult = updateWarehouseSchema.safeParse(req.body);
      if (!parseResult.success) {
        throw new ValidationError('Datos de almacén inválidos', parseResult.error.errors);
      }

      const dto: UpdateWarehouseDto = parseResult.data;
      const warehouse = await warehousesService.update(req.params.id, dto, req.tenantId!, req.user!.userId);

      res.json({
        success: true,
        data: warehouse,
        message: 'Almacén actualizado exitosamente',
      });
    } catch (error) {
      next(error);
    }
  }

  async deleteWarehouse(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      await warehousesService.delete(req.params.id, req.tenantId!);
      res.json({ success: true, message: 'Almacén eliminado exitosamente' });
    } catch (error) {
      next(error);
    }
  }

  async getWarehouseLocations(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const locations = await warehousesService.getLocations(req.params.id, req.tenantId!);
      res.json({ success: true, data: locations });
    } catch (error) {
      next(error);
    }
  }

  async getWarehouseStock(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const stock = await warehousesService.getStock(req.params.id, req.tenantId!);
      res.json({ success: true, data: stock });
    } catch (error) {
      next(error);
    }
  }

  // ========== LOCATIONS ==========
  async getLocations(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const queryResult = locationQuerySchema.safeParse(req.query);
      if (!queryResult.success) {
        throw new ValidationError('Parámetros de consulta inválidos', queryResult.error.errors);
      }

      const filters: LocationFilters = queryResult.data;
      const result = await locationsService.findAll(req.tenantId!, filters);

      res.json({
        success: true,
        data: result.data,
        meta: {
          total: result.total,
          page: filters.page,
          limit: filters.limit,
          totalPages: Math.ceil(result.total / (filters.limit || 50)),
        },
      });
    } catch (error) {
      next(error);
    }
  }

  async getLocation(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const location = await locationsService.findById(req.params.id, req.tenantId!);
      res.json({ success: true, data: location });
    } catch (error) {
      next(error);
    }
  }

  async createLocation(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const parseResult = createLocationSchema.safeParse(req.body);
      if (!parseResult.success) {
        throw new ValidationError('Datos de ubicación inválidos', parseResult.error.errors);
      }

      const dto: CreateLocationDto = parseResult.data;
      const location = await locationsService.create(dto, req.tenantId!, req.user!.userId);

      res.status(201).json({
        success: true,
        data: location,
        message: 'Ubicación creada exitosamente',
      });
    } catch (error) {
      next(error);
    }
  }

  async updateLocation(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const parseResult = updateLocationSchema.safeParse(req.body);
      if (!parseResult.success) {
        throw new ValidationError('Datos de ubicación inválidos', parseResult.error.errors);
      }

      const dto: UpdateLocationDto = parseResult.data;
      const location = await locationsService.update(req.params.id, dto, req.tenantId!, req.user!.userId);

      res.json({
        success: true,
        data: location,
        message: 'Ubicación actualizada exitosamente',
      });
    } catch (error) {
      next(error);
    }
  }

  async getLocationStock(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const stock = await locationsService.getStock(req.params.id, req.tenantId!);
      res.json({ success: true, data: stock });
    } catch (error) {
      next(error);
    }
  }

  // ========== PICKINGS ==========
  async getPickings(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const queryResult = pickingQuerySchema.safeParse(req.query);
      if (!queryResult.success) {
        throw new ValidationError('Parámetros de consulta inválidos', queryResult.error.errors);
      }

      const filters: PickingFilters = queryResult.data;
      const result = await pickingsService.findAll(req.tenantId!, filters);

      res.json({
        success: true,
        data: result.data,
        meta: {
          total: result.total,
          page: filters.page,
          limit: filters.limit,
          totalPages: Math.ceil(result.total / (filters.limit || 20)),
        },
      });
    } catch (error) {
      next(error);
    }
  }

  async getPicking(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const picking = await pickingsService.findById(req.params.id, req.tenantId!);
      res.json({ success: true, data: picking });
    } catch (error) {
      next(error);
    }
  }

  async createPicking(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const parseResult = createPickingSchema.safeParse(req.body);
      if (!parseResult.success) {
        throw new ValidationError('Datos de picking inválidos', parseResult.error.errors);
      }

      const dto: CreatePickingDto = parseResult.data;
      const picking = await pickingsService.create(dto, req.tenantId!, req.user!.userId);

      res.status(201).json({
        success: true,
        data: picking,
        message: 'Picking creado exitosamente',
      });
    } catch (error) {
      next(error);
    }
  }

  async confirmPicking(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const picking = await pickingsService.confirm(req.params.id, req.tenantId!, req.user!.userId);
      res.json({
        success: true,
        data: picking,
        message: 'Picking confirmado exitosamente',
      });
    } catch (error) {
      next(error);
    }
  }

  async validatePicking(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const picking = await pickingsService.validate(req.params.id, req.tenantId!, req.user!.userId);
      res.json({
        success: true,
        data: picking,
        message: 'Picking validado exitosamente',
      });
    } catch (error) {
      next(error);
    }
  }

  async cancelPicking(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const picking = await pickingsService.cancel(req.params.id, req.tenantId!, req.user!.userId);
      res.json({
        success: true,
        data: picking,
        message: 'Picking cancelado exitosamente',
      });
    } catch (error) {
      next(error);
    }
  }

  async deletePicking(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      await pickingsService.delete(req.params.id, req.tenantId!);
      res.json({ success: true, message: 'Picking eliminado exitosamente' });
    } catch (error) {
      next(error);
    }
  }

  // ========== LOTS ==========
  async getLots(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const queryResult = lotQuerySchema.safeParse(req.query);
      if (!queryResult.success) {
        throw new ValidationError('Parámetros de consulta inválidos', queryResult.error.errors);
      }

      const filters: LotFilters = queryResult.data;
      const result = await lotsService.findAll(req.tenantId!, filters);

      res.json({
        success: true,
        data: result.data,
        meta: {
          total: result.total,
          page: filters.page,
          limit: filters.limit,
          totalPages: Math.ceil(result.total / (filters.limit || 50)),
        },
      });
    } catch (error) {
      next(error);
    }
  }

  async getLot(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const lot = await lotsService.findById(req.params.id, req.tenantId!);
      res.json({ success: true, data: lot });
    } catch (error) {
      next(error);
    }
  }

  async createLot(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const parseResult = createLotSchema.safeParse(req.body);
      if (!parseResult.success) {
        throw new ValidationError('Datos de lote inválidos', parseResult.error.errors);
      }

      const dto: CreateLotDto = parseResult.data;
      const lot = await lotsService.create(dto, req.tenantId!, req.user!.userId);

      res.status(201).json({
        success: true,
        data: lot,
        message: 'Lote creado exitosamente',
      });
    } catch (error) {
      next(error);
    }
  }

  async updateLot(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const parseResult = updateLotSchema.safeParse(req.body);
      if (!parseResult.success) {
        throw new ValidationError('Datos de lote inválidos', parseResult.error.errors);
      }

      const dto: UpdateLotDto = parseResult.data;
      const lot = await lotsService.update(req.params.id, dto, req.tenantId!);

      res.json({
        success: true,
        data: lot,
        message: 'Lote actualizado exitosamente',
      });
    } catch (error) {
      next(error);
    }
  }

  async getLotMovements(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const movements = await lotsService.getMovements(req.params.id, req.tenantId!);
      res.json({ success: true, data: movements });
    } catch (error) {
      next(error);
    }
  }

  async deleteLot(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      await lotsService.delete(req.params.id, req.tenantId!);
      res.json({ success: true, message: 'Lote eliminado exitosamente' });
    } catch (error) {
      next(error);
    }
  }

  // ========== ADJUSTMENTS ==========
  async getAdjustments(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const queryResult = adjustmentQuerySchema.safeParse(req.query);
      if (!queryResult.success) {
        throw new ValidationError('Parámetros de consulta inválidos', queryResult.error.errors);
      }

      const filters: AdjustmentFilters = queryResult.data;
      const result = await adjustmentsService.findAll(req.tenantId!, filters);

      res.json({
        success: true,
        data: result.data,
        meta: {
          total: result.total,
          page: filters.page,
          limit: filters.limit,
          totalPages: Math.ceil(result.total / (filters.limit || 20)),
        },
      });
    } catch (error) {
      next(error);
    }
  }

  async getAdjustment(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const adjustment = await adjustmentsService.findById(req.params.id, req.tenantId!);
      res.json({ success: true, data: adjustment });
    } catch (error) {
      next(error);
    }
  }

  async createAdjustment(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const parseResult = createAdjustmentSchema.safeParse(req.body);
      if (!parseResult.success) {
        throw new ValidationError('Datos de ajuste inválidos', parseResult.error.errors);
      }

      const dto: CreateAdjustmentDto = parseResult.data;
      const adjustment = await adjustmentsService.create(dto, req.tenantId!, req.user!.userId);

      res.status(201).json({
        success: true,
        data: adjustment,
        message: 'Ajuste de inventario creado exitosamente',
      });
    } catch (error) {
      next(error);
    }
  }

  async updateAdjustment(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const parseResult = updateAdjustmentSchema.safeParse(req.body);
      if (!parseResult.success) {
        throw new ValidationError('Datos de ajuste inválidos', parseResult.error.errors);
      }

      const dto: UpdateAdjustmentDto = parseResult.data;
      const adjustment = await adjustmentsService.update(req.params.id, dto, req.tenantId!, req.user!.userId);

      res.json({
        success: true,
        data: adjustment,
        message: 'Ajuste de inventario actualizado exitosamente',
      });
    } catch (error) {
      next(error);
    }
  }

  async addAdjustmentLine(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const parseResult = createAdjustmentLineSchema.safeParse(req.body);
      if (!parseResult.success) {
        throw new ValidationError('Datos de línea inválidos', parseResult.error.errors);
      }

      const dto: CreateAdjustmentLineDto = parseResult.data;
      const line = await adjustmentsService.addLine(req.params.id, dto, req.tenantId!);

      res.status(201).json({
        success: true,
        data: line,
        message: 'Línea agregada exitosamente',
      });
    } catch (error) {
      next(error);
    }
  }

  async updateAdjustmentLine(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const parseResult = updateAdjustmentLineSchema.safeParse(req.body);
      if (!parseResult.success) {
        throw new ValidationError('Datos de línea inválidos', parseResult.error.errors);
      }

      const dto: UpdateAdjustmentLineDto = parseResult.data;
      const line = await adjustmentsService.updateLine(req.params.id, req.params.lineId, dto, req.tenantId!);

      res.json({
        success: true,
        data: line,
        message: 'Línea actualizada exitosamente',
      });
    } catch (error) {
      next(error);
    }
  }

  async removeAdjustmentLine(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      await adjustmentsService.removeLine(req.params.id, req.params.lineId, req.tenantId!);
      res.json({ success: true, message: 'Línea eliminada exitosamente' });
    } catch (error) {
      next(error);
    }
  }

  async confirmAdjustment(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const adjustment = await adjustmentsService.confirm(req.params.id, req.tenantId!, req.user!.userId);
      res.json({
        success: true,
        data: adjustment,
        message: 'Ajuste confirmado exitosamente',
      });
    } catch (error) {
      next(error);
    }
  }

  async validateAdjustment(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const adjustment = await adjustmentsService.validate(req.params.id, req.tenantId!, req.user!.userId);
      res.json({
        success: true,
        data: adjustment,
        message: 'Ajuste validado exitosamente. Stock actualizado.',
      });
    } catch (error) {
      next(error);
    }
  }

  async cancelAdjustment(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const adjustment = await adjustmentsService.cancel(req.params.id, req.tenantId!, req.user!.userId);
      res.json({
        success: true,
        data: adjustment,
        message: 'Ajuste cancelado exitosamente',
      });
    } catch (error) {
      next(error);
    }
  }

  async deleteAdjustment(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      await adjustmentsService.delete(req.params.id, req.tenantId!);
      res.json({ success: true, message: 'Ajuste eliminado exitosamente' });
    } catch (error) {
      next(error);
    }
  }
}

export const inventoryController = new InventoryController();
