/**
 * Material Utilization Reporting Service
 * Handles utilization efficiency calculations, waste generation statistics, and cost savings tracking
 */

const inventoryService = require('./inventoryCalculationService');
const dimensionService = require('./dimensionValidationService');

/**
 * Calculates material utilization efficiency for a set of cutting operations
 * @param {Array} cuttingOperations - Array of cutting operations
 * @param {Array} inventoryPieces - Array of RM inventory pieces
 * @param {Object} options - Calculation options
 * @returns {Object} Utilization efficiency report
 */
function calculateUtilizationEfficiency(cuttingOperations, inventoryPieces, options = {}) {
  const {
    timeRange = null,
    groupByProduct = false,
    groupByPeriod = null, // 'day', 'week', 'month'
    includeWasteAnalysis = true
  } = options;

  if (!Array.isArray(cuttingOperations)) {
    return {
      isValid: false,
      error: 'Cutting operations must be an array'
    };
  }

  if (!Array.isArray(inventoryPieces)) {
    return {
      isValid: false,
      error: 'Inventory pieces must be an array'
    };
  }

  // Filter operations by time range if specified
  let filteredOperations = cuttingOperations;
  if (timeRange && timeRange.start && timeRange.end) {
    filteredOperations = cuttingOperations.filter(op => {
      const cutDate = new Date(op.cut_at);
      return cutDate >= new Date(timeRange.start) && cutDate <= new Date(timeRange.end);
    });
  }

  // Calculate overall utilization metrics
  const utilizationMetrics = calculateOverallUtilization(filteredOperations, inventoryPieces);
  if (!utilizationMetrics.isValid) {
    return utilizationMetrics;
  }

  // Group by product if requested
  let productUtilization = null;
  if (groupByProduct) {
    productUtilization = calculateUtilizationByProduct(filteredOperations, inventoryPieces);
  }

  // Group by time period if requested
  let periodUtilization = null;
  if (groupByPeriod) {
    periodUtilization = calculateUtilizationByPeriod(filteredOperations, groupByPeriod);
  }

  // Calculate waste analysis if requested
  let wasteAnalysis = null;
  if (includeWasteAnalysis) {
    wasteAnalysis = calculateWasteAnalysis(filteredOperations, inventoryPieces);
  }

  return {
    isValid: true,
    utilizationReport: {
      overallMetrics: utilizationMetrics.metrics,
      productUtilization: productUtilization,
      periodUtilization: periodUtilization,
      wasteAnalysis: wasteAnalysis,
      reportPeriod: timeRange,
      generatedAt: new Date(),
      totalOperations: filteredOperations.length
    }
  };
}

/**
 * Calculates overall utilization metrics
 * @param {Array} cuttingOperations - Array of cutting operations
 * @param {Array} inventoryPieces - Array of RM inventory pieces
 * @returns {Object} Overall utilization metrics
 */
