/**
 * Integration Tests for BOM Dimension Validation
 * Tests BOM creation and validation with dimension requirements
 * Validates: Requirements 2.1, 2.2
 */

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

/**
 * Test BOM creation with dimension requirements
 */
function testBOMCreationWithDimensions() {
  console.log('🧪 Testing BOM Creation with Dimension Requirements');
  
  let passCount = 0;
  let failCount = 0;
  const iterations = 50;
  
  for (let i = 0; i < iterations; i++) {
    try {
      // Create mock RM products
      const rmProducts = [
        {
          id: 1,
          name: 'Cotton Fabric',
          product_type: 'RM',
          track_by_dimensions: true,
          unit_of_measure: 'cm'
        },
        {
          id: 2,
          name: 'Polyester Thread',
          product_type: 'RM',
          track_by_dimensions: true, // Changed to true for RM products
          unit_of_measure: 'cm'     // Added unit for RM products
        }
      ];
      
      // Create BOM items with mixed dimension/quantity requirements
      const bomItems = [
        {
          rm_product_id: 1,
          use_dimensions: true,
          required_length: Math.random() * 200 + 50, // 50-250 cm
          required_width: Math.random() * 150 + 30,  // 30-180 cm
          dimension_unit: 'cm',
          quantity_per_unit: 1 // Default for dimension-based
        },
        {
          rm_product_id: 2,
          use_dimensions: false,
          quantity_per_unit: Math.random() * 10 + 1, // 1-11 units
          // No dimension fields
        }
      ];
      
      // Test validation for each BOM item
      for (let j = 0; j < bomItems.length; j++) {
        const bomItem = bomItems[j];
        const rmProduct = rmProducts.find(p => p.id === bomItem.rm_product_id);
        
        const validation = bomDimensionService.validateBOMItemDimensions(bomItem, rmProduct);
        
        if (!validation.isValid) {
          throw new Error(`BOM item ${j} validation failed: ${validation.error}`);
        }
        
        // Verify validation results match expectations
        if (rmProduct.track_by_dimensions && bomItem.use_dimensions) {
          if (!validation.requiresDimensions || !validation.useDimensions) {
            throw new Error(`Dimension-based RM product should require and use dimensions`);
          }
          
          if (!validation.dimensions) {
            throw new Error(`Dimension-based BOM item should have dimensions in validation result`);
          }
        } else if (!rmProduct.track_by_dimensions && bomItem.use_dimensions) {
          // This should fail validation
          throw new Error(`Non-RM product should not be able to use dimensions`);
        } else if (rmProduct.track_by_dimensions && !bomItem.use_dimensions) {
          // RM product with quantity-based BOM - should be allowed
          if (!validation.requiresDimensions || validation.useDimensions) {
            throw new Error(`RM product should require dimensions but BOM item can choose not to use them`);
          }
        }
      }
      
      // Test mixed BOM validation
      const mixedValidation = bomDimensionService.validateMixedBOM(bomItems);
      
      if (!mixedValidation.isValid) {
        throw new Error(`Mixed BOM validation failed: ${mixedValidation.itemResults.map(r => r.error).join(', ')}`);
      }
      
      // Verify mixed BOM characteristics
      if (!mixedValidation.isMixed) {
        throw new Error('BOM should be identified as mixed (dimension + quantity based)');
      }
      
      if (!mixedValidation.hasDimensionBased || !mixedValidation.hasQuantityBased) {
        throw new Error('Mixed BOM should have both dimension-based and quantity-based items');
      }
      
      if (mixedValidation.summary.dimensionBasedItems !== 1 || mixedValidation.summary.quantityBasedItems !== 1) {
        throw new Error(`Expected 1 dimension-based and 1 quantity-based item, got ${mixedValidation.summary.dimensionBasedItems} and ${mixedValidation.summary.quantityBasedItems}`);
      }
      
      passCount++;
      
    } catch (error) {
      console.log(`❌ Iteration ${i + 1}: ${error.message}`);
      failCount++;
    }
  }
  
  const successRate = (passCount / iterations) * 100;
  console.log(`✅ BOM Creation with Dimensions: ${passCount}/${iterations} passed (${successRate.toFixed(1)}%)`);
  
  return successRate >= 95;
}

/**
 * Test BOM dimension requirements calculation
 */
