/**
 * Product Variant Controller
 * API endpoints para gestion de variantes de productos
 *
 * @module Products
 * @prefix /api/v1/products/:productId/variants
 */

import { Router, Request, Response, NextFunction } from 'express';
import {
  ProductVariantService,
  CreateProductVariantDto,
  UpdateProductVariantDto
} from '../services/product-variant.service';
import { ProductService } from '../services/product.service';

const router = Router({ mergeParams: true });
const variantService = new ProductVariantService();
const productService = new ProductService();

/**
 * GET /api/v1/products/:productId/variants
 * Lista todas las variantes de un producto
 */
router.get('/', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const { productId } = req.params;
    const { isActive, search } = req.query;

    const product = await productService.findById(productId, tenantId);
    if (!product) {
      return res.status(404).json({ error: 'Producto no encontrado' });
    }

    const variants = await variantService.findAll({
      tenantId,
      productId,
      isActive: isActive === 'true' ? true : isActive === 'false' ? false : undefined,
      search: search as string,
    });

    return res.json({
      success: true,
      data: variants,
      count: variants.length,
    });
  } catch (error) {
    return next(error);
  }
});

/**
 * GET /api/v1/products/:productId/variants/total-stock
 * Obtiene el stock total de todas las variantes
 */
router.get('/total-stock', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const { productId } = req.params;

    const product = await productService.findById(productId, tenantId);
    if (!product) {
      return res.status(404).json({ error: 'Producto no encontrado' });
    }

    const totalStock = await variantService.getTotalStock(productId, tenantId);

    return res.json({
      success: true,
      data: { totalStock },
    });
  } catch (error) {
    return next(error);
  }
});

/**
 * GET /api/v1/products/:productId/variants/:id
 * Obtiene una variante por ID
 */
router.get('/:id', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const variant = await variantService.findById(req.params.id, tenantId);
    if (!variant || variant.productId !== req.params.productId) {
      return res.status(404).json({ error: 'Variante no encontrada' });
    }

    return res.json({ success: true, data: variant });
  } catch (error) {
    return next(error);
  }
});

/**
 * POST /api/v1/products/:productId/variants
 * Crea una nueva variante
 */
router.post('/', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const { productId } = req.params;

    const product = await productService.findById(productId, tenantId);
    if (!product) {
      return res.status(404).json({ error: 'Producto no encontrado' });
    }

    const data: CreateProductVariantDto = {
      ...req.body,
      productId,
      tenantId,
      createdBy: (req as any).user?.id,
    };

    if (!data.sku || !data.name) {
      return res.status(400).json({
        error: 'sku y name son requeridos'
      });
    }

    const existingBySku = await variantService.findBySku(data.sku, tenantId);
    if (existingBySku) {
      return res.status(409).json({ error: 'Ya existe una variante con ese SKU' });
    }

    if (data.barcode) {
      const existingByBarcode = await variantService.findByBarcode(data.barcode, tenantId);
      if (existingByBarcode) {
        return res.status(409).json({ error: 'Ya existe una variante con ese codigo de barras' });
      }
    }

    const variant = await variantService.create(data);
    return res.status(201).json({ success: true, data: variant });
  } catch (error) {
    return next(error);
  }
});

/**
 * POST /api/v1/products/:productId/variants/bulk
 * Crea multiples variantes en lote
 */
router.post('/bulk', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const { productId } = req.params;
    const { variants } = req.body;

    const product = await productService.findById(productId, tenantId);
    if (!product) {
      return res.status(404).json({ error: 'Producto no encontrado' });
    }

    if (!variants || !Array.isArray(variants) || variants.length === 0) {
      return res.status(400).json({ error: 'variants array is required' });
    }

    const variantsData: CreateProductVariantDto[] = variants.map((v: any) => ({
      ...v,
      productId,
      tenantId,
      createdBy: (req as any).user?.id,
    }));

    const createdVariants = await variantService.bulkCreate(variantsData);

    return res.status(201).json({
      success: true,
      data: createdVariants,
      count: createdVariants.length,
    });
  } catch (error) {
    return next(error);
  }
});

