/**
 * Inventory Calculation Service
 * Handles inventory summary calculations, area calculations, and piece counting for RM inventory
 */

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

/**
 * Piece status types for inventory calculations
 */
const PIECE_STATUS = {
  FULL: 'FULL',
  USABLE: 'USABLE', 
  WASTE: 'WASTE',
  SCRAP: 'SCRAP'
};

/**
 * Calculates inventory summary for RM products
 * @param {Array} inventoryPieces - Array of RM inventory pieces
 * @param {Object} options - Calculation options
 * @returns {Object} Inventory summary
 */
function calculateInventorySummary(inventoryPieces, options = {}) {
  const {
    groupByProduct = false,
    groupByDimensions = false,
    includeScrap = false,
    targetUnit = null
  } = options;

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

  // Group pieces by product if requested
  if (groupByProduct) {
    return calculateInventorySummaryByProduct(inventoryPieces, options);
  }

  // Calculate overall summary
  const summary = {
    totalPieces: 0,
    piecesByStatus: {
      [PIECE_STATUS.FULL]: 0,
      [PIECE_STATUS.USABLE]: 0,
      [PIECE_STATUS.WASTE]: 0,
      [PIECE_STATUS.SCRAP]: 0
    },
    totalAreas: {
      fullArea: 0,
      usableArea: 0,
      wasteArea: 0,
      scrapArea: 0,
      totalArea: 0
    },
    dimensionVariations: [],
    utilizationStatistics: {
      utilizationRate: 0,
      wasteRate: 0,
      scrapRate: 0
    }
  };

  const dimensionGroups = new Map();

  for (const piece of inventoryPieces) {
    // Validate piece data
    const validation = validateInventoryPiece(piece);
    if (!validation.isValid) {
      continue; // Skip invalid pieces
    }

    // Count pieces by status
    summary.totalPieces++;
    if (summary.piecesByStatus.hasOwnProperty(piece.status)) {
      summary.piecesByStatus[piece.status]++;
    }

    // Calculate areas
    const areaCalculation = calculatePieceAreas(piece, { targetUnit });
    if (areaCalculation.isValid) {
      summary.totalAreas.fullArea += areaCalculation.fullArea;
      summary.totalAreas.usableArea += areaCalculation.usableArea;
      summary.totalAreas.wasteArea += areaCalculation.wasteArea;
      summary.totalAreas.scrapArea += areaCalculation.scrapArea;
      summary.totalAreas.totalArea += areaCalculation.totalArea;
    }

    // Track dimension variations
    const dimensionKey = `${piece.length}x${piece.width}x${piece.unit}`;
    if (!dimensionGroups.has(dimensionKey)) {
      dimensionGroups.set(dimensionKey, {
        length: piece.length,
        width: piece.width,
        unit: piece.unit,
        pieces: 0,
        statuses: new Set()
      });
    }
    
    const dimGroup = dimensionGroups.get(dimensionKey);
    dimGroup.pieces++;
    dimGroup.statuses.add(piece.status);
  }

  // Convert dimension groups to array
  summary.dimensionVariations = Array.from(dimensionGroups.values()).map(group => ({
    ...group,
    statuses: Array.from(group.statuses)
  }));

  // Calculate utilization statistics
  if (summary.totalAreas.totalArea > 0) {
    // For utilization rate, we should count usableArea (which includes fullArea for FULL pieces)
    // but not double-count fullArea
    summary.utilizationStatistics.utilizationRate = 
      summary.totalAreas.usableArea / summary.totalAreas.totalArea;
    summary.utilizationStatistics.wasteRate = 
      summary.totalAreas.wasteArea / summary.totalAreas.totalArea;
    summary.utilizationStatistics.scrapRate = 
      summary.totalAreas.scrapArea / summary.totalAreas.totalArea;
  }

  return {
    isValid: true,
    summary: summary,
    calculatedAt: new Date(),
    options: options
  };
}

/**
 * Calculates inventory summary grouped by product
 * @param {Array} inventoryPieces - Array of RM inventory pieces
 * @param {Object} options - Calculation options
 * @returns {Object} Product-grouped inventory summary
 */