function calculateOverallUtilization(cuttingOperations, inventoryPieces) {
  let totalMaterialUsed = 0;
  let totalMaterialWasted = 0;
  let totalCutArea = 0;
  let totalSourceArea = 0;
  let operationsWithWaste = 0;
  let reusableWasteArea = 0;
  let scrapArea = 0;

  // Create a map of piece IDs to pieces for quick lookup
  const pieceMap = new Map();
  for (const piece of inventoryPieces) {
    pieceMap.set(piece.id, piece);
  }

  for (const operation of cuttingOperations) {
    if (!operation.cut_area || !operation.rm_piece_id) {
      continue; // Skip invalid operations
    }

    totalCutArea += operation.cut_area;

    // Find the source piece
    const sourcePiece = pieceMap.get(operation.rm_piece_id);
    if (sourcePiece) {
      const sourceArea = sourcePiece.length * sourcePiece.width;
      totalSourceArea += sourceArea;
      totalMaterialUsed += operation.cut_area;

      // Calculate waste from this operation
      if (operation.waste_pieces && Array.isArray(operation.waste_pieces)) {
        let operationWasteArea = 0;
        for (const wastePiece of operation.waste_pieces) {
          const wasteArea = wastePiece.length * wastePiece.width;
          operationWasteArea += wasteArea;
          
          if (wastePiece.status === 'WASTE') {
            reusableWasteArea += wasteArea;
          } else if (wastePiece.status === 'SCRAP') {
            scrapArea += wasteArea;
          }
        }
        
        if (operationWasteArea > 0) {
          operationsWithWaste++;
          totalMaterialWasted += operationWasteArea;
        }
      }
    }
  }

  // Calculate efficiency metrics
  const metrics = {
    totalOperations: cuttingOperations.length,
    totalCutArea: totalCutArea,
    totalSourceArea: totalSourceArea,
    totalWasteArea: totalMaterialWasted,
    materialUtilizationRate: totalSourceArea > 0 ? totalCutArea / totalSourceArea : 0,
    wasteGenerationRate: totalSourceArea > 0 ? totalMaterialWasted / totalSourceArea : 0,
    operationsWithWastePercentage: cuttingOperations.length > 0 ? 
      operationsWithWaste / cuttingOperations.length : 0,
    reusableWastePercentage: totalMaterialWasted > 0 ? 
      reusableWasteArea / totalMaterialWasted : 0,
    scrapPercentage: totalMaterialWasted > 0 ? 
      scrapArea / totalMaterialWasted : 0,
    averageCutEfficiency: cuttingOperations.length > 0 ? 
      totalCutArea / cuttingOperations.length : 0,
    wasteReusabilityScore: calculateWasteReusabilityScore(reusableWasteArea, scrapArea)
  };

  return {
    isValid: true,
    metrics: metrics
  };
}

/**
 * Calculates utilization metrics grouped by product
 * @param {Array} cuttingOperations - Array of cutting operations
 * @param {Array} inventoryPieces - Array of RM inventory pieces
 * @returns {Object} Product-grouped utilization metrics
 */
function calculateUtilizationByProduct(cuttingOperations, inventoryPieces) {
  const productGroups = new Map();
  const pieceMap = new Map();

  // Create piece lookup map
  for (const piece of inventoryPieces) {
    pieceMap.set(piece.id, piece);
  }

  // Group operations by product
  for (const operation of cuttingOperations) {
    const sourcePiece = pieceMap.get(operation.rm_piece_id);
    if (!sourcePiece) continue;

    const productId = sourcePiece.product_id;
    if (!productGroups.has(productId)) {
      productGroups.set(productId, []);
    }
    
    productGroups.get(productId).push(operation);
  }

  // Calculate metrics for each product
  const productMetrics = {};
  for (const [productId, operations] of productGroups) {
    const productPieces = inventoryPieces.filter(p => p.product_id === productId);
    const productUtilization = calculateOverallUtilization(operations, productPieces);
    
    if (productUtilization.isValid) {
      productMetrics[productId] = {
        ...productUtilization.metrics,
        productId: productId,
        operationsCount: operations.length
      };
    }
  }

  return {
    productMetrics: productMetrics,
    totalProducts: productGroups.size
  };
}

/**
 * Calculates utilization metrics grouped by time period
 * @param {Array} cuttingOperations - Array of cutting operations
 * @param {string} period - Time period ('day', 'week', 'month')
 * @returns {Object} Period-grouped utilization metrics
 */
function calculateUtilizationByPeriod(cuttingOperations, period) {
  const periodGroups = new Map();

  for (const operation of cuttingOperations) {
    if (!operation.cut_at) continue;

    const cutDate = new Date(operation.cut_at);
    let periodKey;

    switch (period) {
      case 'day':
        periodKey = cutDate.toISOString().split('T')[0]; // YYYY-MM-DD
        break;
      case 'week':
        const weekStart = new Date(cutDate);
        weekStart.setDate(cutDate.getDate() - cutDate.getDay());
        periodKey = weekStart.toISOString().split('T')[0];
        break;
      case 'month':
        periodKey = `${cutDate.getFullYear()}-${String(cutDate.getMonth() + 1).padStart(2, '0')}`;
        break;
      default:
        periodKey = cutDate.toISOString().split('T')[0];
    }

    if (!periodGroups.has(periodKey)) {
      periodGroups.set(periodKey, {
        operations: [],
        totalCutArea: 0,
        totalWasteArea: 0,
        operationsCount: 0
      });
    }

    const periodData = periodGroups.get(periodKey);
    periodData.operations.push(operation);
    periodData.totalCutArea += operation.cut_area || 0;
    periodData.operationsCount++;

    // Calculate waste for this operation
    if (operation.waste_pieces && Array.isArray(operation.waste_pieces)) {
      for (const wastePiece of operation.waste_pieces) {
        periodData.totalWasteArea += wastePiece.length * wastePiece.width;
      }
    }
  }

  // Convert to array and calculate metrics for each period
  const periodMetrics = Array.from(periodGroups.entries()).map(([periodKey, data]) => ({
    period: periodKey,
    operationsCount: data.operationsCount,
    totalCutArea: data.totalCutArea,
    totalWasteArea: data.totalWasteArea,
    averageCutArea: data.operationsCount > 0 ? data.totalCutArea / data.operationsCount : 0,
    wasteRatio: data.totalCutArea > 0 ? data.totalWasteArea / (data.totalCutArea + data.totalWasteArea) : 0
  }));

  return {
    periodMetrics: periodMetrics.sort((a, b) => a.period.localeCompare(b.period)),
    totalPeriods: periodMetrics.length,
    periodType: period
  };
}

