/**
 * RM Cutting Operation Model
 * Tracks cutting operations on RM inventory pieces with waste and scrap generation
 * This model provides full audit trail for material usage and waste creation
 */

module.exports = (sequelize, DataTypes) => {
  // Define RMCuttingOperation model
  const RMCuttingOperation = sequelize.define('RMCuttingOperation', {
    // Primary key
    id: {
      type: DataTypes.BIGINT, // Use BIGINT for large scale
      primaryKey: true, // Set as primary key
      autoIncrement: true, // Auto-increment ID
    },
    // Foreign key to ProductionOrder
    production_order_id: {
      type: DataTypes.BIGINT, // Match ProductionOrder ID type
      allowNull: false, // Production order ID is required
      references: {
        model: 'production_orders', // Reference to production_orders table
        key: 'id', // Reference to id column
      },
      onUpdate: 'CASCADE', // Cascade update on production order update
      onDelete: 'CASCADE', // Cascade delete when production order is deleted
    },
    // Foreign key to RMInventoryPiece (original piece being cut)
    rm_piece_id: {
      type: DataTypes.BIGINT, // Match RMInventoryPiece ID type
      allowNull: false, // RM piece ID is required
      references: {
        model: 'rm_inventory_pieces', // Reference to rm_inventory_pieces table
        key: 'id', // Reference to id column
      },
      onUpdate: 'CASCADE', // Cascade update on RM piece update
      onDelete: 'CASCADE', // Cascade delete when RM piece is deleted
    },
    // Foreign key to BOMItem (which BOM item required this material)
    bom_item_id: {
      type: DataTypes.BIGINT, // Match BOMItem ID type
      allowNull: false, // BOM item ID is required
      references: {
        model: 'bom_items', // Reference to bom_items table
        key: 'id', // Reference to id column
      },
      onUpdate: 'CASCADE', // Cascade update on BOM item update
      onDelete: 'CASCADE', // Cascade delete when BOM item is deleted
    },
    // Dimensions cut from the original piece
    cut_length: {
      type: DataTypes.DECIMAL(12, 3), // Decimal with 12 digits, 3 decimal places
      allowNull: false, // Cut length is required
      validate: {
        min: 0.001, // Cut length must be positive
      },
    },
    cut_width: {
      type: DataTypes.DECIMAL(12, 3), // Decimal with 12 digits, 3 decimal places
      allowNull: false, // Cut width is required
      validate: {
        min: 0.001, // Cut width must be positive
      },
    },
    unit: {
      type: DataTypes.ENUM('inch', 'cm', 'm'), // Supported units for dimensions
      allowNull: false, // Unit is required
      defaultValue: 'm', // Default to meters
      validate: {
        isIn: [['inch', 'cm', 'm']], // Validate enum values
      },
    },
    // Foreign key to RMInventoryPiece (remaining piece after cutting, if any)
    remaining_piece_id: {
      type: DataTypes.BIGINT, // Match RMInventoryPiece ID type
      allowNull: true, // Remaining piece ID is optional (no remaining piece if fully consumed)
      references: {
        model: 'rm_inventory_pieces', // Reference to rm_inventory_pieces table
        key: 'id', // Reference to id column
      },
      onUpdate: 'CASCADE', // Cascade update on remaining piece update
      onDelete: 'SET NULL', // Set to null when remaining piece is deleted
    },
    // JSON field for waste pieces created during cutting
    waste_pieces: {
      type: DataTypes.JSON, // JSON field for array of waste pieces
      allowNull: true, // Waste pieces are optional (no waste if piece fully consumed)
      validate: {
        isValidWastePieces(value) {
          if (value !== null && value !== undefined) {
            if (!Array.isArray(value)) {
              throw new Error('waste_pieces must be an array');
            }
            for (const piece of value) {
              if (!piece.length || !piece.width || !piece.status) {
                throw new Error('Each waste piece must have length, width, and status');
              }
              if (!['WASTE', 'SCRAP'].includes(piece.status)) {
                throw new Error('Waste piece status must be WASTE or SCRAP');
              }
              if (piece.length <= 0 || piece.width <= 0) {
                throw new Error('Waste piece dimensions must be positive');
              }
            }
          }
        },
      },
    },
    // JSON field for scrap dimensions (unusable material)
    scrap_dimensions: {
      type: DataTypes.JSON, // JSON field for scrap dimensions
      allowNull: true, // Scrap dimensions are optional (no scrap if all material used/reusable)
      validate: {
        isValidScrapDimensions(value) {
          if (value !== null && value !== undefined) {
            if (typeof value !== 'object' || Array.isArray(value)) {
              throw new Error('scrap_dimensions must be an object');
            }
            if (value.length !== undefined && value.length < 0) {
              throw new Error('Scrap length cannot be negative');
            }
            if (value.width !== undefined && value.width < 0) {
              throw new Error('Scrap width cannot be negative');
            }
          }
        },
      },
    },
    // Foreign key to User (who performed the cutting operation)
    cut_by_user_id: {
      type: DataTypes.BIGINT, // Match User ID type
      allowNull: true, // Cut by user ID is optional (system operations)
      references: {
        model: 'users', // Reference to users table
        key: 'id', // Reference to id column
      },
      onUpdate: 'CASCADE', // Cascade update on user update
      onDelete: 'SET NULL', // Set to null when user is deleted
    },
    // When the cutting operation was performed
    cut_at: {
      type: DataTypes.DATE, // Date/time field
      allowNull: false, // Cut at is required
      defaultValue: DataTypes.NOW, // Default to current timestamp
    },
    // Additional notes about the cutting operation
    notes: {
      type: DataTypes.TEXT, // Text field for longer notes
      allowNull: true, // Notes are optional
    },
  }, {
    // Model options
    tableName: 'rm_cutting_operations', // Explicit table name
    underscored: true, // Use snake_case for database columns
    timestamps: true, // Enable createdAt and updatedAt timestamps
    createdAt: 'created_at', // Map createdAt to created_at column
    updatedAt: 'updated_at', // Map updatedAt to updated_at column
    indexes: [
      // Index on production_order_id for production queries
      {
        fields: ['production_order_id'], // Index on production order field
      },
      // Index on rm_piece_id for piece history queries
      {
        fields: ['rm_piece_id'], // Index on RM piece field
      },
      // Index on bom_item_id for BOM usage queries
      {
        fields: ['bom_item_id'], // Index on BOM item field
      },
      // Index on cut_at for chronological queries
      {
        fields: ['cut_at'], // Index on cut timestamp field
      },
      // Index on remaining_piece_id for traceability
      {
        fields: ['remaining_piece_id'], // Index on remaining piece field
      },
      // Composite index for audit trail queries
      {
        fields: ['production_order_id', 'rm_piece_id', 'cut_at'], // Audit trail optimization
      },
    ],
  });

  // Add instance methods for common operations
  RMCuttingOperation.prototype.getCutArea = function() {
    return parseFloat(this.cut_length) * parseFloat(this.cut_width);
  };

  RMCuttingOperation.prototype.getTotalWasteArea = function() {
    if (!this.waste_pieces || !Array.isArray(this.waste_pieces)) {
      return 0;
    }
    return this.waste_pieces.reduce((total, piece) => {
      return total + (parseFloat(piece.length) * parseFloat(piece.width));
    }, 0);
  };

  RMCuttingOperation.prototype.getScrapArea = function() {
    if (!this.scrap_dimensions) {
      return 0;
    }
    const scrap = this.scrap_dimensions;
    return (parseFloat(scrap.length) || 0) * (parseFloat(scrap.width) || 0);
  };

  RMCuttingOperation.prototype.getWastePiecesByStatus = function(status) {
    if (!this.waste_pieces || !Array.isArray(this.waste_pieces)) {
      return [];
    }
    return this.waste_pieces.filter(piece => piece.status === status);
  };

  RMCuttingOperation.prototype.hasRemainingPiece = function() {
    return this.remaining_piece_id !== null && this.remaining_piece_id !== undefined;
  };

  // Add class methods for common queries
  RMCuttingOperation.findByProductionOrder = async function(productionOrderId) {
    return await this.findAll({
      where: {
        production_order_id: productionOrderId
      },
      order: [['cut_at', 'ASC']]
    });
  };

  RMCuttingOperation.findByRMPiece = async function(rmPieceId) {
    return await this.findAll({
      where: {
        rm_piece_id: rmPieceId
      },
      order: [['cut_at', 'ASC']]
    });
  };

  RMCuttingOperation.getProductionMaterialUsage = async function(productionOrderId) {
    const operations = await this.findByProductionOrder(productionOrderId);
    
    const summary = {
      total_cut_area: 0,
      total_waste_area: 0,
      total_scrap_area: 0,
      pieces_cut: operations.length,
      waste_pieces_created: 0
    };
    
    operations.forEach(op => {
      summary.total_cut_area += op.getCutArea();
      summary.total_waste_area += op.getTotalWasteArea();
      summary.total_scrap_area += op.getScrapArea();
      if (op.waste_pieces && Array.isArray(op.waste_pieces)) {
        summary.waste_pieces_created += op.waste_pieces.length;
      }
    });
    
    return summary;
  };

  // Define model associations
  RMCuttingOperation.associate = (models) => {
    // RMCuttingOperation belongs to ProductionOrder (many-to-one relationship)
    RMCuttingOperation.belongsTo(models.ProductionOrder, {
      foreignKey: 'production_order_id', // Foreign key in RMCuttingOperation table
      as: 'productionOrder', // Alias for association
    });
    
    // RMCuttingOperation belongs to RMInventoryPiece (original piece, many-to-one relationship)
    RMCuttingOperation.belongsTo(models.RMInventoryPiece, {
      foreignKey: 'rm_piece_id', // Foreign key in RMCuttingOperation table
      as: 'originalPiece', // Alias for association
    });
    
    // RMCuttingOperation belongs to RMInventoryPiece (remaining piece, many-to-one relationship, optional)
    RMCuttingOperation.belongsTo(models.RMInventoryPiece, {
      foreignKey: 'remaining_piece_id', // Foreign key in RMCuttingOperation table
      as: 'remainingPiece', // Alias for association
    });
    
    // RMCuttingOperation belongs to BOMItem (many-to-one relationship)
    RMCuttingOperation.belongsTo(models.BOMItem, {
      foreignKey: 'bom_item_id', // Foreign key in RMCuttingOperation table
      as: 'bomItem', // Alias for association
    });
    
    // RMCuttingOperation belongs to User (many-to-one relationship, optional)
    RMCuttingOperation.belongsTo(models.User, {
      foreignKey: 'cut_by_user_id', // Foreign key in RMCuttingOperation table
      as: 'cutByUser', // Alias for association
    });
  };

  // Return RMCuttingOperation model
  return RMCuttingOperation;
};