/**
 * Property Test: Fractional Dimension Support
 * Tests that the system correctly handles fractional dimensions
 * Property 14: Fractional Dimension Support
 * Validates: Requirements 9.4
 */

const dimensionValidationService = require('./services/dimensionValidationService');
const bomDimensionService = require('./services/bomDimensionService');
const materialAllocationService = require('./services/materialAllocationService');

/**
 * Property 14: Fractional Dimension Support
 * The system should correctly handle fractional dimensions in all operations
 * including validation, conversion, calculation, and allocation
 */
function testFractionalDimensionSupport() {
  console.log('🧪 Testing Property 14: Fractional Dimension Support');
  
  let passCount = 0;
  let failCount = 0;
  const iterations = 100;
  
  for (let i = 0; i < iterations; i++) {
    try {
      // Generate fractional dimensions
      const length = Math.random() * 100 + 10.5; // 10.5-110.5 (always fractional)
      const width = Math.random() * 80 + 5.25;   // 5.25-85.25 (always fractional)
      const unit = ['cm', 'm', 'inch'][Math.floor(Math.random() * 3)];
      
      // Ensure we have fractional values
      const fractionalLength = Math.floor(length * 100) / 100; // 2 decimal places
      const fractionalWidth = Math.floor(width * 100) / 100;   // 2 decimal places
      
      // Test 1: Dimension validation with fractional values
      const validation = dimensionValidationService.validateDimensions(
        fractionalLength,
        fractionalWidth,
        unit
      );
      
      if (!validation.isValid) {
        throw new Error(`Fractional dimension validation failed: ${validation.errors.join(', ')}`);
      }
      
      // Test 2: Area calculation with fractional dimensions
      const areaResult = dimensionValidationService.calculateArea(
        fractionalLength,
        fractionalWidth,
        unit
      );
      
      if (!areaResult.isValid) {
        throw new Error(`Fractional area calculation failed: ${areaResult.errors.join(', ')}`);
      }
      
      const expectedArea = fractionalLength * fractionalWidth;
      if (Math.abs(areaResult.area - expectedArea) > 0.0001) {
        throw new Error(`Area calculation precision error: expected ${expectedArea}, got ${areaResult.area}`);
      }
      
      // Test 3: Unit conversion with fractional dimensions
      const targetUnit = unit === 'cm' ? 'm' : 'cm';
      const conversionResult = dimensionValidationService.convertDimensions(
        {
          length: fractionalLength,
          width: fractionalWidth,
          unit: unit
        },
        targetUnit
      );
      
      if (!conversionResult.isValid) {
        throw new Error(`Fractional unit conversion failed: ${conversionResult.error}`);
      }
      
      // Verify conversion maintains precision
      const conversionFactor = dimensionValidationService.UNIT_CONVERSIONS[unit] / 
                              dimensionValidationService.UNIT_CONVERSIONS[targetUnit];
      const expectedConvertedLength = fractionalLength * conversionFactor;
      const expectedConvertedWidth = fractionalWidth * conversionFactor;
      
      const lengthDiff = Math.abs(conversionResult.dimensions.length - expectedConvertedLength);
      const widthDiff = Math.abs(conversionResult.dimensions.width - expectedConvertedWidth);
      
      if (lengthDiff > 0.0001 || widthDiff > 0.0001) {
        throw new Error(`Conversion precision error: length diff ${lengthDiff}, width diff ${widthDiff}`);
      }
      
      // Test 4: BOM dimension requirements with fractional values
      const bomItem = {
        use_dimensions: true,
        required_length: fractionalLength,
        required_width: fractionalWidth,
        dimension_unit: unit
      };
      
      const productionQuantity = Math.random() * 10 + 1; // Fractional production quantity
      const fractionalProductionQty = Math.floor(productionQuantity * 100) / 100;
      
      const dimensionReq = bomDimensionService.calculateDimensionRequirements(
        bomItem,
        fractionalProductionQty
      );
      
      if (!dimensionReq.isValid) {
        throw new Error(`BOM fractional dimension calculation failed: ${dimensionReq.error}`);
      }
      
      const expectedAreaPerUnit = fractionalLength * fractionalWidth;
      const expectedTotalArea = expectedAreaPerUnit * fractionalProductionQty;
      
      if (Math.abs(dimensionReq.areaPerUnit - expectedAreaPerUnit) > 0.0001) {
        throw new Error(`BOM area per unit precision error: expected ${expectedAreaPerUnit}, got ${dimensionReq.areaPerUnit}`);
      }
      
      if (Math.abs(dimensionReq.totalAreaRequired - expectedTotalArea) > 0.0001) {
        throw new Error(`BOM total area precision error: expected ${expectedTotalArea}, got ${dimensionReq.totalAreaRequired}`);
      }
      
      // Test 5: Dimension sufficiency check with fractional values
      const availableDimensions = {
        length: fractionalLength + Math.random() * 10, // Slightly larger
        width: fractionalWidth + Math.random() * 10,   // Slightly larger
        unit: unit
      };
      
      const requiredDimensions = {
        length: fractionalLength,
        width: fractionalWidth,
        unit: unit
      };
      
      const sufficiencyResult = dimensionValidationService.checkDimensionSufficiency(
        availableDimensions,
        requiredDimensions
      );
      
      if (!sufficiencyResult.isValid) {
        throw new Error(`Fractional dimension sufficiency check failed: ${sufficiencyResult.error}`);
      }
      
      if (!sufficiencyResult.canFit) {
        throw new Error('Larger fractional dimensions should fit smaller fractional requirements');
      }
      
      // Verify remaining dimensions calculation precision
      if (sufficiencyResult.remainingDimensions) {
        const expectedRemainingLength = availableDimensions.length - fractionalLength;
        const expectedRemainingWidth = availableDimensions.width - fractionalWidth;
        
        const remainingLengthDiff = Math.abs(sufficiencyResult.remainingDimensions.length - expectedRemainingLength);
        const remainingWidthDiff = Math.abs(sufficiencyResult.remainingDimensions.width - expectedRemainingWidth);
        
        if (remainingLengthDiff > 0.0001 || remainingWidthDiff > 0.0001) {
          throw new Error(`Remaining dimensions precision error: length diff ${remainingLengthDiff}, width diff ${remainingWidthDiff}`);
        }
      }
      
      // Test 6: Multiple fractional dimension sets
      const fractionalDimensionSets = [
        {
          length: fractionalLength,
          width: fractionalWidth,
          unit: unit,
          quantity: Math.floor((Math.random() * 5 + 1) * 100) / 100 // Fractional quantity
        },
        {
          length: Math.floor((Math.random() * 50 + 20) * 100) / 100,
          width: Math.floor((Math.random() * 40 + 15) * 100) / 100,
          unit: unit,
          quantity: Math.floor((Math.random() * 3 + 1) * 100) / 100 // Fractional quantity
        }
      ];
      
      const multiValidation = dimensionValidationService.validateMultipleDimensionSets(
        fractionalDimensionSets,
        unit
      );
      
      if (!multiValidation.isValid) {
        throw new Error(`Multiple fractional dimension sets validation failed: ${multiValidation.error}`);
      }
      
      // Verify total area calculation with fractional values
      let expectedTotalAreaMulti = 0;
      for (const dimSet of fractionalDimensionSets) {
        expectedTotalAreaMulti += dimSet.length * dimSet.width * dimSet.quantity;
      }
      
      if (Math.abs(multiValidation.totalArea - expectedTotalAreaMulti) > 0.0001) {
        throw new Error(`Multiple sets total area precision error: expected ${expectedTotalAreaMulti}, got ${multiValidation.totalArea}`);
      }
      
      passCount++;
      
    } catch (error) {
      console.log(`❌ Iteration ${i + 1}: ${error.message}`);
      failCount++;
    }
  }
  
  const successRate = (passCount / iterations) * 100;
  console.log(`✅ Property 14 Results: ${passCount}/${iterations} passed (${successRate.toFixed(1)}%)`);
  
  if (successRate < 95) {
    console.log('❌ Property 14 FAILED: Success rate below 95%');
    return false;
  }
  
  console.log('✅ Property 14 PASSED: Fractional dimension support validated');
  return true;
}

