/**
 * Price Lists Service
 * Business logic for price list management
 */

// Import PriceList and related models
const { PriceList, Customer } = require('../../../models');
// Import custom error classes
const { NotFoundError, ValidationError, ConflictError } = require('../../../utils/errors');
// Import logger for logging
const logger = require('../../../utils/logger');
// Import Sequelize operators
const { Op } = require('sequelize');

/**
 * Create price list
 * Creates a new price list
 * @param {Object} priceListData - Price list data (name, code, price_list_type, currency, description, is_default)
 * @returns {Promise<Object>} Created price list
 */
const createPriceList = async (priceListData) => {
  // Extract price list data
  const { name, code, price_list_type, currency = 'KES', description = null, is_default = false } = priceListData; // Extract data
  
  // Validate required fields
  if (!name || !code || !price_list_type) {
    throw new ValidationError('Name, code, and price_list_type are required'); // Throw error if missing required fields
  }
  
  // Validate price_list_type
  const validTypes = ['RETAIL', 'WHOLESALE', 'B2B', 'CUSTOMER_SPECIFIC']; // Valid price list types
  if (!validTypes.includes(price_list_type)) {
    throw new ValidationError(`Price list type must be one of: ${validTypes.join(', ')}`); // Throw error if invalid type
  }
  
  // Check if code already exists
  const existingPriceList = await PriceList.findOne({
    where: { code }, // Match code
  });
  
  if (existingPriceList) {
    throw new ConflictError(`Price list with code ${code} already exists`); // Throw error if code exists
  }
  
  // If setting as default, unset other defaults
  if (is_default) {
    await PriceList.update(
      { is_default: false }, // Set is_default to false
      {
        where: { is_default: true }, // Match existing defaults
      }
    );
  }
  
  // Create price list
  const priceList = await PriceList.create({
    name, // Set name
    code, // Set code
    price_list_type, // Set price list type
    currency, // Set currency
    description, // Set description
    is_default, // Set default flag
    active: true, // Default to active
  });
  
  // Log price list creation
  logger.info(`Price list created: ${name}`, {
    priceListId: priceList.id,
    name,
    code,
    priceListType: price_list_type,
    isDefault: is_default,
  });
  
  // Return created price list
  return priceList; // Return price list
};

/**
 * Get price list by ID
 * Retrieves a price list with details
 * @param {number} priceListId - Price list ID
 * @returns {Promise<Object>} Price list
 */
const getPriceList = async (priceListId) => {
  // Find price list by ID
  const priceList = await PriceList.findByPk(priceListId); // Find price list by ID
  
  // If price list not found, throw error
  if (!priceList) {
    throw new NotFoundError('Price list not found'); // Throw error
  }
  
  // Return price list
  return priceList; // Return price list
};

/**
 * Update price list
 * Updates an existing price list
 * @param {number} priceListId - Price list ID
 * @param {Object} updateData - Update data
 * @returns {Promise<Object>} Updated price list
 */
const updatePriceList = async (priceListId, updateData) => {
  // Find price list
  const priceList = await PriceList.findByPk(priceListId); // Find price list by ID
  if (!priceList) {
    throw new NotFoundError('Price list not found'); // Throw error if price list doesn't exist
  }
  
  // Extract update data
  const { code, is_default, price_list_type } = updateData; // Extract data
  
  // If code is being updated, check if new code already exists
  if (code && code !== priceList.code) {
    const existingPriceList = await PriceList.findOne({
      where: {
        code, // Match code
        id: { [Op.ne]: priceListId }, // Exclude current price list
      },
    });
    
    if (existingPriceList) {
      throw new ConflictError(`Price list with code ${code} already exists`); // Throw error if code exists
    }
  }
  
  // Validate price_list_type if being updated
  if (price_list_type) {
    const validTypes = ['RETAIL', 'WHOLESALE', 'B2B', 'CUSTOMER_SPECIFIC']; // Valid price list types
    if (!validTypes.includes(price_list_type)) {
      throw new ValidationError(`Price list type must be one of: ${validTypes.join(', ')}`); // Throw error if invalid type
    }
  }
  
  // If setting as default, unset other defaults
  if (is_default === true && !priceList.is_default) {
    await PriceList.update(
      { is_default: false }, // Set is_default to false
      {
        where: {
          is_default: true, // Match existing defaults
          id: { [Op.ne]: priceListId }, // Exclude current price list
        },
      }
    );
  }
  
  // Update price list
  await priceList.update(updateData); // Update price list
  
  // Reload price list
  const updatedPriceList = await PriceList.findByPk(priceListId); // Reload price list
  
  // Log price list update
  logger.info(`Price list updated: ${priceListId}`, {
    priceListId,
    updateData,
  });
  
  // Return updated price list
  return updatedPriceList; // Return price list
};

