/**
 * Discount Rules Service
 * Business logic for discount rule management
 */

// Import DiscountRule and related models
const { DiscountRule, Discount, Product, Category, Customer } = require('../../../models');
// Import custom error classes
const { NotFoundError, ValidationError } = require('../../../utils/errors');
// Import logger for logging
const logger = require('../../../utils/logger');

/**
 * Create discount rule
 * Creates a new discount rule
 * @param {number} discountId - Discount ID
 * @param {Object} ruleData - Rule data (rule_type, product_id, category_id, customer_id, min_quantity)
 * @returns {Promise<Object>} Created discount rule
 */
const createDiscountRule = async (discountId, ruleData) => {
  // Validate discount ID
  if (!discountId) {
    throw new ValidationError('Discount ID is required'); // Throw error if ID missing
  }
  
  // Find discount
  const discount = await Discount.findByPk(discountId); // Find by ID
  
  // Check if discount exists
  if (!discount) {
    throw new NotFoundError(`Discount with ID ${discountId} not found`); // Throw error if not found
  }
  
  // Extract rule data
  const {
    rule_type, // Rule type (PRODUCT, CATEGORY, CUSTOMER, ALL)
    product_id = null, // Product ID (if rule_type is PRODUCT)
    category_id = null, // Category ID (if rule_type is CATEGORY)
    customer_id = null, // Customer ID (if rule_type is CUSTOMER)
    min_quantity = 1, // Minimum quantity
  } = ruleData; // Extract data
  
  // Validate rule type
  const validRuleTypes = ['PRODUCT', 'CATEGORY', 'CUSTOMER', 'ALL']; // Valid rule types
  if (!validRuleTypes.includes(rule_type)) {
    throw new ValidationError(`Invalid rule type. Must be one of: ${validRuleTypes.join(', ')}`); // Throw error if invalid type
  }
  
  // Validate rule-specific fields
  if (rule_type === 'PRODUCT' && !product_id) {
    throw new ValidationError('Product ID is required for PRODUCT rule type'); // Throw error if product_id missing
  }
  
  if (rule_type === 'CATEGORY' && !category_id) {
    throw new ValidationError('Category ID is required for CATEGORY rule type'); // Throw error if category_id missing
  }
  
  if (rule_type === 'CUSTOMER' && !customer_id) {
    throw new ValidationError('Customer ID is required for CUSTOMER rule type'); // Throw error if customer_id missing
  }
  
  // Verify referenced entities exist
  if (product_id) {
    const product = await Product.findByPk(product_id); // Find product
    if (!product) {
      throw new NotFoundError(`Product with ID ${product_id} not found`); // Throw error if product not found
    }
  }
  
  if (category_id) {
    const category = await Category.findByPk(category_id); // Find category
    if (!category) {
      throw new NotFoundError(`Category with ID ${category_id} not found`); // Throw error if category not found
    }
  }
  
  if (customer_id) {
    const customer = await Customer.findByPk(customer_id); // Find customer
    if (!customer) {
      throw new NotFoundError(`Customer with ID ${customer_id} not found`); // Throw error if customer not found
    }
  }
  
  // Create discount rule
  const discountRule = await DiscountRule.create({
    discount_id: discountId, // Discount ID
    rule_type, // Rule type
    product_id: rule_type === 'PRODUCT' ? product_id : null, // Product ID if applicable
    category_id: rule_type === 'CATEGORY' ? category_id : null, // Category ID if applicable
    customer_id: rule_type === 'CUSTOMER' ? customer_id : null, // Customer ID if applicable
    min_quantity, // Minimum quantity
  });
  
  logger.info(`Discount rule created: ${discountRule.id} for discount ${discountId}`); // Log rule creation
  
  // Return rule with associations
  return await getDiscountRule(discountRule.id); // Return rule with associations
};

/**
 * Get discount rule by ID
 * Retrieves a discount rule by ID
 * @param {number} ruleId - Rule ID
 * @returns {Promise<Object>} Discount rule
 */
const getDiscountRule = async (ruleId) => {
  // Validate rule ID
  if (!ruleId) {
    throw new ValidationError('Rule ID is required'); // Throw error if ID missing
  }
  
  // Find discount rule
  const rule = await DiscountRule.findByPk(ruleId, {
    include: [
      {
        model: Discount, // Include discount
        as: 'discount', // Use discount alias
      },
      {
        model: Product, // Include product if applicable
        as: 'product', // Use product alias
        required: false, // Left join
      },
      {
        model: Category, // Include category if applicable
        as: 'category', // Use category alias
        required: false, // Left join
      },
      {
        model: Customer, // Include customer if applicable
        as: 'customer', // Use customer alias
        required: false, // Left join
      },
    ],
  });
  
  // Check if rule exists
  if (!rule) {
    throw new NotFoundError(`Discount rule with ID ${ruleId} not found`); // Throw error if not found
  }
  
  // Return rule
  return rule;
};

/**
 * Update discount rule
 * Updates an existing discount rule
 * @param {number} ruleId - Rule ID
 * @param {Object} updateData - Update data
 * @returns {Promise<Object>} Updated discount rule
 */