/**
 * Test fractional dimensions in material allocation
 */
function testFractionalDimensionsInAllocation() {
  console.log('🧪 Testing Fractional Dimensions in Material Allocation');
  
  let passCount = 0;
  let failCount = 0;
  const iterations = 50;
  
  for (let i = 0; i < iterations; i++) {
    try {
      // Create inventory pieces with fractional dimensions
      const inventoryPieces = [
        {
          id: 1,
          product_id: 1,
          length: Math.floor((Math.random() * 200 + 100) * 100) / 100, // 100-300 with 2 decimals
          width: Math.floor((Math.random() * 150 + 80) * 100) / 100,   // 80-230 with 2 decimals
          unit: 'cm',
          status: 'FULL'
        },
        {
          id: 2,
          product_id: 1,
          length: Math.floor((Math.random() * 150 + 75) * 100) / 100,  // 75-225 with 2 decimals
          width: Math.floor((Math.random() * 100 + 50) * 100) / 100,   // 50-150 with 2 decimals
          unit: 'cm',
          status: 'USABLE'
        }
      ];
      
      // Create requirements with fractional dimensions
      const requirements = [
        {
          length: Math.floor((Math.random() * 80 + 40) * 100) / 100,   // 40-120 with 2 decimals
          width: Math.floor((Math.random() * 60 + 30) * 100) / 100,    // 30-90 with 2 decimals
          unit: 'cm',
          quantity: Math.floor((Math.random() * 3 + 1) * 100) / 100    // 1-4 with 2 decimals
        }
      ];
      
      // Test allocation feasibility with fractional dimensions
      let feasiblePieces = 0;
      let totalAvailableArea = 0;
      
      for (const piece of inventoryPieces) {
        const sufficiencyResult = dimensionValidationService.checkDimensionSufficiency(
          {
            length: piece.length,
            width: piece.width,
            unit: piece.unit
          },
          {
            length: requirements[0].length,
            width: requirements[0].width,
            unit: requirements[0].unit
          }
        );
        
        if (!sufficiencyResult.isValid) {
          throw new Error(`Sufficiency check failed for piece ${piece.id}: ${sufficiencyResult.error}`);
        }
        
        if (sufficiencyResult.canFit) {
          feasiblePieces++;
          
          // Verify remaining dimensions calculation with fractional precision
          if (sufficiencyResult.remainingDimensions) {
            const expectedRemainingLength = piece.length - requirements[0].length;
            const expectedRemainingWidth = piece.width - requirements[0].width;
            
            const lengthDiff = Math.abs(sufficiencyResult.remainingDimensions.length - expectedRemainingLength);
            const widthDiff = Math.abs(sufficiencyResult.remainingDimensions.width - expectedRemainingWidth);
            
            if (lengthDiff > 0.0001 || widthDiff > 0.0001) {
              throw new Error(`Remaining dimensions precision error for piece ${piece.id}`);
            }
          }
        }
        
        totalAvailableArea += piece.length * piece.width;
      }
      
      // Verify area calculations with fractional precision
      const requiredArea = requirements[0].length * requirements[0].width * requirements[0].quantity;
      
      // Test that fractional calculations maintain precision
      if (feasiblePieces > 0) {
        const firstFeasiblePiece = inventoryPieces.find(piece => {
          const sufficiency = dimensionValidationService.checkDimensionSufficiency(
            { length: piece.length, width: piece.width, unit: piece.unit },
            { length: requirements[0].length, width: requirements[0].width, unit: requirements[0].unit }
          );
          return sufficiency.isValid && sufficiency.canFit;
        });
        
        if (firstFeasiblePiece) {
          const wasteArea = (firstFeasiblePiece.length * firstFeasiblePiece.width) - 
                           (requirements[0].length * requirements[0].width);
          
          // Verify waste calculation precision
          if (wasteArea < 0) {
            throw new Error('Waste area calculation error with fractional dimensions');
          }
          
          // Test that small fractional differences don't cause allocation errors
          const almostExactRequirement = {
            length: firstFeasiblePiece.length - 0.01, // Very close to piece size
            width: firstFeasiblePiece.width - 0.01,   // Very close to piece size
            unit: firstFeasiblePiece.unit
          };
          
          const almostExactSufficiency = dimensionValidationService.checkDimensionSufficiency(
            {
              length: firstFeasiblePiece.length,
              width: firstFeasiblePiece.width,
              unit: firstFeasiblePiece.unit
            },
            almostExactRequirement
          );
          
          if (!almostExactSufficiency.isValid || !almostExactSufficiency.canFit) {
            throw new Error('Almost exact fractional dimensions should fit');
          }
          
          // Verify very small remaining dimensions
          if (almostExactSufficiency.remainingDimensions) {
            if (almostExactSufficiency.remainingDimensions.length < 0 || 
                almostExactSufficiency.remainingDimensions.width < 0) {
              throw new Error('Remaining dimensions should not be negative with fractional precision');
            }
            
            if (Math.abs(almostExactSufficiency.remainingDimensions.length - 0.01) > 0.0001 ||
                Math.abs(almostExactSufficiency.remainingDimensions.width - 0.01) > 0.0001) {
              throw new Error('Small remaining dimensions precision error');
            }
          }
        }
      }
      
      passCount++;
      
    } catch (error) {
      console.log(`❌ Iteration ${i + 1}: ${error.message}`);
      failCount++;
    }
  }
  
  const successRate = (passCount / iterations) * 100;
  console.log(`✅ Fractional Dimensions in Allocation: ${passCount}/${iterations} passed (${successRate.toFixed(1)}%)`);
  
  return successRate >= 95;
}

