/**
 * RM Dimension Validation Service
 * Provides validation functions for RM products requiring dimensions
 * Implements unit conversion utilities and dimension sufficiency checking
 */

/**
 * Supported units and their conversion factors to meters
 */
const UNIT_CONVERSIONS = {
  'm': 1.0,           // Base unit (meters)
  'cm': 0.01,         // Centimeters to meters
  'inch': 0.0254      // Inches to meters
};

/**
 * Validates if a product requires dimension tracking
 * @param {Object} product - Product object
 * @returns {Object} Validation result
 */
function validateProductDimensionRequirement(product) {
  if (!product) {
    return {
      isValid: false,
      error: 'Product is required'
    };
  }

  // Only RM products can have dimension tracking
  if (product.product_type !== 'RM') {
    return {
      isValid: true,
      requiresDimensions: false,
      message: 'Non-RM products do not require dimension tracking'
    };
  }

  // RM products can be dimension-based or special items (quantity-based)
  // Special items RM (track_by_dimensions = false) don't require dimensions
  if (!product.track_by_dimensions) {
    return {
      isValid: true,
      requiresDimensions: false,
      message: 'Special items RM (zippers, buttons, etc.) use quantity-based tracking, not dimensions'
    };
  }

  // Dimension-based RM products must have a valid unit of measure
  if (!product.unit_of_measure || !UNIT_CONVERSIONS[product.unit_of_measure]) {
    return {
      isValid: false,
      error: 'Dimension-based RM products must have a valid unit_of_measure (inch, cm, m)'
    };
  }

  return {
    isValid: true,
    requiresDimensions: true,
    unit: product.unit_of_measure
  };
}

/**
 * Validates dimension values
 * @param {number} length - Length value
 * @param {number} width - Width value
 * @param {string} unit - Unit of measure
 * @returns {Object} Validation result
 */
function validateDimensions(length, width, unit) {
  const errors = [];

  // Check if dimensions are provided
  if (length === null || length === undefined) {
    errors.push('Length is required');
  }
  if (width === null || width === undefined) {
    errors.push('Width is required');
  }
  if (!unit) {
    errors.push('Unit is required');
  }

  // Check if unit is valid
  if (unit && !UNIT_CONVERSIONS[unit]) {
    errors.push(`Invalid unit: ${unit}. Supported units: ${Object.keys(UNIT_CONVERSIONS).join(', ')}`);
  }

  // Check if dimensions are positive
  if (length !== null && length !== undefined && length <= 0) {
    errors.push('Length must be positive');
  }
  if (width !== null && width !== undefined && width <= 0) {
    errors.push('Width must be positive');
  }

  // Check for reasonable dimension limits (prevent extremely large values)
  const MAX_DIMENSION = 1000; // 1000 units in any system
  if (length > MAX_DIMENSION) {
    errors.push(`Length cannot exceed ${MAX_DIMENSION} ${unit}`);
  }
  if (width > MAX_DIMENSION) {
    errors.push(`Width cannot exceed ${MAX_DIMENSION} ${unit}`);
  }

  return {
    isValid: errors.length === 0,
    errors: errors.length > 0 ? errors : undefined
  };
}

/**
 * Converts dimensions from one unit to another
 * @param {number} value - Dimension value
 * @param {string} fromUnit - Source unit
 * @param {string} toUnit - Target unit
 * @returns {Object} Conversion result
 */
function convertUnit(value, fromUnit, toUnit) {
  if (!UNIT_CONVERSIONS[fromUnit]) {
    return {
      isValid: false,
      error: `Invalid source unit: ${fromUnit}`
    };
  }

  if (!UNIT_CONVERSIONS[toUnit]) {
    return {
      isValid: false,
      error: `Invalid target unit: ${toUnit}`
    };
  }

  if (value === null || value === undefined || value < 0) {
    return {
      isValid: false,
      error: 'Value must be a non-negative number'
    };
  }

  // Convert to meters first, then to target unit
  const valueInMeters = value * UNIT_CONVERSIONS[fromUnit];
  const convertedValue = valueInMeters / UNIT_CONVERSIONS[toUnit];

  return {
    isValid: true,
    value: convertedValue,
    originalValue: value,
    originalUnit: fromUnit,
    targetUnit: toUnit
  };
}

/**
 * Converts dimensions object from one unit to another
 * @param {Object} dimensions - Dimensions object {length, width, unit}
 * @param {string} toUnit - Target unit
 * @returns {Object} Conversion result
 */
function convertDimensions(dimensions, toUnit) {
  if (!dimensions || !dimensions.length || !dimensions.width || !dimensions.unit) {
    return {
      isValid: false,
      error: 'Dimensions object must have length, width, and unit properties'
    };
  }

  const lengthResult = convertUnit(dimensions.length, dimensions.unit, toUnit);
  if (!lengthResult.isValid) {
    return lengthResult;
  }

  const widthResult = convertUnit(dimensions.width, dimensions.unit, toUnit);
  if (!widthResult.isValid) {
    return widthResult;
  }

  return {
    isValid: true,
    dimensions: {
      length: lengthResult.value,
      width: widthResult.value,
      unit: toUnit
    },
    originalDimensions: dimensions
  };
}

