import { body } from 'express-validator';

const TRACKING_TYPES = ['QUANTITY', 'WEIGHT', 'VOLUME', 'SIZE'];

const BARCODE_FORMAT = /^[A-Za-z0-9\-_]{3,64}$/;

const validateVariants = (value) => {
  let arr = value;
  if (typeof value === 'string') {
    try {
      arr = JSON.parse(value);
    } catch {
      throw new Error('Invalid variants data');
    }
  }
  if (!Array.isArray(arr)) throw new Error('Variants must be an array');
  const barcodes = [];
  const variantIds = [];
  for (const v of arr) {
    if (v.currentStock !== undefined && Number(v.currentStock) < 0) {
      throw new Error('Variant stock cannot be negative');
    }
    if (v.purchasePrice !== undefined && Number(v.purchasePrice) < 0) {
      throw new Error('Variant purchase price cannot be negative');
    }
    if (v.sellingPrice !== undefined && Number(v.sellingPrice) < 0) {
      throw new Error('Variant selling price cannot be negative');
    }
    if (v.lowStockThreshold !== undefined && Number(v.lowStockThreshold) < 0) {
      throw new Error('Variant low stock threshold cannot be negative');
    }
    const barcode = typeof v.barcode === 'string' ? v.barcode.trim() : '';
    if (barcode) {
      if (!BARCODE_FORMAT.test(barcode)) {
        throw new Error(`Invalid barcode format: ${barcode}. Use 3-64 letters, numbers, dashes or underscores.`);
      }
      if (barcodes.includes(barcode)) {
        throw new Error(`Duplicate barcode in variants: ${barcode}`);
      }
      barcodes.push(barcode);
    }
    const vid = typeof v.variantId === 'string' ? v.variantId.trim() : '';
    if (vid) {
      if (variantIds.includes(vid)) {
        throw new Error('Duplicate variant identifiers in variants. Save again to regenerate them.');
      }
      variantIds.push(vid);
    }
  }
  return true;
};

export const createProductValidator = [
  body('name').trim().notEmpty().withMessage('Product name is required'),
  body('category').trim().notEmpty().withMessage('Category is required'),
  body('purchasePrice').optional().isFloat({ min: 0 }).withMessage('Purchase price must be a non-negative number'),
  body('sellingPrice').optional().isFloat({ min: 0 }).withMessage('Selling price must be a non-negative number'),
  body('trackingType').optional().isIn(TRACKING_TYPES).withMessage('Invalid tracking type'),
  body('unit').optional().trim(),
  body('sizeSystem').optional().isIn(['CLOTHING', 'SHOES', '']).withMessage('Invalid size system'),
  body('currentStock').optional().isInt({ min: 0 }).withMessage('Stock must be a non-negative integer'),
  body('lowStockThreshold').optional().isInt({ min: 0 }).withMessage('Threshold must be a non-negative integer'),
  body('variants').optional().custom(validateVariants),
  body('discountRules').optional().custom((value) => {
    if (typeof value === 'string') {
      try {
        JSON.parse(value);
      } catch {
        throw new Error('Invalid discount rules data');
      }
    }
    return true;
  }),
];

export const updateProductValidator = [
  body('name').optional().trim().notEmpty().withMessage('Product name cannot be empty'),
  body('category').optional().trim().notEmpty().withMessage('Category cannot be empty'),
  body('purchasePrice').optional().isFloat({ min: 0 }).withMessage('Purchase price must be a non-negative number'),
  body('sellingPrice').optional().isFloat({ min: 0 }).withMessage('Selling price must be a non-negative number'),
  body('trackingType').optional().isIn(TRACKING_TYPES).withMessage('Invalid tracking type'),
  body('unit').optional().trim(),
  body('sizeSystem').optional().isIn(['CLOTHING', 'SHOES', '']).withMessage('Invalid size system'),
  body('currentStock').optional().isInt({ min: 0 }).withMessage('Stock must be a non-negative integer'),
  body('lowStockThreshold').optional().isInt({ min: 0 }).withMessage('Threshold must be a non-negative integer'),
  body('variants').optional().custom(validateVariants),
  body('discountRules').optional().custom((value) => {
    if (typeof value === 'string') {
      try {
        JSON.parse(value);
      } catch {
        throw new Error('Invalid discount rules data');
      }
    }
    return true;
  }),
];