/**
 * Calculates detailed waste analysis
 * @param {Array} cuttingOperations - Array of cutting operations
 * @param {Array} inventoryPieces - Array of RM inventory pieces
 * @returns {Object} Waste analysis report
 */
function calculateWasteAnalysis(cuttingOperations, inventoryPieces) {
  let totalWastePieces = 0;
  let reusableWastePieces = 0;
  let scrapPieces = 0;
  let totalWasteArea = 0;
  let reusableWasteArea = 0;
  let scrapArea = 0;
  const wasteSizeDistribution = {
    small: 0,    // < 0.1 m²
    medium: 0,   // 0.1 - 1.0 m²
    large: 0     // > 1.0 m²
  };

  for (const operation of cuttingOperations) {
    if (operation.waste_pieces && Array.isArray(operation.waste_pieces)) {
      for (const wastePiece of operation.waste_pieces) {
        totalWastePieces++;
        const wasteArea = wastePiece.length * wastePiece.width;
        totalWasteArea += wasteArea;

        if (wastePiece.status === 'WASTE') {
          reusableWastePieces++;
          reusableWasteArea += wasteArea;
        } else if (wastePiece.status === 'SCRAP') {
          scrapPieces++;
          scrapArea += wasteArea;
        }

        // Categorize by size (convert to m² for consistency)
        let areaSqM = wasteArea;
        if (wastePiece.unit === 'cm') {
          areaSqM = wasteArea / 10000;
        } else if (wastePiece.unit === 'inch') {
          areaSqM = wasteArea * 0.00064516;
        }

        if (areaSqM < 0.1) {
          wasteSizeDistribution.small++;
        } else if (areaSqM <= 1.0) {
          wasteSizeDistribution.medium++;
        } else {
          wasteSizeDistribution.large++;
        }
      }
    }
  }

  return {
    totalWastePieces: totalWastePieces,
    reusableWastePieces: reusableWastePieces,
    scrapPieces: scrapPieces,
    totalWasteArea: totalWasteArea,
    reusableWasteArea: reusableWasteArea,
    scrapArea: scrapArea,
    reusabilityRate: totalWastePieces > 0 ? reusableWastePieces / totalWastePieces : 0,
    wasteSizeDistribution: wasteSizeDistribution,
    averageWasteSize: totalWastePieces > 0 ? totalWasteArea / totalWastePieces : 0,
    wasteEfficiencyScore: calculateWasteEfficiencyScore(reusableWastePieces, scrapPieces, totalWasteArea)
  };
}

/**
 * Calculates cost savings from waste reuse
 * @param {Array} wasteReusageOperations - Array of operations that reused waste
 * @param {Object} materialCosts - Material cost information
 * @param {Object} options - Calculation options
 * @returns {Object} Cost savings report
 */
