/**
 * Core Services Integration Test
 * Tests all dimension-based inventory services working together
 */

const dimensionService = require('./services/dimensionValidationService');
const allocationService = require('./services/materialAllocationService');
const cuttingService = require('./services/cuttingOperationsService');
const inventoryService = require('./services/inventoryCalculationService');
const utilizationService = require('./services/materialUtilizationService');

console.log('Running Core Services Integration Test...\n');

async function runIntegrationTest() {
  try {
    // Test 1: Complete workflow simulation
    console.log('Test 1: Complete workflow simulation');
    
    // Step 1: Create mock inventory pieces (simulating GRN receipt)
    const inventoryPieces = [
      {
        id: 1,
        product_id: 1,
        piece_number: 1,
        length: 6.0,
        width: 4.0,
        unit: 'm',
        status: 'FULL',
        created_at: new Date()
      },
      {
        id: 2,
        product_id: 1,
        piece_number: 2,
        length: 5.0,
        width: 3.0,
        unit: 'm',
        status: 'FULL',
        created_at: new Date()
      },
      {
        id: 3,
        product_id: 2,
        piece_number: 1,
        length: 200, // 200 cm = 2.0 m
        width: 150,  // 150 cm = 1.5 m
        unit: 'cm',
        status: 'USABLE', // Changed from WASTE to USABLE
        usable_length: 180, // 180 cm usable
        usable_width: 130,  // 130 cm usable
        created_at: new Date()
      }
    ];
    
    console.log(`  Created ${inventoryPieces.length} inventory pieces`);
    
    // Step 2: Calculate initial inventory summary
    const initialInventory = inventoryService.calculateInventorySummary(inventoryPieces, {
      targetUnit: 'm'
    });
    
    if (!initialInventory.isValid) {
      throw new Error('Initial inventory calculation failed');
    }
    
    console.log(`  Initial inventory: ${initialInventory.summary.totalPieces} pieces, ${initialInventory.summary.totalAreas.totalArea.toFixed(2)} m² total area`);
    
    // Step 3: Define BOM requirements (simulating production order)
    const bomRequirements = [
      {
        id: 1,
        product_id: 1,
        required_length: 2.5,
        required_width: 1.8,
        dimension_unit: 'm',
        isDimensionBased: () => true
      },
      {
        id: 2,
        product_id: 2,
        required_length: 80, // 80 cm
        required_width: 60,  // 60 cm
        dimension_unit: 'cm',
        isDimensionBased: () => true
      }
    ];
    
    console.log(`  BOM requirements: ${bomRequirements.length} items`);
    
    // Step 4: Allocate materials using allocation service
    const allocationResults = [];
    
    for (const bomItem of bomRequirements) {
      const productionQuantity = bomItem.id === 1 ? 3 : 2; // 3 for first item, 2 for second
      console.log(`  Allocating for BOM item ${bomItem.id}: ${bomItem.required_length}x${bomItem.required_width} ${bomItem.dimension_unit} x${productionQuantity}`);
      
      const allocation = allocationService.allocateMaterialForBOMItem(
        inventoryPieces,
        bomItem,
        productionQuantity,
        { strategy: 'BEST_FIT' }
      );
      
      if (allocation.isValid && allocation.allocatedPieces && allocation.allocatedPieces.length > 0) {
        for (const allocatedPiece of allocation.allocatedPieces) {
          allocationResults.push({
            bomItemId: bomItem.id,
            allocatedPiece: allocatedPiece.piece,
            requirement: bomItem
          });
          console.log(`    Allocated piece ${allocatedPiece.piece.id}`);
        }
      } else {
        console.log(`    No suitable pieces found: ${allocation.error || 'Unknown error'}`);
      }
    }
    
    console.log(`  Total allocations: ${allocationResults.length}`);
    
    // Step 5: Simulate cutting operations
    const cuttingOperations = [];
    
    for (const allocation of allocationResults) {
      const cuttingData = {
        production_order_id: 1,
        bom_item_id: allocation.bomItemId,
        cut_length: allocation.requirement.required_length,
        cut_width: allocation.requirement.required_width,
        unit: allocation.requirement.dimension_unit,
        operator_id: 1
      };
      
      const cuttingResult = cuttingService.processCuttingOperation(
        cuttingData,
        allocation.allocatedPiece
      );
      
      if (cuttingResult.isValid) {
        cuttingOperations.push(cuttingResult.cuttingOperation);
        console.log(`    Cut operation completed: ${cuttingResult.cuttingOperation.cut_area.toFixed(2)} area cut`);
        
        // Update inventory piece status (in real system, this would be persisted)
        if (cuttingResult.sourcePieceUpdates) {
          const piece = inventoryPieces.find(p => p.id === allocation.allocatedPiece.id);
          if (piece) {
            piece.status = cuttingResult.sourcePieceUpdates.newStatus;
            piece.usable_length = cuttingResult.sourcePieceUpdates.newUsableLength;
            piece.usable_width = cuttingResult.sourcePieceUpdates.newUsableWidth;
          }
        }
        
        // Add new waste pieces to inventory (in real system, these would be persisted)
        if (cuttingResult.newWastePieces) {
          for (const wastePiece of cuttingResult.newWastePieces) {
            inventoryPieces.push({
              id: inventoryPieces.length + 1,
              product_id: allocation.allocatedPiece.product_id,
              piece_number: inventoryPieces.length + 1,
              length: wastePiece.length,
              width: wastePiece.width,
              unit: wastePiece.unit,
              status: wastePiece.status,
              parent_piece_id: allocation.allocatedPiece.id,
              created_at: new Date()
            });
          }
        }
      } else {
        console.log(`    Cut operation failed for piece ${allocation.allocatedPiece.id}`);
      }
    }
    
    console.log(`  Completed ${cuttingOperations.length} cutting operations`);
    
    // Step 6: Calculate final inventory summary
    const finalInventory = inventoryService.calculateInventorySummary(inventoryPieces, {
      targetUnit: 'm'
    });
    
    if (!finalInventory.isValid) {
      throw new Error('Final inventory calculation failed');
    }
    
    console.log(`  Final inventory: ${finalInventory.summary.totalPieces} pieces, ${finalInventory.summary.totalAreas.totalArea.toFixed(2)} m² total area`);
    console.log(`  Status breakdown: FULL=${finalInventory.summary.piecesByStatus.FULL}, USABLE=${finalInventory.summary.piecesByStatus.USABLE}, WASTE=${finalInventory.summary.piecesByStatus.WASTE}, SCRAP=${finalInventory.summary.piecesByStatus.SCRAP}`);
    
    // Step 7: Generate utilization report
    const utilizationReport = utilizationService.calculateUtilizationEfficiency(
      cuttingOperations,
      inventoryPieces,
      { includeWasteAnalysis: true }
    );
    
    if (!utilizationReport.isValid) {
      throw new Error('Utilization report generation failed');
    }
    
    const metrics = utilizationReport.utilizationReport.overallMetrics;
    console.log(`  Material utilization: ${(metrics.materialUtilizationRate * 100).toFixed(1)}%`);
    console.log(`  Waste generation: ${(metrics.wasteGenerationRate * 100).toFixed(1)}%`);
    console.log(`  Waste reusability: ${(metrics.reusableWastePercentage * 100).toFixed(1)}%`);
    
    // Step 8: Generate recommendations
    const recommendations = utilizationService.generateUtilizationRecommendations(
      utilizationReport.utilizationReport,
      inventoryPieces
    );
    
    console.log(`  Generated ${recommendations.length} optimization recommendations`);
    if (recommendations.length > 0) {
      console.log(`  Top recommendation: ${recommendations[0].title} (${recommendations[0].priority})`);
    }
    
    console.log('✓ Integration test completed successfully\n');
    
    // Test 2: Cross-service validation
    console.log('Test 2: Cross-service validation');
    
    // Validate that dimension service works with all other services
    const testDimensions = { length: 2.5, width: 1.8, unit: 'm' };
    const dimValidation = dimensionService.validateDimensions(
      testDimensions.length,
      testDimensions.width,
      testDimensions.unit
    );
    
    if (!dimValidation.isValid) {
      throw new Error('Dimension validation failed');
    }
    
    console.log('  ✓ Dimension validation service integration');
    
    // Validate that all services handle unit conversion consistently
    const cmPiece = {
      id: 999,
      length: 250, // 250 cm = 2.5 m
      width: 180,  // 180 cm = 1.8 m
      unit: 'cm',
      status: 'FULL'
    };
    
    const areaInCm = inventoryService.calculatePieceAreas(cmPiece);
    const areaInM = inventoryService.calculatePieceAreas(cmPiece, { targetUnit: 'm' });
    
    if (!areaInCm.isValid || !areaInM.isValid) {
      throw new Error('Unit conversion validation failed');
    }
    
    // 250cm * 180cm = 45000 cm² = 4.5 m²
    const expectedAreaCm = 45000;
    const expectedAreaM = 4.5;
    
    if (Math.abs(areaInCm.totalArea - expectedAreaCm) > 0.1) {
      throw new Error(`Area calculation in cm failed: expected ${expectedAreaCm}, got ${areaInCm.totalArea}`);
    }
    
    if (Math.abs(areaInM.totalArea - expectedAreaM) > 0.01) {
      throw new Error(`Area calculation in m failed: expected ${expectedAreaM}, got ${areaInM.totalArea}`);
    }
    
    console.log('  ✓ Unit conversion consistency across services');
    
    // Validate that allocation service works with cutting service
    const testPiece = {
      id: 999,
      length: 250, // 250 cm = 2.5 m
      width: 180,  // 180 cm = 1.8 m
      unit: 'cm',
      status: 'FULL'
    };
    
    const testAllocation = allocationService.allocateMaterialForBOMItem(
      [testPiece],
      { 
        required_length: 200, 
        required_width: 150, 
        dimension_unit: 'cm',
        isDimensionBased: () => true
      },
      1 // production quantity
    );
    
    if (!testAllocation.isValid) {
      throw new Error('Test allocation failed');
    }
    
    const testCutting = cuttingService.processCuttingOperation(
      {
        production_order_id: 999,
        bom_item_id: 999,
        cut_length: 200,
        cut_width: 150,
        unit: 'cm'
      },
      testPiece
    );
    
    if (!testCutting.isValid) {
      throw new Error('Test cutting operation failed');
    }
    
    console.log('  ✓ Allocation and cutting service integration');
    
    console.log('✓ Cross-service validation completed successfully\n');
    
    // Test 3: Performance validation
    console.log('Test 3: Performance validation');
    
    const startTime = Date.now();
    
    // Generate larger dataset for performance testing
    const largePieceSet = [];
    for (let i = 0; i < 100; i++) {
      largePieceSet.push({
        id: i + 1,
        product_id: Math.floor(i / 20) + 1, // 5 products, 20 pieces each
        piece_number: (i % 20) + 1,
        length: Math.random() * 5 + 1,
        width: Math.random() * 4 + 1,
        unit: 'm',
        status: ['FULL', 'USABLE', 'WASTE', 'SCRAP'][Math.floor(Math.random() * 4)],
        created_at: new Date()
      });
    }
    
    // Test inventory calculation performance
    const largeInventoryResult = inventoryService.calculateInventorySummary(largePieceSet, {
      groupByProduct: true
    });
    
    if (!largeInventoryResult.isValid) {
      throw new Error('Large inventory calculation failed');
    }
    
    // Test inventory report generation performance
    const largeReportResult = inventoryService.generateInventoryReport(largePieceSet, {
      includeUtilization: true,
      includeAging: true,
      includeSuggestions: true
    });
    
    if (!largeReportResult.isValid) {
      throw new Error('Large report generation failed');
    }
    
    const endTime = Date.now();
    const processingTime = endTime - startTime;
    
    console.log(`  Processed ${largePieceSet.length} pieces in ${processingTime}ms`);
    console.log(`  Performance: ${(largePieceSet.length / processingTime * 1000).toFixed(0)} pieces/second`);
    
    if (processingTime > 5000) { // Should complete within 5 seconds
      console.log('  ⚠ Performance warning: Processing took longer than expected');
    } else {
      console.log('  ✓ Performance validation passed');
    }
    
    console.log('✓ Performance validation completed\n');
    
    return {
      success: true,
      message: 'All core services integration tests passed',
      metrics: {
        initialPieces: 3,
        finalPieces: finalInventory.summary.totalPieces,
        cuttingOperations: cuttingOperations.length,
        utilizationRate: metrics.materialUtilizationRate,
        wasteRate: metrics.wasteGenerationRate,
        recommendations: recommendations.length,
        performanceMs: processingTime
      }
    };
    
  } catch (error) {
    console.error('✗ Integration test failed:', error.message);
    return {
      success: false,
      error: error.message
    };
  }
}

// Run the integration test
runIntegrationTest().then((result) => {
  console.log('=== Core Services Integration Test Results ===');
  
  if (result.success) {
    console.log('Status: PASSED');
    console.log('Message:', result.message);
    console.log('\nMetrics:');
    console.log(`- Initial pieces: ${result.metrics.initialPieces}`);
    console.log(`- Final pieces: ${result.metrics.finalPieces}`);
    console.log(`- Cutting operations: ${result.metrics.cuttingOperations}`);
    console.log(`- Material utilization: ${(result.metrics.utilizationRate * 100).toFixed(1)}%`);
    console.log(`- Waste generation: ${(result.metrics.wasteRate * 100).toFixed(1)}%`);
    console.log(`- Recommendations: ${result.metrics.recommendations}`);
    console.log(`- Processing time: ${result.metrics.performanceMs}ms`);
    
    console.log('\n🎉 All core services are working correctly and ready for integration!');
    process.exit(0);
  } else {
    console.log('Status: FAILED');
    console.log('Error:', result.error);
    process.exit(1);
  }
}).catch(error => {
  console.error('Integration test runner error:', error);
  process.exit(1);
});