/**
 * Test fractional dimension edge cases
 */
function testFractionalDimensionEdgeCases() {
  console.log('🧪 Testing Fractional Dimension Edge Cases');
  
  // Test 1: Very small fractional dimensions
  try {
    const validation = dimensionValidationService.validateDimensions(0.01, 0.01, 'cm');
    if (!validation.isValid) {
      console.log('❌ Very small fractional dimensions should be valid');
      return false;
    }
    console.log('✅ Very small fractional dimensions handled correctly');
  } catch (error) {
    console.log(`❌ Very small fractional dimensions test failed: ${error.message}`);
    return false;
  }
  
  // Test 2: High precision fractional dimensions
  try {
    const highPrecisionLength = 123.456789;
    const highPrecisionWidth = 98.765432;
    
    const validation = dimensionValidationService.validateDimensions(
      highPrecisionLength,
      highPrecisionWidth,
      'cm'
    );
    
    if (!validation.isValid) {
      console.log('❌ High precision fractional dimensions should be valid');
      return false;
    }
    
    const areaResult = dimensionValidationService.calculateArea(
      highPrecisionLength,
      highPrecisionWidth,
      'cm'
    );
    
    if (!areaResult.isValid) {
      console.log('❌ High precision area calculation should be valid');
      return false;
    }
    
    const expectedArea = highPrecisionLength * highPrecisionWidth;
    if (Math.abs(areaResult.area - expectedArea) > 0.000001) {
      console.log('❌ High precision area calculation should maintain precision');
      return false;
    }
    
    console.log('✅ High precision fractional dimensions handled correctly');
  } catch (error) {
    console.log(`❌ High precision fractional dimensions test failed: ${error.message}`);
    return false;
  }
  
  // Test 3: Fractional unit conversion precision
  try {
    const fractionalDimensions = {
      length: 12.345,
      width: 6.789,
      unit: 'cm'
    };
    
    const conversionResult = dimensionValidationService.convertDimensions(
      fractionalDimensions,
      'm'
    );
    
    if (!conversionResult.isValid) {
      console.log('❌ Fractional unit conversion should be valid');
      return false;
    }
    
    // Verify conversion maintains reasonable precision
    const expectedLengthM = 12.345 / 100;
    const expectedWidthM = 6.789 / 100;
    
    const lengthDiff = Math.abs(conversionResult.dimensions.length - expectedLengthM);
    const widthDiff = Math.abs(conversionResult.dimensions.width - expectedWidthM);
    
    if (lengthDiff > 0.000001 || widthDiff > 0.000001) {
      console.log('❌ Fractional unit conversion should maintain precision');
      return false;
    }
    
    console.log('✅ Fractional unit conversion precision maintained');
  } catch (error) {
    console.log(`❌ Fractional unit conversion test failed: ${error.message}`);
    return false;
  }
  
  // Test 4: Fractional quantity in multiple dimension sets
  try {
    const fractionalSets = [
      { length: 10.5, width: 8.25, unit: 'cm', quantity: 2.5 },
      { length: 15.75, width: 12.125, unit: 'cm', quantity: 1.25 }
    ];
    
    const validation = dimensionValidationService.validateMultipleDimensionSets(
      fractionalSets,
      'cm'
    );
    
    if (!validation.isValid) {
      console.log('❌ Fractional quantities in multiple sets should be valid');
      return false;
    }
    
    // Verify total area calculation with fractional quantities
    const expectedTotalArea = (10.5 * 8.25 * 2.5) + (15.75 * 12.125 * 1.25);
    
    if (Math.abs(validation.totalArea - expectedTotalArea) > 0.0001) {
      console.log('❌ Fractional quantity total area calculation precision error');
      return false;
    }
    
    console.log('✅ Fractional quantities in multiple sets handled correctly');
  } catch (error) {
    console.log(`❌ Fractional quantities test failed: ${error.message}`);
    return false;
  }
  
  console.log('✅ All fractional dimension edge cases handled correctly');
  return true;
}

// Run all tests
function runAllTests() {
  console.log('🚀 Starting Fractional Dimension Support Property Tests\n');
  
  const results = [
    testFractionalDimensionSupport(),
    testFractionalDimensionsInAllocation(),
    testFractionalDimensionEdgeCases()
  ];
  
  const allPassed = results.every(result => result === true);
  
  console.log('\n📊 Final Results:');
  console.log(`Fractional Dimension Support: ${allPassed ? '✅ PASSED' : '❌ FAILED'}`);
  
  if (allPassed) {
    console.log('\n🎉 All fractional dimension support tests passed!');
    console.log('✅ Property 14: Fractional Dimension Support - VALIDATED');
    console.log('✅ Requirements 9.4 - SATISFIED');
  } else {
    console.log('\n💥 Some fractional dimension support tests failed!');
    process.exit(1);
  }
}

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

module.exports = {
  testFractionalDimensionSupport,
  testFractionalDimensionsInAllocation,
  testFractionalDimensionEdgeCases,
  runAllTests
};