/**
 * PATCH /api/v1/products/:productId/variants/:id
 * Actualiza una variante
 */
router.patch('/:id', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const data: UpdateProductVariantDto = {
      ...req.body,
      updatedBy: (req as any).user?.id,
    };

    if (data.sku) {
      const existing = await variantService.findBySku(data.sku, tenantId);
      if (existing && existing.id !== req.params.id) {
        return res.status(409).json({ error: 'Ya existe una variante con ese SKU' });
      }
    }

    if (data.barcode) {
      const existing = await variantService.findByBarcode(data.barcode, tenantId);
      if (existing && existing.id !== req.params.id) {
        return res.status(409).json({ error: 'Ya existe una variante con ese codigo de barras' });
      }
    }

    const variant = await variantService.update(req.params.id, tenantId, data);
    if (!variant || variant.productId !== req.params.productId) {
      return res.status(404).json({ error: 'Variante no encontrada' });
    }

    return res.json({ success: true, data: variant });
  } catch (error) {
    return next(error);
  }
});

/**
 * PATCH /api/v1/products/:productId/variants/:id/stock
 * Actualiza el stock de una variante
 */
router.patch('/:id/stock', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const { quantity, operation } = req.body;

    if (quantity === undefined) {
      return res.status(400).json({ error: 'quantity es requerido' });
    }

    const existing = await variantService.findById(req.params.id, tenantId);
    if (!existing || existing.productId !== req.params.productId) {
      return res.status(404).json({ error: 'Variante no encontrada' });
    }

    const variant = await variantService.updateStock(
      req.params.id,
      tenantId,
      quantity,
      operation || 'set'
    );

    if (!variant) {
      return res.status(404).json({ error: 'Variante no encontrada' });
    }

    return res.json({ success: true, data: variant });
  } catch (error) {
    return next(error);
  }
});

/**
 * PATCH /api/v1/products/:productId/variants/:id/price-extra
 * Actualiza el precio extra de una variante
 */
router.patch('/:id/price-extra', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const { priceExtra } = req.body;

    if (priceExtra === undefined) {
      return res.status(400).json({ error: 'priceExtra es requerido' });
    }

    const existing = await variantService.findById(req.params.id, tenantId);
    if (!existing || existing.productId !== req.params.productId) {
      return res.status(404).json({ error: 'Variante no encontrada' });
    }

    const variant = await variantService.updatePriceExtra(req.params.id, tenantId, priceExtra);
    if (!variant) {
      return res.status(404).json({ error: 'Variante no encontrada' });
    }

    return res.json({ success: true, data: variant });
  } catch (error) {
    return next(error);
  }
});

/**
 * PATCH /api/v1/products/:productId/variants/:id/toggle-active
 * Activa/desactiva una variante
 */
router.patch('/:id/toggle-active', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const existing = await variantService.findById(req.params.id, tenantId);
    if (!existing || existing.productId !== req.params.productId) {
      return res.status(404).json({ error: 'Variante no encontrada' });
    }

    const variant = await variantService.toggleActive(req.params.id, tenantId);
    if (!variant) {
      return res.status(404).json({ error: 'Variante no encontrada' });
    }

    return res.json({ success: true, data: variant });
  } catch (error) {
    return next(error);
  }
});

/**
 * DELETE /api/v1/products/:productId/variants/:id
 * Elimina una variante
 */
router.delete('/:id', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const existing = await variantService.findById(req.params.id, tenantId);
    if (!existing || existing.productId !== req.params.productId) {
      return res.status(404).json({ error: 'Variante no encontrada' });
    }

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

    return res.json({ success: true, message: 'Variante eliminada' });
  } catch (error) {
    return next(error);
  }
});

export default router;
