/**
 * Standalone Property Test: Multi-Dimension Independence
 * Tests that multiple dimension scenarios are processed independently
 * Property 12: Multi-Dimension Independence
 * Validates: Requirements 7.1, 7.2
 */

const grnProcessingService = require('./services/grnProcessingService');
const dimensionValidationService = require('./services/dimensionValidationService');

/**
 * Property 12: Multi-Dimension Independence
 * When processing multiple dimension sets for the same product,
 * each dimension set should be processed independently without affecting others
 */
function testMultiDimensionIndependence() {
  console.log('🧪 Testing Property 12: Multi-Dimension Independence');
  
  let passCount = 0;
  let failCount = 0;
  const iterations = 100;
  
  for (let i = 0; i < iterations; i++) {
    try {
      // Generate random product data
      const product = {
        id: Math.floor(Math.random() * 1000) + 1,
        name: `Cotton Fabric ${i}`,
        product_type: 'RM',
        track_by_dimensions: true,
        unit_of_measure: 'cm'
      };
      
      // Generate multiple dimension sets for the same product
      const dimensionSets = [];
      const numSets = Math.floor(Math.random() * 4) + 2; // 2-5 dimension sets
      
      for (let j = 0; j < numSets; j++) {
        dimensionSets.push({
          length: Math.random() * 500 + 50, // 50-550 cm
          width: Math.random() * 300 + 30,  // 30-330 cm
          unit: 'cm',
          quantity: Math.floor(Math.random() * 5) + 1 // 1-5 pieces
        });
      }
      
      // Validate multiple dimension sets
      const validation = dimensionValidationService.validateMultipleDimensionSets(
        dimensionSets,
        product.unit_of_measure
      );
      
      if (!validation.isValid) {
        console.log(`❌ Iteration ${i + 1}: Validation failed - ${validation.error}`);
        failCount++;
        continue;
      }
      
      // Test independence: each dimension set should be processed separately
      let totalExpectedPieces = 0;
      let totalExpectedArea = 0;
      
      for (const dimSet of validation.dimensionSets) {
        totalExpectedPieces += dimSet.quantity;
        totalExpectedArea += dimSet.totalArea;
        
        // Verify each dimension set maintains its properties
        if (dimSet.area !== dimSet.normalizedDimensions.length * dimSet.normalizedDimensions.width) {
          throw new Error(`Area calculation mismatch for dimension set ${dimSet.index}`);
        }
        
        // Verify quantity independence
        if (dimSet.quantity < 1) {
          throw new Error(`Invalid quantity for dimension set ${dimSet.index}`);
        }
        
        // Verify dimension independence (no cross-contamination)
        if (dimSet.normalizedDimensions.unit !== product.unit_of_measure) {
          throw new Error(`Unit conversion failed for dimension set ${dimSet.index}`);
        }
      }
      
      // Verify total calculations
      if (Math.abs(validation.totalArea - totalExpectedArea) > 0.001) {
        throw new Error(`Total area calculation mismatch: expected ${totalExpectedArea}, got ${validation.totalArea}`);
      }
      
      // Test that modifying one dimension set doesn't affect others
      const originalSets = JSON.parse(JSON.stringify(validation.dimensionSets));
      
      // Simulate processing each set independently
      for (let k = 0; k < validation.dimensionSets.length; k++) {
        const currentSet = validation.dimensionSets[k];
        
        // Verify this set hasn't been affected by processing others
        const originalSet = originalSets[k];
        
        if (currentSet.area !== originalSet.area) {
          throw new Error(`Dimension set ${k} was affected by processing other sets`);
        }
        
        if (currentSet.quantity !== originalSet.quantity) {
          throw new Error(`Quantity for dimension set ${k} was affected by processing other sets`);
        }
        
        // Verify dimensions remain independent
        if (currentSet.normalizedDimensions.length !== originalSet.normalizedDimensions.length ||
            currentSet.normalizedDimensions.width !== originalSet.normalizedDimensions.width) {
          throw new Error(`Dimensions for set ${k} were affected by processing other sets`);
        }
      }
      
      // Test edge case: identical dimension sets should still be independent
      if (numSets >= 2) {
        const identicalSets = [
          { length: 100, width: 200, unit: 'cm', quantity: 2 },
          { length: 100, width: 200, unit: 'cm', quantity: 3 }
        ];
        
        const identicalValidation = dimensionValidationService.validateMultipleDimensionSets(
          identicalSets,
          product.unit_of_measure
        );
        
        if (identicalValidation.isValid) {
          // Should have 2 separate dimension sets even though dimensions are identical
          if (identicalValidation.dimensionSets.length !== 2) {
            throw new Error('Identical dimension sets should remain independent');
          }
          
          // Total pieces should be sum of both sets
          const totalPieces = identicalValidation.dimensionSets.reduce((sum, set) => sum + set.quantity, 0);
          if (totalPieces !== 5) { // 2 + 3
            throw new Error('Identical dimension sets should maintain independent quantities');
          }
        }
      }
      
      passCount++;
      
    } catch (error) {
      console.log(`❌ Iteration ${i + 1}: ${error.message}`);
      failCount++;
    }
  }
  
  const successRate = (passCount / iterations) * 100;
  console.log(`✅ Property 12 Results: ${passCount}/${iterations} passed (${successRate.toFixed(1)}%)`);
  
  if (successRate < 95) {
    console.log('❌ Property 12 FAILED: Success rate below 95%');
    return false;
  }
  
  console.log('✅ Property 12 PASSED: Multi-dimension independence maintained');
  return true;
}