/**
 * Calculates area from dimensions
 * @param {number} length - Length value
 * @param {number} width - Width value
 * @param {string} unit - Unit of measure
 * @returns {Object} Area calculation result
 */
function calculateArea(length, width, unit) {
  const validation = validateDimensions(length, width, unit);
  if (!validation.isValid) {
    return {
      isValid: false,
      errors: validation.errors
    };
  }

  const area = length * width;
  return {
    isValid: true,
    area: area,
    unit: unit,
    areaUnit: `${unit}²`
  };
}

/**
 * Checks if available dimensions can satisfy required dimensions
 * @param {Object} available - Available dimensions {length, width, unit}
 * @param {Object} required - Required dimensions {length, width, unit}
 * @returns {Object} Sufficiency check result
 */
function checkDimensionSufficiency(available, required) {
  // Validate inputs
  const availableValidation = validateDimensions(available.length, available.width, available.unit);
  if (!availableValidation.isValid) {
    return {
      isValid: false,
      error: 'Invalid available dimensions',
      details: availableValidation.errors
    };
  }

  const requiredValidation = validateDimensions(required.length, required.width, required.unit);
  if (!requiredValidation.isValid) {
    return {
      isValid: false,
      error: 'Invalid required dimensions',
      details: requiredValidation.errors
    };
  }

  // Convert required dimensions to available unit for comparison
  const convertedRequired = convertDimensions(required, available.unit);
  if (!convertedRequired.isValid) {
    return {
      isValid: false,
      error: 'Unit conversion failed',
      details: convertedRequired.error
    };
  }

  const reqDim = convertedRequired.dimensions;
  
  // Check if available dimensions can accommodate required dimensions
  const lengthSufficient = available.length >= reqDim.length;
  const widthSufficient = available.width >= reqDim.width;
  const canFit = lengthSufficient && widthSufficient;

  // Calculate remaining dimensions if it fits
  let remaining = null;
  if (canFit) {
    remaining = {
      length: available.length - reqDim.length,
      width: available.width - reqDim.width,
      unit: available.unit
    };
  }

  return {
    isValid: true,
    canFit: canFit,
    lengthSufficient: lengthSufficient,
    widthSufficient: widthSufficient,
    availableDimensions: available,
    requiredDimensions: reqDim,
    remainingDimensions: remaining,
    shortfall: canFit ? null : {
      length: Math.max(0, reqDim.length - available.length),
      width: Math.max(0, reqDim.width - available.width),
      unit: available.unit
    }
  };
}

/**
 * Validates multiple dimension scenarios for a product
 * @param {Array} dimensionSets - Array of dimension objects
 * @param {string} productUnit - Product's unit of measure
 * @returns {Object} Validation result
 */
function validateMultipleDimensionSets(dimensionSets, productUnit) {
  if (!Array.isArray(dimensionSets)) {
    return {
      isValid: false,
      error: 'Dimension sets must be an array'
    };
  }

  if (dimensionSets.length === 0) {
    return {
      isValid: false,
      error: 'At least one dimension set is required'
    };
  }

  const validationResults = [];
  let totalArea = 0;

  for (let i = 0; i < dimensionSets.length; i++) {
    const dimSet = dimensionSets[i];
    
    // Validate individual dimension set
    const validation = validateDimensions(dimSet.length, dimSet.width, dimSet.unit || productUnit);
    if (!validation.isValid) {
      return {
        isValid: false,
        error: `Invalid dimension set at index ${i}`,
        details: validation.errors
      };
    }

    // Convert to product unit for consistency
    const converted = convertDimensions({
      length: dimSet.length,
      width: dimSet.width,
      unit: dimSet.unit || productUnit
    }, productUnit);

    if (!converted.isValid) {
      return {
        isValid: false,
        error: `Unit conversion failed for dimension set at index ${i}`,
        details: converted.error
      };
    }

    const area = converted.dimensions.length * converted.dimensions.width;
    const quantity = dimSet.quantity !== undefined ? dimSet.quantity : 1;
    
    // Validate quantity
    if (quantity <= 0) {
      return {
        isValid: false,
        error: `Invalid quantity at index ${i}: quantity must be greater than 0`,
        details: `Quantity: ${quantity}`
      };
    }
    
    validationResults.push({
      index: i,
      originalDimensions: dimSet,
      normalizedDimensions: converted.dimensions,
      area: area,
      quantity: quantity,
      totalArea: area * quantity
    });

    totalArea += area * quantity;
  }

  return {
    isValid: true,
    dimensionSets: validationResults,
    totalArea: totalArea,
    unit: productUnit
  };
}

module.exports = {
  validateProductDimensionRequirement,
  validateDimensions,
  convertUnit,
  convertDimensions,
  calculateArea,
  checkDimensionSufficiency,
  validateMultipleDimensionSets,
  UNIT_CONVERSIONS
};