function calculateCostSavings(wasteReusageOperations, materialCosts, options = {}) {
  const {
    currency = 'USD',
    timeRange = null,
    includeProjections = false
  } = options;

  if (!Array.isArray(wasteReusageOperations)) {
    return {
      isValid: false,
      error: 'Waste reusage operations must be an array'
    };
  }

  let totalAreaReused = 0;
  let totalCostSaved = 0;
  let operationsCount = 0;
  const savingsByProduct = new Map();

  for (const operation of wasteReusageOperations) {
    if (!operation.reused_waste_area || !operation.product_id) {
      continue;
    }

    operationsCount++;
    totalAreaReused += operation.reused_waste_area;

    // Calculate cost savings for this operation
    const productCost = materialCosts[operation.product_id];
    if (productCost && productCost.costPerUnit) {
      const operationSavings = operation.reused_waste_area * productCost.costPerUnit;
      totalCostSaved += operationSavings;

      // Track savings by product
      if (!savingsByProduct.has(operation.product_id)) {
        savingsByProduct.set(operation.product_id, {
          productId: operation.product_id,
          totalAreaReused: 0,
          totalSavings: 0,
          operationsCount: 0
        });
      }

      const productSavings = savingsByProduct.get(operation.product_id);
      productSavings.totalAreaReused += operation.reused_waste_area;
      productSavings.totalSavings += operationSavings;
      productSavings.operationsCount++;
    }
  }

  // Calculate projections if requested
  let projections = null;
  if (includeProjections && operationsCount > 0) {
    projections = calculateSavingsProjections(totalCostSaved, operationsCount, timeRange);
  }

  return {
    isValid: true,
    costSavingsReport: {
      totalAreaReused: totalAreaReused,
      totalCostSaved: totalCostSaved,
      operationsCount: operationsCount,
      averageSavingsPerOperation: operationsCount > 0 ? totalCostSaved / operationsCount : 0,
      savingsByProduct: Array.from(savingsByProduct.values()),
      projections: projections,
      currency: currency,
      reportPeriod: timeRange,
      generatedAt: new Date()
    }
  };
}

/**
 * Generates material utilization recommendations
 * @param {Object} utilizationReport - Utilization efficiency report
 * @param {Array} inventoryPieces - Current inventory pieces
 * @param {Object} options - Recommendation options
 * @returns {Array} Array of recommendations
 */
function generateUtilizationRecommendations(utilizationReport, inventoryPieces, options = {}) {
  const {
    priorityThreshold = 0.7, // Utilization rate below this triggers recommendations
    includeWasteReuse = true,
    includeProcessOptimization = true
  } = options;

  const recommendations = [];

  if (!utilizationReport || !utilizationReport.overallMetrics) {
    return recommendations;
  }

  const metrics = utilizationReport.overallMetrics;

  // Low utilization rate recommendation
  if (metrics.materialUtilizationRate < priorityThreshold) {
    recommendations.push({
      type: 'UTILIZATION_IMPROVEMENT',
      priority: 'HIGH',
      title: 'Low Material Utilization Rate',
      description: `Current utilization rate is ${(metrics.materialUtilizationRate * 100).toFixed(1)}%, below target of ${(priorityThreshold * 100).toFixed(1)}%`,
      suggestions: [
        'Review cutting patterns for optimization opportunities',
        'Consider nesting algorithms to reduce waste',
        'Analyze piece sizes to identify better material dimensions for procurement'
      ],
      potentialImpact: 'Material cost reduction of 10-20%'
    });
  }

  // High waste generation recommendation
  if (metrics.wasteGenerationRate > 0.3) {
    recommendations.push({
      type: 'WASTE_REDUCTION',
      priority: 'HIGH',
      title: 'High Waste Generation',
      description: `Waste generation rate is ${(metrics.wasteGenerationRate * 100).toFixed(1)}%`,
      suggestions: [
        'Implement advanced cutting optimization software',
        'Train operators on efficient cutting techniques',
        'Review BOM requirements for potential adjustments'
      ],
      potentialImpact: 'Waste reduction of 15-25%'
    });
  }

  // Waste reuse opportunities
  if (includeWasteReuse && utilizationReport.wasteAnalysis) {
    const wasteAnalysis = utilizationReport.wasteAnalysis;
    if (wasteAnalysis.reusabilityRate < 0.6 && wasteAnalysis.reusableWastePieces > 0) {
      recommendations.push({
        type: 'WASTE_REUSE',
        priority: 'MEDIUM',
        title: 'Waste Reuse Opportunities',
        description: `${wasteAnalysis.reusableWastePieces} reusable waste pieces available`,
        suggestions: [
          'Create waste piece inventory for production planning',
          'Implement waste-first allocation policy',
          'Design smaller products that can use waste pieces'
        ],
        potentialImpact: 'Material cost savings of 5-15%'
      });
    }
  }

  // Scrap reduction recommendation
  if (metrics.scrapPercentage > 0.2) {
    recommendations.push({
      type: 'SCRAP_REDUCTION',
      priority: 'MEDIUM',
      title: 'High Scrap Generation',
      description: `${(metrics.scrapPercentage * 100).toFixed(1)}% of waste becomes scrap`,
      suggestions: [
        'Review minimum reusable dimensions policy',
        'Implement precision cutting techniques',
        'Consider alternative uses for small pieces'
      ],
      potentialImpact: 'Scrap reduction of 20-30%'
    });
  }

  // Process optimization recommendations
  if (includeProcessOptimization) {
    if (metrics.operationsWithWastePercentage > 0.8) {
      recommendations.push({
        type: 'PROCESS_OPTIMIZATION',
        priority: 'LOW',
        title: 'Consistent Waste Generation',
        description: `${(metrics.operationsWithWastePercentage * 100).toFixed(1)}% of operations generate waste`,
        suggestions: [
          'Standardize cutting procedures',
          'Implement lean manufacturing principles',
          'Consider batch processing for similar cuts'
        ],
        potentialImpact: 'Process efficiency improvement of 10-15%'
      });
    }
  }

  return recommendations.sort((a, b) => {
    const priorityOrder = { 'HIGH': 3, 'MEDIUM': 2, 'LOW': 1 };
    return priorityOrder[b.priority] - priorityOrder[a.priority];
  });
}