/**
 * Test multiple dimension scenarios with different units
 */
function testMultiDimensionUnitConversion() {
  console.log('🧪 Testing Multi-Dimension Unit Conversion');
  
  let passCount = 0;
  let failCount = 0;
  const iterations = 50;
  
  for (let i = 0; i < iterations; i++) {
    try {
      const product = {
        id: i + 1,
        name: `Mixed Unit Fabric ${i}`,
        product_type: 'RM',
        track_by_dimensions: true,
        unit_of_measure: 'm' // Product uses meters
      };
      
      // Create dimension sets with different units
      const dimensionSets = [
        { length: 200, width: 150, unit: 'cm', quantity: 2 }, // Centimeters
        { length: 1.5, width: 1.0, unit: 'm', quantity: 1 },  // Meters
        { length: 60, width: 40, unit: 'inch', quantity: 3 }   // Inches
      ];
      
      const validation = dimensionValidationService.validateMultipleDimensionSets(
        dimensionSets,
        product.unit_of_measure
      );
      
      if (!validation.isValid) {
        throw new Error(`Validation failed: ${validation.error}`);
      }
      
      // Verify all dimensions are converted to product unit (meters)
      for (const dimSet of validation.dimensionSets) {
        if (dimSet.normalizedDimensions.unit !== 'm') {
          throw new Error(`Unit conversion failed: expected 'm', got '${dimSet.normalizedDimensions.unit}'`);
        }
        
        // Verify conversion accuracy
        const originalSet = dimensionSets[dimSet.index];
        const expectedLength = dimensionValidationService.convertUnit(
          originalSet.length,
          originalSet.unit,
          'm'
        );
        const expectedWidth = dimensionValidationService.convertUnit(
          originalSet.width,
          originalSet.unit,
          'm'
        );
        
        if (!expectedLength.isValid || !expectedWidth.isValid) {
          throw new Error('Unit conversion failed during validation');
        }
        
        // Allow small floating point differences
        const lengthDiff = Math.abs(dimSet.normalizedDimensions.length - expectedLength.value);
        const widthDiff = Math.abs(dimSet.normalizedDimensions.width - expectedWidth.value);
        
        if (lengthDiff > 0.0001 || widthDiff > 0.0001) {
          throw new Error(`Conversion accuracy error: length diff ${lengthDiff}, width diff ${widthDiff}`);
        }
      }
      
      // Verify total area calculation with mixed units
      let expectedTotalArea = 0;
      for (let j = 0; j < dimensionSets.length; j++) {
        const originalSet = dimensionSets[j];
        const convertedLength = dimensionValidationService.convertUnit(
          originalSet.length,
          originalSet.unit,
          'm'
        );
        const convertedWidth = dimensionValidationService.convertUnit(
          originalSet.width,
          originalSet.unit,
          'm'
        );
        
        const area = convertedLength.value * convertedWidth.value;
        expectedTotalArea += area * originalSet.quantity;
      }
      
      const areaDiff = Math.abs(validation.totalArea - expectedTotalArea);
      if (areaDiff > 0.001) {
        throw new Error(`Total area calculation error: expected ${expectedTotalArea}, got ${validation.totalArea}`);
      }
      
      passCount++;
      
    } catch (error) {
      console.log(`❌ Iteration ${i + 1}: ${error.message}`);
      failCount++;
    }
  }
  
  const successRate = (passCount / iterations) * 100;
  console.log(`✅ Multi-Dimension Unit Conversion: ${passCount}/${iterations} passed (${successRate.toFixed(1)}%)`);
  
  return successRate >= 95;
}