function testBOMDimensionRequirementsCalculation() {
  console.log('🧪 Testing BOM Dimension Requirements Calculation');
  
  let passCount = 0;
  let failCount = 0;
  const iterations = 30;
  
  for (let i = 0; i < iterations; i++) {
    try {
      // Create dimension-based BOM item
      const bomItem = {
        id: i + 1,
        use_dimensions: true,
        required_length: Math.random() * 100 + 50, // 50-150 cm
        required_width: Math.random() * 80 + 20,   // 20-100 cm
        dimension_unit: 'cm'
      };
      
      const productionQuantity = Math.floor(Math.random() * 50) + 10; // 10-59 units
      
      // Calculate dimension requirements
      const requirements = bomDimensionService.calculateDimensionRequirements(bomItem, productionQuantity);
      
      if (!requirements.isValid) {
        throw new Error(`Requirements calculation failed: ${requirements.error}`);
      }
      
      // Verify calculations
      const expectedAreaPerUnit = bomItem.required_length * bomItem.required_width;
      const expectedTotalArea = expectedAreaPerUnit * productionQuantity;
      
      if (Math.abs(requirements.areaPerUnit - expectedAreaPerUnit) > 0.001) {
        throw new Error(`Area per unit mismatch: expected ${expectedAreaPerUnit}, got ${requirements.areaPerUnit}`);
      }
      
      if (Math.abs(requirements.totalAreaRequired - expectedTotalArea) > 0.001) {
        throw new Error(`Total area mismatch: expected ${expectedTotalArea}, got ${requirements.totalAreaRequired}`);
      }
      
      if (requirements.productionQuantity !== productionQuantity) {
        throw new Error(`Production quantity mismatch: expected ${productionQuantity}, got ${requirements.productionQuantity}`);
      }
      
      if (requirements.dimensions.length !== bomItem.required_length ||
          requirements.dimensions.width !== bomItem.required_width ||
          requirements.dimensions.unit !== bomItem.dimension_unit) {
        throw new Error('Dimension details mismatch in requirements result');
      }
      
      passCount++;
      
    } catch (error) {
      console.log(`❌ Iteration ${i + 1}: ${error.message}`);
      failCount++;
    }
  }
  
  const successRate = (passCount / iterations) * 100;
  console.log(`✅ BOM Dimension Requirements Calculation: ${passCount}/${iterations} passed (${successRate.toFixed(1)}%)`);
  
  return successRate >= 95;
}

/**
 * Test BOM validation error scenarios
 */
function testBOMValidationErrors() {
  console.log('🧪 Testing BOM Validation Error Scenarios');
  
  const rmProduct = {
    id: 1,
    name: 'Test Fabric',
    product_type: 'RM',
    track_by_dimensions: true,
    unit_of_measure: 'cm'
  };
  
  const nonRMProduct = {
    id: 2,
    name: 'Test Thread',
    product_type: 'RM',
    track_by_dimensions: false,
    unit_of_measure: null
  };
  
  // Test 1: Missing dimensions for dimension-based BOM item
  try {
    const invalidItem = {
      rm_product_id: 1,
      use_dimensions: true,
      // Missing required_length, required_width, dimension_unit
    };
    
    const validation = bomDimensionService.validateBOMItemDimensions(invalidItem, rmProduct);
    if (validation.isValid) {
      console.log('❌ Missing dimensions should be invalid');
      return false;
    }
    console.log('✅ Missing dimensions correctly rejected');
  } catch (error) {
    console.log(`❌ Missing dimensions test failed: ${error.message}`);
    return false;
  }
  
  // Test 2: Negative dimensions
  try {
    const negativeItem = {
      rm_product_id: 1,
      use_dimensions: true,
      required_length: -100, // Negative
      required_width: 50,
      dimension_unit: 'cm'
    };
    
    const validation = bomDimensionService.validateBOMItemDimensions(negativeItem, rmProduct);
    if (validation.isValid) {
      console.log('❌ Negative dimensions should be invalid');
      return false;
    }
    console.log('✅ Negative dimensions correctly rejected');
  } catch (error) {
    console.log(`❌ Negative dimensions test failed: ${error.message}`);
    return false;
  }
  
  // Test 3: Invalid unit
  try {
    const invalidUnitItem = {
      rm_product_id: 1,
      use_dimensions: true,
      required_length: 100,
      required_width: 50,
      dimension_unit: 'invalid' // Invalid unit
    };
    
    const validation = bomDimensionService.validateBOMItemDimensions(invalidUnitItem, rmProduct);
    if (validation.isValid) {
      console.log('❌ Invalid unit should be invalid');
      return false;
    }
    console.log('✅ Invalid unit correctly rejected');
  } catch (error) {
    console.log(`❌ Invalid unit test failed: ${error.message}`);
    return false;
  }
  
  // Test 4: Non-RM product using dimensions
  try {
    const fgProduct = {
      id: 3,
      name: 'Finished Shirt',
      product_type: 'FG',
      track_by_dimensions: false,
      unit_of_measure: null
    };
    
    const invalidItem = {
      rm_product_id: 3,
      use_dimensions: true,
      required_length: 100,
      required_width: 50,
      dimension_unit: 'cm'
    };
    
    const validation = bomDimensionService.validateBOMItemDimensions(invalidItem, fgProduct);
    if (validation.isValid) {
      console.log('❌ Non-RM product using dimensions should be invalid');
      return false;
    }
    console.log('✅ Non-RM product using dimensions correctly rejected');
  } catch (error) {
    console.log(`❌ Non-RM product test failed: ${error.message}`);
    return false;
  }
  
  // Test 5: Zero production quantity
  try {
    const validItem = {
      use_dimensions: true,
      required_length: 100,
      required_width: 50,
      dimension_unit: 'cm'
    };
    
    const requirements = bomDimensionService.calculateDimensionRequirements(validItem, 0);
    if (requirements.isValid) {
      console.log('❌ Zero production quantity should be invalid');
      return false;
    }
    console.log('✅ Zero production quantity correctly rejected');
  } catch (error) {
    console.log(`❌ Zero production quantity test failed: ${error.message}`);
    return false;
  }
  
  console.log('✅ All BOM validation error scenarios handled correctly');
  return true;
}