function calculateInventorySummaryByProduct(inventoryPieces, options = {}) {
  const productGroups = new Map();

  for (const piece of inventoryPieces) {
    const productId = piece.product_id;
    
    if (!productGroups.has(productId)) {
      productGroups.set(productId, []);
    }
    
    productGroups.get(productId).push(piece);
  }

  const productSummaries = {};
  let overallSummary = {
    totalProducts: productGroups.size,
    totalPieces: 0,
    totalArea: 0,
    piecesByStatus: {
      [PIECE_STATUS.FULL]: 0,
      [PIECE_STATUS.USABLE]: 0,
      [PIECE_STATUS.WASTE]: 0,
      [PIECE_STATUS.SCRAP]: 0
    }
  };

  for (const [productId, pieces] of productGroups) {
    const productSummary = calculateInventorySummary(pieces, {
      ...options,
      groupByProduct: false // Prevent infinite recursion
    });

    if (productSummary.isValid) {
      productSummaries[productId] = productSummary.summary;
      
      // Aggregate to overall summary
      overallSummary.totalPieces += productSummary.summary.totalPieces;
      overallSummary.totalArea += productSummary.summary.totalAreas.totalArea;
      
      for (const status of Object.keys(overallSummary.piecesByStatus)) {
        overallSummary.piecesByStatus[status] += productSummary.summary.piecesByStatus[status];
      }
    }
  }

  return {
    isValid: true,
    productSummaries: productSummaries,
    overallSummary: overallSummary,
    calculatedAt: new Date()
  };
}

/**
 * Calculates areas for a single inventory piece
 * @param {Object} piece - RM inventory piece
 * @param {Object} options - Calculation options
 * @returns {Object} Area calculations
 */
function calculatePieceAreas(piece, options = {}) {
  const { targetUnit = null } = options;

  const validation = validateInventoryPiece(piece);
  if (!validation.isValid) {
    return validation;
  }

  let length = piece.length;
  let width = piece.width;
  let unit = piece.unit;

  // Convert to target unit if specified
  if (targetUnit && targetUnit !== unit) {
    const conversionResult = dimensionService.convertDimensions(
      { length, width, unit },
      targetUnit
    );
    
    if (conversionResult.isValid) {
      length = conversionResult.dimensions.length;
      width = conversionResult.dimensions.width;
      unit = targetUnit;
    } else {
      return {
        isValid: false,
        error: 'Unit conversion failed'
      };
    }
  }

  // Calculate base area
  const baseArea = length * width;
  
  let fullArea = 0;
  let usableArea = 0;
  let wasteArea = 0;
  let scrapArea = 0;

  switch (piece.status) {
    case PIECE_STATUS.FULL:
      fullArea = baseArea;
      usableArea = baseArea; // FULL pieces are fully usable
      break;
      
    case PIECE_STATUS.USABLE:
      if (piece.usable_length && piece.usable_width) {
        // Convert usable dimensions if needed
        let usableLength = piece.usable_length;
        let usableWidth = piece.usable_width;
        
        if (targetUnit && targetUnit !== piece.unit) {
          const usableConversion = dimensionService.convertDimensions(
            { length: usableLength, width: usableWidth, unit: piece.unit },
            targetUnit
          );
          
          if (usableConversion.isValid) {
            usableLength = usableConversion.dimensions.length;
            usableWidth = usableConversion.dimensions.width;
          }
        }
        
        usableArea = usableLength * usableWidth;
        wasteArea = baseArea - usableArea; // Remaining area is waste
      } else {
        usableArea = baseArea; // Fallback if usable dimensions not specified
      }
      break;
      
    case PIECE_STATUS.WASTE:
      wasteArea = baseArea;
      break;
      
    case PIECE_STATUS.SCRAP:
      scrapArea = baseArea;
      break;
      
    default:
      return {
        isValid: false,
        error: `Unknown piece status: ${piece.status}`
      };
  }

  return {
    isValid: true,
    fullArea: fullArea,
    usableArea: usableArea,
    wasteArea: wasteArea,
    scrapArea: scrapArea,
    totalArea: baseArea,
    unit: unit,
    originalUnit: piece.unit
  };
}

/**
 * Counts pieces by status and dimensions
 * @param {Array} inventoryPieces - Array of RM inventory pieces
 * @param {Object} options - Counting options
 * @returns {Object} Piece count results
 */
function countPiecesByStatus(inventoryPieces, options = {}) {
  const {
    filterByStatus = null,
    filterByDimensions = null,
    groupByDimensions = false
  } = options;

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

  let filteredPieces = inventoryPieces;

  // Apply status filter
  if (filterByStatus) {
    const statusArray = Array.isArray(filterByStatus) ? filterByStatus : [filterByStatus];
    filteredPieces = filteredPieces.filter(piece => statusArray.includes(piece.status));
  }

  // Apply dimension filter
  if (filterByDimensions) {
    filteredPieces = filteredPieces.filter(piece => {
      return dimensionService.checkDimensionSufficiency(
        { length: piece.length, width: piece.width, unit: piece.unit },
        filterByDimensions
      ).canFit;
    });
  }

  if (groupByDimensions) {
    return countPiecesByDimensions(filteredPieces);
  }

  // Simple status counting
  const counts = {
    [PIECE_STATUS.FULL]: 0,
    [PIECE_STATUS.USABLE]: 0,
    [PIECE_STATUS.WASTE]: 0,
    [PIECE_STATUS.SCRAP]: 0,
    total: 0
  };

  for (const piece of filteredPieces) {
    if (counts.hasOwnProperty(piece.status)) {
      counts[piece.status]++;
    }
    counts.total++;
  }

  return {
    isValid: true,
    counts: counts,
    filteredCount: filteredPieces.length,
    originalCount: inventoryPieces.length
  };
}

