/**
 * RM Inventory Controller
 * Handles dimension-based Raw Material inventory operations
 */

// Import required models and services
const { RMInventoryPiece, Product, GRNItem } = require('../../../models');
const inventoryCalculationService = require('../../../services/inventoryCalculationService');
const materialUtilizationService = require('../../../services/materialUtilizationService');
// Import custom error classes
const { NotFoundError, ValidationError } = require('../../../utils/errors');
// Import logger
const logger = require('../../../utils/logger');
// Import Sequelize operators
const { Op } = require('sequelize');

/**
 * List RM inventory pieces with dimensions
 * GET /api/inventory/rm/:productId/pieces
 */
const listRMInventoryPieces = async (req, res) => {
  try {
    const { productId } = req.params;
    const { 
      status, 
      page = 1, 
      limit = 50,
      min_length,
      max_length,
      min_width,
      max_width,
      unit
    } = req.query;

    // Validate product exists and is RM
    const product = await Product.findByPk(productId);
    if (!product) {
      throw new NotFoundError(`Product with ID ${productId} not found`);
    }

    if (product.product_type !== 'RM') {
      throw new ValidationError('This endpoint is only for Raw Material (RM) products');
    }

    if (!product.track_by_dimensions) {
      throw new ValidationError('Product does not use dimension-based tracking');
    }

    // Build where clause
    const where = { product_id: productId };

    // Add status filter
    if (status) {
      if (!['FULL', 'USABLE', 'WASTE', 'SCRAP'].includes(status)) {
        throw new ValidationError('Invalid status. Must be one of: FULL, USABLE, WASTE, SCRAP');
      }
      where.status = status;
    }

    // Add dimension filters
    if (min_length) where.length = { [Op.gte]: parseFloat(min_length) };
    if (max_length) where.length = { ...where.length, [Op.lte]: parseFloat(max_length) };
    if (min_width) where.width = { [Op.gte]: parseFloat(min_width) };
    if (max_width) where.width = { ...where.width, [Op.lte]: parseFloat(max_width) };
    if (unit) where.unit = unit;

    // Calculate pagination
    const offset = (parseInt(page) - 1) * parseInt(limit);

    // Find pieces with pagination
    const { count, rows } = await RMInventoryPiece.findAndCountAll({
      where,
      include: [
        {
          model: Product,
          as: 'product',
          attributes: ['id', 'name', 'sku', 'product_type']
        },
        {
          model: GRNItem,
          as: 'grnItem',
          attributes: ['id', 'grn_id', 'product_id', 'quantity', 'unit_cost', 'piece_length', 'piece_width', 'dimension_unit', 'pieces_count'],
          required: false
        }
      ],
      limit: parseInt(limit),
      offset: offset,
      order: [['created_at', 'DESC']]
    });

    // Calculate pagination metadata
    const totalPages = Math.ceil(count / parseInt(limit));

    res.status(200).json({
      success: true,
      data: {
        pieces: rows,
        pagination: {
          page: parseInt(page),
          limit: parseInt(limit),
          total: count,
          totalPages: totalPages,
          hasNextPage: parseInt(page) < totalPages,
          hasPrevPage: parseInt(page) > 1
        }
      }
    });

  } catch (error) {
    logger.error('Error listing RM inventory pieces:', error);
    
    if (error instanceof NotFoundError || error instanceof ValidationError) {
      return res.status(error instanceof NotFoundError ? 404 : 400).json({
        success: false,
        error: error.message
      });
    }

    res.status(500).json({
      success: false,
      error: 'Internal server error'
    });
  }
};

/**
 * Get RM inventory summary with aggregated dimensions
 * GET /api/inventory/rm/:productId/summary
 */
const getRMInventorySummary = async (req, res) => {
  try {
    const { productId } = req.params;
    const { unit } = req.query;

    // Validate product exists and is RM
    const product = await Product.findByPk(productId);
    if (!product) {
      throw new NotFoundError(`Product with ID ${productId} not found`);
    }

    if (product.product_type !== 'RM') {
      throw new ValidationError('This endpoint is only for Raw Material (RM) products');
    }

    if (!product.track_by_dimensions) {
      throw new ValidationError('Product does not use dimension-based tracking');
    }

    // Get all pieces for this product
    const pieces = await RMInventoryPiece.findAll({
      where: { product_id: productId },
      include: [
        {
          model: Product,
          as: 'product',
          attributes: ['id', 'name', 'sku', 'unit_of_measure']
        }
      ]
    });

    // Calculate inventory summary using service
    const summaryResult = inventoryCalculationService.calculateInventorySummary(pieces, {
      targetUnit: unit || product.unit_of_measure,
      groupByStatus: true,
      includeUtilizationMetrics: true
    });

    if (!summaryResult.isValid) {
      throw new ValidationError(`Summary calculation failed: ${summaryResult.error}`);
    }

    // Get utilization statistics
    const utilizationResult = materialUtilizationService.calculateUtilizationStatistics(pieces, {
      timeRange: { days: 30 }, // Last 30 days
      includeWasteAnalysis: true
    });

    const response = {
      product: {
        id: product.id,
        name: product.name,
        sku: product.sku,
        unit_of_measure: product.unit_of_measure
      },
      summary: summaryResult.summary,
      utilization: utilizationResult.isValid ? utilizationResult.statistics : null,
      last_updated: new Date().toISOString()
    };

    res.status(200).json({
      success: true,
      data: response
    });

  } catch (error) {
    logger.error('Error getting RM inventory summary:', error);
    
    if (error instanceof NotFoundError || error instanceof ValidationError) {
      return res.status(error instanceof NotFoundError ? 404 : 400).json({
        success: false,
        error: error.message
      });
    }

    res.status(500).json({
      success: false,
      error: 'Internal server error'
    });
  }
};