/**
 * Delete price list
 * Deletes a price list (only if it has no product prices)
 * @param {number} priceListId - Price list ID
 * @returns {Promise<void>}
 */
const deletePriceList = async (priceListId) => {
  // Find price list
  const priceList = await PriceList.findByPk(priceListId); // Find price list by ID
  if (!priceList) {
    throw new NotFoundError('Price list not found'); // Throw error if price list doesn't exist
  }
  
  // Check if price list has product prices
  const { ProductPrice } = require('../../../models'); // Import ProductPrice model
  const pricesCount = await ProductPrice.count({
    where: { price_list_id: priceListId }, // Count product prices
  });
  
  if (pricesCount > 0) {
    throw new ValidationError('Cannot delete price list with assigned product prices'); // Throw error if has prices
  }
  
  // Check if price list has customers
  const customersCount = await Customer.count({
    where: { price_list_id: priceListId }, // Count customers
  });
  
  if (customersCount > 0) {
    throw new ValidationError('Cannot delete price list with assigned customers'); // Throw error if has customers
  }
  
  // Delete price list
  await priceList.destroy(); // Delete price list
  
  // Log price list deletion
  logger.info(`Price list deleted: ${priceListId}`, {
    priceListId,
    name: priceList.name,
  });
};

/**
 * List price lists with filters
 * Retrieves paginated list of price lists
 * @param {Object} options - Query options
 * @param {number} options.page - Page number (default: 1)
 * @param {number} options.limit - Items per page (default: 10)
 * @param {string|null} options.priceListType - Filter by price list type
 * @param {boolean|null} options.active - Filter by active status
 * @returns {Promise<Object>} Paginated price lists list
 */
const listPriceLists = async (options = {}) => {
  // Extract options with defaults
  const {
    page = 1,
    limit = 10,
    priceListType = null,
    active = null,
  } = options; // Extract and set defaults
  
  // Build where clause
  const where = {}; // Initialize where clause
  
  // Add price list type filter if provided
  if (priceListType) {
    where.price_list_type = priceListType; // Filter by price list type
  }
  
  // Add active filter if provided
  if (active !== null) {
    where.active = active === true || active === 'true'; // Filter by active status
  }
  
  // Calculate offset for pagination
  const offset = (page - 1) * limit; // Calculate offset
  
  // Build query options
  const queryOptions = {
    where, // Apply where clause
    limit: parseInt(limit), // Set limit
    offset: parseInt(offset), // Set offset
    order: [['is_default', 'DESC'], ['name', 'ASC']], // Order by default flag then name
  };
  
  // Execute query to get price lists and total count
  const { count, rows } = await PriceList.findAndCountAll(queryOptions); // Get price lists with count
  
  // Calculate total pages
  const totalPages = Math.ceil(count / limit); // Calculate total pages
  
  // Return paginated results
  return {
    priceLists: rows, // Price list records
    pagination: {
      page: parseInt(page), // Current page
      limit: parseInt(limit), // Items per page
      total: count, // Total items
      totalPages, // Total pages
    },
  };
};

/**
 * Get default price list
 * Retrieves the default price list
 * @returns {Promise<Object|null>} Default price list or null
 */
const getDefaultPriceList = async () => {
  // Find default price list
  const defaultPriceList = await PriceList.findOne({
    where: { is_default: true, active: true }, // Match default and active
  });
  
  // Return default price list (or null if not found)
  return defaultPriceList; // Return price list
};

// Export service functions
module.exports = {
  createPriceList, // Create price list function
  getPriceList, // Get price list function
  updatePriceList, // Update price list function
  deletePriceList, // Delete price list function
  listPriceLists, // List price lists function
  getDefaultPriceList, // Get default price list function
};

