/**
 * Product Model
 * Represents products - can be Finished Goods (FG) or Raw Materials (RM)
 */

module.exports = (sequelize, DataTypes) => {
  // Define Product model
  const Product = sequelize.define('Product', {
    // Primary key
    id: {
      type: DataTypes.BIGINT, // Use BIGINT for large scale
      primaryKey: true, // Set as primary key
      autoIncrement: true, // Auto-increment ID
    },
    // Product name
    name: {
      type: DataTypes.STRING(150), // Product name with max length
      allowNull: false, // Name is required
      validate: {
        notEmpty: true, // Name cannot be empty string
      },
    },
    // Stock Keeping Unit (unique identifier)
    sku: {
      type: DataTypes.STRING(100), // SKU with max length
      allowNull: true, // SKU is optional
      unique: true, // SKU must be unique if provided
      validate: {
        len: [0, 100], // Maximum length validation
      },
    },
    // Product type (Finished Goods or Raw Materials)
    product_type: {
      type: DataTypes.ENUM('FG', 'RM'), // Enum for product type
      allowNull: false, // Product type is required
      validate: {
        isIn: [['FG', 'RM']], // Validate enum values
      },
    },
    // Whether to track inventory for this product
    track_inventory: {
      type: DataTypes.BOOLEAN, // Boolean for inventory tracking
      defaultValue: true, // Default to tracking inventory
      allowNull: false, // Track inventory flag is required
    },
    // Product description (added enhancement)
    description: {
      type: DataTypes.TEXT, // Text field for longer descriptions
      allowNull: true, // Description is optional
    },
    // Product image URL or path
    image_url: {
      type: DataTypes.STRING(255), // Image URL with max length
      allowNull: true, // Image URL is optional
      validate: {
        len: [0, 255], // Maximum length validation
      },
    },
    // Whether product can be sold on POS
    sell_on_pos: {
      type: DataTypes.BOOLEAN, // Boolean for POS sellability
      defaultValue: true, // Default to sellable (FG), RM should be false
      allowNull: false, // Sell on POS flag is required
    },
    // Default selling price (simple fallback when price list prices aren't available)
    selling_price: {
      type: DataTypes.DECIMAL(12, 2), // Decimal with 12 digits, 2 decimal places
      allowNull: true, // Selling price is optional (can use price lists instead)
      validate: {
        min: 0, // Price cannot be negative
      },
    },
    // Low stock threshold - alert when stock falls below this quantity
    low_stock_threshold: {
      type: DataTypes.DECIMAL(12, 3), // Decimal with 12 digits, 3 decimal places
      allowNull: true, // Low stock threshold is optional
      defaultValue: 0, // Default to 0 (no threshold)
      validate: {
        min: 0, // Threshold cannot be negative
      },
    },
    // Unit of measure for dimension-based tracking (only required for dimension-based RM)
    unit_of_measure: {
      type: DataTypes.ENUM('inch', 'cm', 'm'), // Supported units for dimensions
      defaultValue: 'm', // Default to meters
      allowNull: true, // Allow null for special items RM (quantity-based)
      validate: {
        isIn: [['inch', 'cm', 'm']], // Validate enum values
      },
    },
    // Whether to track inventory by dimensions (mandatory for RM products)
    track_by_dimensions: {
      type: DataTypes.BOOLEAN, // Boolean for dimension tracking
      defaultValue: false, // Default to false, but will be enforced as true for RM
      allowNull: false, // Track by dimensions flag is required
    },
  }, {
    // Model options
    tableName: 'products', // 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 SKU for faster lookups
      {
        unique: true, // Unique index
        fields: ['sku'], // Index on SKU field
        where: {
          sku: {
            [sequelize.Sequelize.Op.ne]: null, // Only index non-null SKUs
          },
        },
      },
      // Index on product_type for filtering
      {
        fields: ['product_type'], // Index on product_type field
      },
      // Index on sell_on_pos for filtering
      {
        fields: ['sell_on_pos'], // Index on sell_on_pos field
      },
      // Index on dimension tracking for RM products
      {
        fields: ['product_type', 'track_by_dimensions'], // Composite index for dimension queries
      },
    ],
  });

  // Add validation hooks to enforce business rules
  Product.addHook('beforeValidate', (product, options) => {
    // Handle RM products: default to dimension-based if not explicitly set
    if (product.product_type === 'RM') {
      // If track_by_dimensions is explicitly set, respect it
      // Otherwise, default to true (dimension-based) for backward compatibility
      if (product.track_by_dimensions === undefined || product.track_by_dimensions === null) {
        product.track_by_dimensions = true;
      }
      
      // For dimension-based RM, ensure unit_of_measure is set
      if (product.track_by_dimensions === true && !product.unit_of_measure) {
        product.unit_of_measure = 'm'; // Default to meters
      }
    }
  });

  Product.addHook('beforeUpdate', (product, options) => {
    // Allow both dimension-based and special items RM
    // Dimension-based RM: track_by_dimensions = true (requires unit_of_measure)
    // Special items RM: track_by_dimensions = false (quantity-based, no unit_of_measure required)
    if (product.product_type === 'RM') {
      // If switching to dimension-based, ensure unit_of_measure is set
      if (product.track_by_dimensions === true && !product.unit_of_measure) {
        product.unit_of_measure = 'm'; // Default to meters
      }
      // Special items RM (track_by_dimensions = false) don't need unit_of_measure validation
    }
  });

  // Define model associations
  Product.associate = (models) => {
    // Product has many Inventories (one-to-many relationship)
    Product.hasMany(models.Inventory, {
      foreignKey: 'product_id', // Foreign key in Inventories table
      as: 'inventories', // Alias for association
    });
    
    // Product has many InventoryItems (one-to-many relationship)
    Product.hasMany(models.InventoryItem, {
      foreignKey: 'product_id', // Foreign key in InventoryItems table
      as: 'inventoryItems', // Alias for association
    });
    
    // Product has many InventoryMovements (one-to-many relationship)
    Product.hasMany(models.InventoryMovement, {
      foreignKey: 'product_id', // Foreign key in InventoryMovements table
      as: 'inventoryMovements', // Alias for association
    });
    
    // Product has many SaleItems (one-to-many relationship)
    Product.hasMany(models.SaleItem, {
      foreignKey: 'product_id', // Foreign key in SaleItems table
      as: 'saleItems', // Alias for association
    });
    
    // Product has many GRNItems (one-to-many relationship)
    Product.hasMany(models.GRNItem, {
      foreignKey: 'product_id', // Foreign key in GRNItems table
      as: 'grnItems', // Alias for association
    });
    
    // Product has many BOMItems as Raw Material (one-to-many relationship)
    Product.hasMany(models.BOMItem, {
      foreignKey: 'rm_product_id', // Foreign key in BOMItems table
      as: 'bomItemsAsRM', // Alias for association
    });
    
    // Product has many ProductPrices (one-to-many relationship)
    Product.hasMany(models.ProductPrice, {
      foreignKey: 'product_id', // Foreign key in ProductPrices table
      as: 'productPrices', // Alias for association
    });
    
    // Product has many ProductCategories (one-to-many relationship)
    Product.hasMany(models.ProductCategory, {
      foreignKey: 'product_id', // Foreign key in ProductCategories table
      as: 'productCategories', // Alias for association
    });
    
    // Product has many DiscountRules (one-to-many relationship)
    Product.hasMany(models.DiscountRule, {
      foreignKey: 'product_id', // Foreign key in DiscountRules table
      as: 'discountRules', // Alias for association
    });
    
    // Product has many BOMs (one-to-many relationship) - as Finished Good
    Product.hasMany(models.BOM, {
      foreignKey: 'fg_product_id', // Foreign key in BOMs table
      as: 'bomsAsFG', // Alias for association
    });
    
    // Product has many ProductionOrders (one-to-many relationship) - as Finished Good
    Product.hasMany(models.ProductionOrder, {
      foreignKey: 'fg_product_id', // Foreign key in ProductionOrders table
      as: 'productionOrders', // Alias for association
    });
  };

  // Return Product model
  return Product;
};