/**
 * Test BOM dimension unit conversion
 */
function testBOMDimensionUnitConversion() {
  console.log('🧪 Testing BOM Dimension Unit Conversion');
  
  let passCount = 0;
  let failCount = 0;
  const iterations = 20;
  
  for (let i = 0; i < iterations; i++) {
    try {
      // Create BOM item with cm dimensions
      const bomItem = {
        use_dimensions: true,
        required_length: 200, // cm
        required_width: 150,  // cm
        dimension_unit: 'cm'
      };
      
      // Test conversion to meters
      const conversionResult = bomDimensionService.convertBOMDimensions(bomItem, 'm');
      
      if (!conversionResult.isValid) {
        throw new Error(`Conversion failed: ${conversionResult.error}`);
      }
      
      // Verify conversion accuracy
      const expectedLengthM = 200 / 100; // cm to m
      const expectedWidthM = 150 / 100;  // cm to m
      
      const lengthDiff = Math.abs(conversionResult.convertedDimensions.length - expectedLengthM);
      const widthDiff = Math.abs(conversionResult.convertedDimensions.width - expectedWidthM);
      
      if (lengthDiff > 0.0001 || widthDiff > 0.0001) {
        throw new Error(`Conversion accuracy error: length diff ${lengthDiff}, width diff ${widthDiff}`);
      }
      
      // Verify area calculations
      const originalArea = bomItem.required_length * bomItem.required_width;
      const convertedArea = conversionResult.convertedDimensions.length * conversionResult.convertedDimensions.width;
      
      // Areas should be equivalent (accounting for unit conversion)
      const originalAreaM2 = originalArea / 10000; // cm² to m²
      const areaDiff = Math.abs(convertedArea - originalAreaM2);
      
      if (areaDiff > 0.0001) {
        throw new Error(`Area conversion error: expected ${originalAreaM2} m², got ${convertedArea} m²`);
      }
      
      // Verify original dimensions are preserved
      if (conversionResult.originalDimensions.length !== bomItem.required_length ||
          conversionResult.originalDimensions.width !== bomItem.required_width ||
          conversionResult.originalDimensions.unit !== bomItem.dimension_unit) {
        throw new Error('Original dimensions not preserved in conversion result');
      }
      
      passCount++;
      
    } catch (error) {
      console.log(`❌ Iteration ${i + 1}: ${error.message}`);
      failCount++;
    }
  }
  
  const successRate = (passCount / iterations) * 100;
  console.log(`✅ BOM Dimension Unit Conversion: ${passCount}/${iterations} passed (${successRate.toFixed(1)}%)`);
  
  return successRate >= 95;
}

/**
 * Test BOM requirements summary generation
 */