/**
 * Write off scrap dimensions
 * POST /api/inventory/rm/:productId/write-off
 */
const writeOffScrapDimensions = async (req, res) => {
  try {
    const { productId } = req.params;
    const { piece_ids, reason, notes } = req.body;

    // Validate product exists and is RM
    const product = await Product.findByPk(productId);
    if (!product) {
      throw new NotFoundError(`Product with ID ${productId} not found`);
    }

    if (product.product_type !== 'RM') {
      throw new ValidationError('This endpoint is only for Raw Material (RM) products');
    }

    if (!product.track_by_dimensions) {
      throw new ValidationError('Product does not use dimension-based tracking');
    }

    // Validate request body
    if (!Array.isArray(piece_ids) || piece_ids.length === 0) {
      throw new ValidationError('piece_ids must be a non-empty array');
    }

    if (!reason) {
      throw new ValidationError('reason is required');
    }

    // Find pieces to write off
    const pieces = await RMInventoryPiece.findAll({
      where: {
        id: { [Op.in]: piece_ids },
        product_id: productId,
        status: { [Op.in]: ['SCRAP', 'WASTE'] } // Only allow write-off of SCRAP or WASTE pieces
      }
    });

    if (pieces.length === 0) {
      throw new ValidationError('No valid pieces found for write-off. Only SCRAP or WASTE pieces can be written off.');
    }

    if (pieces.length !== piece_ids.length) {
      const foundIds = pieces.map(p => p.id);
      const missingIds = piece_ids.filter(id => !foundIds.includes(parseInt(id)));
      throw new ValidationError(`Some pieces not found or not eligible for write-off: ${missingIds.join(', ')}`);
    }

    // Calculate total area being written off
    const totalAreaWrittenOff = pieces.reduce((sum, piece) => {
      const area = piece.status === 'SCRAP' ? 
        (piece.scrap_length || 0) * (piece.scrap_width || 0) :
        (piece.usable_length || piece.length) * (piece.usable_width || piece.width);
      return sum + area;
    }, 0);

    // Update pieces to WRITTEN_OFF status
    const writeOffResults = [];
    for (const piece of pieces) {
      const originalStatus = piece.status;
      const originalArea = piece.status === 'SCRAP' ? 
        (piece.scrap_length || 0) * (piece.scrap_width || 0) :
        (piece.usable_length || piece.length) * (piece.usable_width || piece.width);

      await piece.update({
        status: 'WRITTEN_OFF',
        written_off_at: new Date(),
        written_off_reason: reason,
        written_off_notes: notes,
        written_off_by: req.user.id
      });

      writeOffResults.push({
        piece_id: piece.id,
        piece_number: piece.piece_number,
        original_status: originalStatus,
        area_written_off: originalArea,
        unit: piece.unit
      });
    }

    logger.info(`Write-off completed: ${pieces.length} pieces, total area: ${totalAreaWrittenOff}, user: ${req.user.id}`);

    res.status(200).json({
      success: true,
      message: `Successfully written off ${pieces.length} pieces`,
      data: {
        pieces_written_off: writeOffResults,
        total_pieces: pieces.length,
        total_area_written_off: totalAreaWrittenOff,
        reason: reason,
        notes: notes,
        written_off_at: new Date().toISOString(),
        written_off_by: req.user.id
      }
    });

  } catch (error) {
    logger.error('Error writing off scrap dimensions:', error);
    
    if (error instanceof NotFoundError || error instanceof ValidationError) {
      return res.status(error instanceof NotFoundError ? 404 : 400).json({
        success: false,
        error: error.message
      });
    }

    res.status(500).json({
      success: false,
      error: 'Internal server error'
    });
  }
};

module.exports = {
  listRMInventoryPieces,
  getRMInventorySummary,
  writeOffScrapDimensions
};