/**
 * Product Controller
 * API endpoints para gestion de productos comerciales
 *
 * @module Products
 * @prefix /api/v1/products
 */

import { Router, Request, Response, NextFunction } from 'express';
import {
  ProductService,
  CreateProductDto,
  UpdateProductDto
} from '../services/product.service';

const router = Router();
const productService = new ProductService();

/**
 * GET /api/v1/products
 * Lista todos los productos del tenant (paginado)
 */
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 { categoryId, productType, isActive, isSellable, isPurchasable, search, tags, limit, offset } = req.query;

    const result = await productService.findAll({
      tenantId,
      categoryId: categoryId as string,
      productType: productType as 'product' | 'service' | 'consumable' | 'kit',
      isActive: isActive === 'true' ? true : isActive === 'false' ? false : undefined,
      isSellable: isSellable === 'true' ? true : isSellable === 'false' ? false : undefined,
      isPurchasable: isPurchasable === 'true' ? true : isPurchasable === 'false' ? false : undefined,
      search: search as string,
      tags: tags ? (tags as string).split(',') : undefined,
      limit: limit ? parseInt(limit as string, 10) : undefined,
      offset: offset ? parseInt(offset as string, 10) : undefined,
    });

    return res.json({
      success: true,
      data: result.data,
      total: result.total,
      limit: result.limit,
      offset: result.offset,
    });
  } catch (error) {
    return next(error);
  }
});

/**
 * GET /api/v1/products/search
 * Busqueda rapida de productos
 */
router.get('/search', 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 { q, limit } = req.query;
    if (!q) {
      return res.status(400).json({ error: 'Query parameter q is required' });
    }

    const products = await productService.searchProducts(
      tenantId,
      q as string,
      limit ? parseInt(limit as string, 10) : 20
    );

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

/**
 * GET /api/v1/products/low-stock
 * Obtiene productos con stock bajo
 */
router.get('/low-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 products = await productService.getLowStockProducts(tenantId);

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

/**
 * GET /api/v1/products/:id
 * Obtiene un producto 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 product = await productService.findById(req.params.id, tenantId);
    if (!product) {
      return res.status(404).json({ error: 'Producto no encontrado' });
    }

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

/**
 * GET /api/v1/products/sku/:sku
 * Obtiene un producto por SKU
 */
router.get('/sku/:sku', 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 product = await productService.findBySku(req.params.sku, tenantId);
    if (!product) {
      return res.status(404).json({ error: 'Producto no encontrado' });
    }

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

/**
 * GET /api/v1/products/barcode/:barcode
 * Obtiene un producto por codigo de barras
 */
router.get('/barcode/:barcode', 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 product = await productService.findByBarcode(req.params.barcode, tenantId);
    if (!product) {
      return res.status(404).json({ error: 'Producto no encontrado' });
    }

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

/**
 * POST /api/v1/products
 * Crea un nuevo producto
 */
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 data: CreateProductDto = {
      ...req.body,
      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 productService.findBySku(data.sku, tenantId);
    if (existingBySku) {
      return res.status(409).json({ error: 'Ya existe un producto con ese SKU' });
    }

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

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

/**
 * PATCH /api/v1/products/:id
 * Actualiza un producto
 */
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: UpdateProductDto = {
      ...req.body,
      updatedBy: (req as any).user?.id,
    };

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

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

    const product = await productService.update(req.params.id, tenantId, data);
    if (!product) {
      return res.status(404).json({ error: 'Producto no encontrado' });
    }

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

/**
 * PATCH /api/v1/products/:id/prices
 * Actualiza los precios de un producto
 */
router.patch('/:id/prices', 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 { salePrice, costPrice, minSalePrice } = req.body;

    const product = await productService.updatePrices(req.params.id, tenantId, {
      salePrice,
      costPrice,
      minSalePrice,
    });

    if (!product) {
      return res.status(404).json({ error: 'Producto no encontrado' });
    }

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

/**
 * PATCH /api/v1/products/:id/stock-settings
 * Actualiza la configuracion de stock de un producto
 */
router.patch('/:id/stock-settings', 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 { minStock, maxStock, reorderPoint, reorderQuantity } = req.body;

    const product = await productService.updateStock(req.params.id, tenantId, {
      minStock,
      maxStock,
      reorderPoint,
      reorderQuantity,
    });

    if (!product) {
      return res.status(404).json({ error: 'Producto no encontrado' });
    }

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

/**
 * PATCH /api/v1/products/:id/toggle-active
 * Activa/desactiva un producto
 */
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 product = await productService.toggleActive(req.params.id, tenantId);
    if (!product) {
      return res.status(404).json({ error: 'Producto no encontrado' });
    }

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

/**
 * POST /api/v1/products/bulk-update-prices
 * Actualiza precios en lote
 */
router.post('/bulk-update-prices', 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 { updates } = req.body;
    if (!updates || !Array.isArray(updates)) {
      return res.status(400).json({ error: 'updates array is required' });
    }

    const updated = await productService.bulkUpdatePrices(tenantId, updates);

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

/**
 * DELETE /api/v1/products/:id
 * Elimina un producto (soft delete)
 */
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 deleted = await productService.delete(req.params.id, tenantId);
    if (!deleted) {
      return res.status(404).json({ error: 'Producto no encontrado' });
    }

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

export default router;