function testBOMRequirementsSummary() {
  console.log('🧪 Testing BOM Requirements Summary Generation');
  
  let passCount = 0;
  let failCount = 0;
  const iterations = 20;
  
  for (let i = 0; i < iterations; i++) {
    try {
      // Create mock BOM with mixed items
      const bom = {
        id: i + 1,
        items: [
          {
            id: 1,
            use_dimensions: true,
            required_length: 100,
            required_width: 80,
            dimension_unit: 'cm',
            rawMaterial: {
              id: 1,
              name: 'Cotton Fabric'
            }
          },
          {
            id: 2,
            use_dimensions: true,
            required_length: 50,
            required_width: 30,
            dimension_unit: 'cm',
            rawMaterial: {
              id: 2,
              name: 'Lining Fabric'
            }
          },
          {
            id: 3,
            use_dimensions: false,
            quantity_per_unit: 5,
            rawMaterial: {
              id: 3,
              name: 'Thread'
            }
          }
        ]
      };
      
      const productionQuantity = Math.floor(Math.random() * 20) + 5; // 5-24 units
      
      // Generate requirements summary
      const summary = bomDimensionService.generateDimensionRequirementsSummary(bom, productionQuantity);
      
      if (!summary.isValid) {
        throw new Error(`Summary generation failed: ${summary.error}`);
      }
      
      const result = summary.summary;
      
      // Verify summary structure
      if (result.bomId !== bom.id) {
        throw new Error(`BOM ID mismatch: expected ${bom.id}, got ${result.bomId}`);
      }
      
      if (result.productionQuantity !== productionQuantity) {
        throw new Error(`Production quantity mismatch: expected ${productionQuantity}, got ${result.productionQuantity}`);
      }
      
      // Verify dimension-based items
      if (result.dimensionBasedItems.length !== 2) {
        throw new Error(`Expected 2 dimension-based items, got ${result.dimensionBasedItems.length}`);
      }
      
      // Verify quantity-based items
      if (result.quantityBasedItems.length !== 1) {
        throw new Error(`Expected 1 quantity-based item, got ${result.quantityBasedItems.length}`);
      }
      
      // Verify area calculations
      let expectedTotalArea = 0;
      for (const dimItem of result.dimensionBasedItems) {
        const expectedAreaPerUnit = dimItem.dimensions.length * dimItem.dimensions.width;
        const expectedTotalAreaForItem = expectedAreaPerUnit * productionQuantity;
        
        if (Math.abs(dimItem.areaPerUnit - expectedAreaPerUnit) > 0.001) {
          throw new Error(`Area per unit mismatch for item ${dimItem.bomItemId}`);
        }
        
        if (Math.abs(dimItem.totalAreaRequired - expectedTotalAreaForItem) > 0.001) {
          throw new Error(`Total area mismatch for item ${dimItem.bomItemId}`);
        }
        
        expectedTotalArea += expectedTotalAreaForItem;
      }
      
      if (Math.abs(result.totalAreaRequired - expectedTotalArea) > 0.001) {
        throw new Error(`Total area summary mismatch: expected ${expectedTotalArea}, got ${result.totalAreaRequired}`);
      }
      
      // Verify unit breakdown
      if (!result.unitBreakdown['cm']) {
        throw new Error('Unit breakdown should include cm');
      }
      
      if (Math.abs(result.unitBreakdown['cm'] - expectedTotalArea) > 0.001) {
        throw new Error(`Unit breakdown mismatch for cm: expected ${expectedTotalArea}, got ${result.unitBreakdown['cm']}`);
      }
      
      passCount++;
      
    } catch (error) {
      console.log(`❌ Iteration ${i + 1}: ${error.message}`);
      failCount++;
    }
  }
  
  const successRate = (passCount / iterations) * 100;
  console.log(`✅ BOM Requirements Summary: ${passCount}/${iterations} passed (${successRate.toFixed(1)}%)`);
  
  return successRate >= 95;
}

// Run all tests
function runAllTests() {
  console.log('🚀 Starting BOM Dimension Integration Tests\n');
  
  const results = [
    testBOMCreationWithDimensions(),
    testBOMDimensionRequirementsCalculation(),
    testBOMValidationErrors(),
    testBOMDimensionUnitConversion(),
    testBOMRequirementsSummary()
  ];
  
  const allPassed = results.every(result => result === true);
  
  console.log('\n📊 Final Results:');
  console.log(`BOM Dimension Integration Tests: ${allPassed ? '✅ PASSED' : '❌ FAILED'}`);
  
  if (allPassed) {
    console.log('\n🎉 All BOM dimension integration tests passed!');
    console.log('✅ BOM creation with dimension requirements - VALIDATED');
    console.log('✅ Dimension requirements calculation - VALIDATED');
    console.log('✅ Mixed BOM support (dimension + quantity) - VALIDATED');
    console.log('✅ Requirements 2.1, 2.2 - SATISFIED');
  } else {
    console.log('\n💥 Some BOM dimension integration tests failed!');
    process.exit(1);
  }
}

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

module.exports = {
  testBOMCreationWithDimensions,
  testBOMDimensionRequirementsCalculation,
  testBOMValidationErrors,
  testBOMDimensionUnitConversion,
  testBOMRequirementsSummary,
  runAllTests
};