/**
 * Test edge cases for multi-dimension processing
 */
function testMultiDimensionEdgeCases() {
  console.log('🧪 Testing Multi-Dimension Edge Cases');
  
  const product = {
    id: 1,
    name: 'Test Fabric',
    product_type: 'RM',
    track_by_dimensions: true,
    unit_of_measure: 'cm'
  };
  
  // Test 1: Empty dimension sets
  try {
    const validation1 = dimensionValidationService.validateMultipleDimensionSets([], product.unit_of_measure);
    if (validation1.isValid) {
      console.log('❌ Empty dimension sets should be invalid');
      return false;
    }
  } catch (error) {
    // Expected to fail
  }
  
  // Test 2: Single dimension set
  try {
    const singleSet = [{ length: 100, width: 200, unit: 'cm', quantity: 1 }];
    const validation2 = dimensionValidationService.validateMultipleDimensionSets(singleSet, product.unit_of_measure);
    if (!validation2.isValid) {
      console.log('❌ Single dimension set should be valid');
      return false;
    }
    if (validation2.dimensionSets.length !== 1) {
      console.log('❌ Single dimension set should result in one processed set');
      return false;
    }
  } catch (error) {
    console.log(`❌ Single dimension set test failed: ${error.message}`);
    return false;
  }
  
  // Test 3: Zero quantity
  try {
    const zeroQuantitySet = [{ length: 100, width: 200, unit: 'cm', quantity: 0 }];
    const validation3 = dimensionValidationService.validateMultipleDimensionSets(zeroQuantitySet, product.unit_of_measure);
    console.log('Zero quantity validation result:', validation3);
    if (validation3.isValid) {
      console.log('❌ Zero quantity should be invalid');
      return false;
    }
    console.log('✅ Zero quantity correctly rejected');
  } catch (error) {
    // Expected to fail - this is correct behavior
    console.log('✅ Zero quantity correctly rejected with exception:', error.message);
  }
  
  // Test 4: Negative dimensions
  try {
    const negativeSet = [{ length: -100, width: 200, unit: 'cm', quantity: 1 }];
    const validation4 = dimensionValidationService.validateMultipleDimensionSets(negativeSet, product.unit_of_measure);
    if (validation4.isValid) {
      console.log('❌ Negative dimensions should be invalid');
      return false;
    }
  } catch (error) {
    // Expected to fail
  }
  
  // Test 5: Invalid unit
  try {
    const invalidUnitSet = [{ length: 100, width: 200, unit: 'invalid', quantity: 1 }];
    const validation5 = dimensionValidationService.validateMultipleDimensionSets(invalidUnitSet, product.unit_of_measure);
    if (validation5.isValid) {
      console.log('❌ Invalid unit should be invalid');
      return false;
    }
  } catch (error) {
    // Expected to fail
  }
  
  console.log('✅ All multi-dimension edge cases handled correctly');
  return true;
}

// Run all tests
function runAllTests() {
  console.log('🚀 Starting Multi-Dimension Independence Property Tests\n');
  
  const results = [
    testMultiDimensionIndependence(),
    testMultiDimensionUnitConversion(),
    testMultiDimensionEdgeCases()
  ];
  
  const allPassed = results.every(result => result === true);
  
  console.log('\n📊 Final Results:');
  console.log(`Multi-Dimension Independence: ${allPassed ? '✅ PASSED' : '❌ FAILED'}`);
  
  if (allPassed) {
    console.log('\n🎉 All multi-dimension independence tests passed!');
    console.log('✅ Property 12: Multi-Dimension Independence - VALIDATED');
    console.log('✅ Requirements 7.1, 7.2 - SATISFIED');
  } else {
    console.log('\n💥 Some multi-dimension independence tests failed!');
    process.exit(1);
  }
}

// Run tests if this file is executed directly
if (require.main === module) {
  runAllTests();
}

module.exports = {
  testMultiDimensionIndependence,
  testMultiDimensionUnitConversion,
  testMultiDimensionEdgeCases,
  runAllTests
};