const updateDiscountRule = async (ruleId, updateData) => {
  // Validate rule ID
  if (!ruleId) {
    throw new ValidationError('Rule ID is required'); // Throw error if ID missing
  }
  
  // Find discount rule
  const rule = await DiscountRule.findByPk(ruleId); // Find by ID
  
  // Check if rule exists
  if (!rule) {
    throw new NotFoundError(`Discount rule with ID ${ruleId} not found`); // Throw error if not found
  }
  
  // Extract update data
  const {
    rule_type, // Rule type
    product_id, // Product ID
    category_id, // Category ID
    customer_id, // Customer ID
    min_quantity, // Minimum quantity
  } = updateData; // Extract data
  
  // Validate rule type if provided
  if (rule_type !== undefined) {
    const validRuleTypes = ['PRODUCT', 'CATEGORY', 'CUSTOMER', 'ALL']; // Valid rule types
    if (!validRuleTypes.includes(rule_type)) {
      throw new ValidationError(`Invalid rule type. Must be one of: ${validRuleTypes.join(', ')}`); // Throw error if invalid type
    }
  }
  
  // Use existing rule type if not provided
  const finalRuleType = rule_type || rule.rule_type; // Use provided or existing
  
  // Validate rule-specific fields
  if (finalRuleType === 'PRODUCT' && !product_id && !rule.product_id) {
    throw new ValidationError('Product ID is required for PRODUCT rule type'); // Throw error if product_id missing
  }
  
  if (finalRuleType === 'CATEGORY' && !category_id && !rule.category_id) {
    throw new ValidationError('Category ID is required for CATEGORY rule type'); // Throw error if category_id missing
  }
  
  if (finalRuleType === 'CUSTOMER' && !customer_id && !rule.customer_id) {
    throw new ValidationError('Customer ID is required for CUSTOMER rule type'); // Throw error if customer_id missing
  }
  
  // Verify referenced entities exist if provided
  if (product_id !== undefined && product_id !== null) {
    const product = await Product.findByPk(product_id); // Find product
    if (!product) {
      throw new NotFoundError(`Product with ID ${product_id} not found`); // Throw error if product not found
    }
  }
  
  if (category_id !== undefined && category_id !== null) {
    const category = await Category.findByPk(category_id); // Find category
    if (!category) {
      throw new NotFoundError(`Category with ID ${category_id} not found`); // Throw error if category not found
    }
  }
  
  if (customer_id !== undefined && customer_id !== null) {
    const customer = await Customer.findByPk(customer_id); // Find customer
    if (!customer) {
      throw new NotFoundError(`Customer with ID ${customer_id} not found`); // Throw error if customer not found
    }
  }
  
  // Update discount rule
  await rule.update({
    ...(rule_type !== undefined && { rule_type }), // Update type if provided
    ...(product_id !== undefined && { product_id: finalRuleType === 'PRODUCT' ? product_id : null }), // Update product_id if provided
    ...(category_id !== undefined && { category_id: finalRuleType === 'CATEGORY' ? category_id : null }), // Update category_id if provided
    ...(customer_id !== undefined && { customer_id: finalRuleType === 'CUSTOMER' ? customer_id : null }), // Update customer_id if provided
    ...(min_quantity !== undefined && { min_quantity }), // Update min_quantity if provided
  });
  
  logger.info(`Discount rule updated: ${ruleId}`); // Log rule update
  
  // Return updated rule
  return await getDiscountRule(ruleId); // Return rule with associations
};

/**
 * Delete discount rule
 * Deletes a discount rule
 * @param {number} ruleId - Rule ID
 * @returns {Promise<void>}
 */
const deleteDiscountRule = async (ruleId) => {
  // Validate rule ID
  if (!ruleId) {
    throw new ValidationError('Rule ID is required'); // Throw error if ID missing
  }
  
  // Find discount rule
  const rule = await DiscountRule.findByPk(ruleId); // Find by ID
  
  // Check if rule exists
  if (!rule) {
    throw new NotFoundError(`Discount rule with ID ${ruleId} not found`); // Throw error if not found
  }
  
  // Delete discount rule
  await rule.destroy(); // Delete rule
  
  logger.info(`Discount rule deleted: ${ruleId}`); // Log rule deletion
};

/**
 * List discount rules
 * Lists discount rules for a discount
 * @param {number} discountId - Discount ID
 * @returns {Promise<Array>} Array of discount rules
 */
const listDiscountRules = async (discountId) => {
  // Validate discount ID
  if (!discountId) {
    throw new ValidationError('Discount ID is required'); // Throw error if ID missing
  }
  
  // Find discount
  const discount = await Discount.findByPk(discountId); // Find by ID
  
  // Check if discount exists
  if (!discount) {
    throw new NotFoundError(`Discount with ID ${discountId} not found`); // Throw error if not found
  }
  
  // Find discount rules
  const rules = await DiscountRule.findAll({
    where: { discount_id: discountId }, // Filter by discount ID
    include: [
      {
        model: Product, // Include product if applicable
        as: 'product', // Use product alias
        required: false, // Left join
      },
      {
        model: Category, // Include category if applicable
        as: 'category', // Use category alias
        required: false, // Left join
      },
      {
        model: Customer, // Include customer if applicable
        as: 'customer', // Use customer alias
        required: false, // Left join
      },
    ],
    order: [['id', 'ASC']], // Order by ID ascending
  });
  
  // Return rules
  return rules;
};

// Export discount rule service functions
module.exports = {
  createDiscountRule,
  getDiscountRule,
  updateDiscountRule,
  deleteDiscountRule,
  listDiscountRules,
};