/**
 * Counts pieces grouped by dimensions
 * @param {Array} inventoryPieces - Array of RM inventory pieces
 * @returns {Object} Dimension-grouped counts
 */
function countPiecesByDimensions(inventoryPieces) {
  const dimensionGroups = new Map();

  for (const piece of inventoryPieces) {
    const dimensionKey = `${piece.length}x${piece.width}x${piece.unit}`;
    
    if (!dimensionGroups.has(dimensionKey)) {
      dimensionGroups.set(dimensionKey, {
        length: piece.length,
        width: piece.width,
        unit: piece.unit,
        area: piece.length * piece.width,
        statusCounts: {
          [PIECE_STATUS.FULL]: 0,
          [PIECE_STATUS.USABLE]: 0,
          [PIECE_STATUS.WASTE]: 0,
          [PIECE_STATUS.SCRAP]: 0
        },
        totalPieces: 0
      });
    }

    const group = dimensionGroups.get(dimensionKey);
    if (group.statusCounts.hasOwnProperty(piece.status)) {
      group.statusCounts[piece.status]++;
    }
    group.totalPieces++;
  }

  return {
    isValid: true,
    dimensionGroups: Array.from(dimensionGroups.values()),
    totalGroups: dimensionGroups.size
  };
}

/**
 * Generates detailed inventory report
 * @param {Array} inventoryPieces - Array of RM inventory pieces
 * @param {Object} options - Report options
 * @returns {Object} Detailed inventory report
 */