// Helper functions

/**
 * Calculates waste reusability score
 * @param {number} reusableWasteArea - Total reusable waste area
 * @param {number} scrapArea - Total scrap area
 * @returns {number} Reusability score (0-1)
 */
function calculateWasteReusabilityScore(reusableWasteArea, scrapArea) {
  const totalWaste = reusableWasteArea + scrapArea;
  if (totalWaste === 0) return 1; // No waste is perfect
  return reusableWasteArea / totalWaste;
}

/**
 * Calculates waste efficiency score
 * @param {number} reusableWastePieces - Number of reusable waste pieces
 * @param {number} scrapPieces - Number of scrap pieces
 * @param {number} totalWasteArea - Total waste area
 * @returns {number} Efficiency score (0-1)
 */
function calculateWasteEfficiencyScore(reusableWastePieces, scrapPieces, totalWasteArea) {
  const totalPieces = reusableWastePieces + scrapPieces;
  if (totalPieces === 0) return 1;
  
  const reusabilityRatio = reusableWastePieces / totalPieces;
  const averageWasteSize = totalWasteArea / totalPieces;
  
  // Score based on reusability ratio and average size (larger pieces are better)
  return (reusabilityRatio * 0.7) + (Math.min(averageWasteSize, 1.0) * 0.3);
}

/**
 * Calculates savings projections
 * @param {number} totalSavings - Total savings in the period
 * @param {number} operationsCount - Number of operations
 * @param {Object} timeRange - Time range of the data
 * @returns {Object} Projections
 */
function calculateSavingsProjections(totalSavings, operationsCount, timeRange) {
  if (!timeRange || !timeRange.start || !timeRange.end) {
    return null;
  }

  const startDate = new Date(timeRange.start);
  const endDate = new Date(timeRange.end);
  const daysInPeriod = Math.ceil((endDate - startDate) / (1000 * 60 * 60 * 24));
  
  const dailyAverage = totalSavings / daysInPeriod;
  const monthlyProjection = dailyAverage * 30;
  const yearlyProjection = dailyAverage * 365;

  return {
    dailyAverage: dailyAverage,
    monthlyProjection: monthlyProjection,
    yearlyProjection: yearlyProjection,
    basedOnDays: daysInPeriod,
    basedOnOperations: operationsCount
  };
}

module.exports = {
  calculateUtilizationEfficiency,
  calculateOverallUtilization,
  calculateUtilizationByProduct,
  calculateUtilizationByPeriod,
  calculateWasteAnalysis,
  calculateCostSavings,
  generateUtilizationRecommendations,
  calculateWasteReusabilityScore,
  calculateWasteEfficiencyScore
};