function generateInventoryReport(inventoryPieces, options = {}) {
  const {
    includeUtilization = true,
    includeAging = false,
    includeSuggestions = false,
    targetUnit = 'm'
  } = options;

  // Calculate basic summary
  const summary = calculateInventorySummary(inventoryPieces, { targetUnit });
  if (!summary.isValid) {
    return summary;
  }

  // Count pieces by status
  const statusCounts = countPiecesByStatus(inventoryPieces);
  if (!statusCounts.isValid) {
    return statusCounts;
  }

  // Count pieces by dimensions
  const dimensionCounts = countPiecesByStatus(inventoryPieces, { groupByDimensions: true });
  if (!dimensionCounts.isValid) {
    return dimensionCounts;
  }

  const report = {
    summary: summary.summary,
    statusCounts: statusCounts.counts,
    dimensionBreakdown: dimensionCounts.dimensionGroups,
    reportOptions: options,
    generatedAt: new Date()
  };

  // Add utilization analysis if requested
  if (includeUtilization) {
    report.utilizationAnalysis = calculateUtilizationAnalysis(inventoryPieces);
  }

  // Add aging analysis if requested
  if (includeAging) {
    report.agingAnalysis = calculateAgingAnalysis(inventoryPieces);
  }

  // Add optimization suggestions if requested
  if (includeSuggestions) {
    report.optimizationSuggestions = generateOptimizationSuggestions(inventoryPieces);
  }

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

/**
 * Calculates utilization analysis for inventory pieces
 * @param {Array} inventoryPieces - Array of RM inventory pieces
 * @returns {Object} Utilization analysis
 */
function calculateUtilizationAnalysis(inventoryPieces) {
  const analysis = {
    totalPieces: inventoryPieces.length,
    fullyUtilized: 0,
    partiallyUtilized: 0,
    unutilized: 0,
    averageUtilization: 0,
    wasteGeneration: 0
  };

  let totalUtilization = 0;
  let totalWasteArea = 0;
  let totalOriginalArea = 0;

  for (const piece of inventoryPieces) {
    const areaCalc = calculatePieceAreas(piece);
    if (!areaCalc.isValid) continue;

    totalOriginalArea += areaCalc.totalArea;
    totalWasteArea += areaCalc.wasteArea + areaCalc.scrapArea;

    const pieceUtilization = (areaCalc.usableArea + areaCalc.fullArea) / areaCalc.totalArea;
    totalUtilization += pieceUtilization;

    if (pieceUtilization >= 0.95) {
      analysis.fullyUtilized++;
    } else if (pieceUtilization > 0.1) {
      analysis.partiallyUtilized++;
    } else {
      analysis.unutilized++;
    }
  }

  if (inventoryPieces.length > 0) {
    analysis.averageUtilization = totalUtilization / inventoryPieces.length;
  }

  if (totalOriginalArea > 0) {
    analysis.wasteGeneration = totalWasteArea / totalOriginalArea;
  }

  return analysis;
}

/**
 * Calculates aging analysis for waste pieces
 * @param {Array} inventoryPieces - Array of RM inventory pieces
 * @returns {Object} Aging analysis
 */
function calculateAgingAnalysis(inventoryPieces) {
  const now = new Date();
  const wastePieces = inventoryPieces.filter(p => p.status === PIECE_STATUS.WASTE);
  
  const aging = {
    totalWastePieces: wastePieces.length,
    ageGroups: {
      fresh: 0,      // < 30 days
      aging: 0,      // 30-90 days
      old: 0,        // 90-180 days
      stale: 0       // > 180 days
    },
    averageAge: 0,
    oldestPiece: null
  };

  let totalAge = 0;
  let oldestAge = 0;

  for (const piece of wastePieces) {
    const createdAt = new Date(piece.created_at || piece.updated_at || now);
    const ageInDays = Math.floor((now - createdAt) / (1000 * 60 * 60 * 24));
    
    totalAge += ageInDays;
    
    if (ageInDays > oldestAge) {
      oldestAge = ageInDays;
      aging.oldestPiece = {
        id: piece.id,
        age: ageInDays,
        dimensions: `${piece.length}x${piece.width} ${piece.unit}`
      };
    }

    if (ageInDays < 30) {
      aging.ageGroups.fresh++;
    } else if (ageInDays < 90) {
      aging.ageGroups.aging++;
    } else if (ageInDays < 180) {
      aging.ageGroups.old++;
    } else {
      aging.ageGroups.stale++;
    }
  }

  if (wastePieces.length > 0) {
    aging.averageAge = totalAge / wastePieces.length;
  }

  return aging;
}

/**
 * Generates optimization suggestions based on inventory analysis
 * @param {Array} inventoryPieces - Array of RM inventory pieces
 * @returns {Array} Array of optimization suggestions
 */
function generateOptimizationSuggestions(inventoryPieces) {
  const suggestions = [];
  
  // Analyze waste pieces for reuse opportunities
  const wastePieces = inventoryPieces.filter(p => p.status === PIECE_STATUS.WASTE);
  if (wastePieces.length > 0) {
    suggestions.push({
      type: 'WASTE_REUSE',
      priority: 'HIGH',
      message: `${wastePieces.length} waste pieces available for reuse`,
      action: 'Review waste pieces for upcoming production orders',
      potentialSavings: 'Material cost reduction'
    });
  }

  // Analyze scrap pieces for write-off
  const scrapPieces = inventoryPieces.filter(p => p.status === PIECE_STATUS.SCRAP);
  if (scrapPieces.length > 10) {
    suggestions.push({
      type: 'SCRAP_WRITEOFF',
      priority: 'MEDIUM',
      message: `${scrapPieces.length} scrap pieces should be written off`,
      action: 'Process scrap write-off to clean up inventory',
      potentialSavings: 'Inventory accuracy improvement'
    });
  }

  // Analyze dimension consolidation opportunities
  const dimensionGroups = countPiecesByStatus(inventoryPieces, { groupByDimensions: true });
  if (dimensionGroups.isValid && dimensionGroups.dimensionGroups.length > 20) {
    suggestions.push({
      type: 'DIMENSION_CONSOLIDATION',
      priority: 'LOW',
      message: `${dimensionGroups.dimensionGroups.length} different dimension variations`,
      action: 'Consider standardizing material dimensions for future purchases',
      potentialSavings: 'Inventory management efficiency'
    });
  }

  return suggestions;
}

/**
 * Validates inventory piece data
 * @param {Object} piece - Inventory piece to validate
 * @returns {Object} Validation result
 */
function validateInventoryPiece(piece) {
  if (!piece) {
    return {
      isValid: false,
      error: 'Piece is required'
    };
  }

  if (!piece.length || !piece.width || !piece.unit) {
    return {
      isValid: false,
      error: 'Piece must have length, width, and unit'
    };
  }

  if (!piece.status || !Object.values(PIECE_STATUS).includes(piece.status)) {
    return {
      isValid: false,
      error: 'Piece must have valid status'
    };
  }

  // Validate dimensions
  const dimValidation = dimensionService.validateDimensions(piece.length, piece.width, piece.unit);
  if (!dimValidation.isValid) {
    return dimValidation;
  }

  return {
    isValid: true
  };
}

module.exports = {
  calculateInventorySummary,
  calculateInventorySummaryByProduct,
  calculatePieceAreas,
  countPiecesByStatus,
  countPiecesByDimensions,
  generateInventoryReport,
  calculateUtilizationAnalysis,
  calculateAgingAnalysis,
  generateOptimizationSuggestions,
  validateInventoryPiece,
  PIECE_STATUS
};