/**
 * Vendor Service
 * Business logic for vendor management
 */

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

/**
 * Create vendor
 * Creates a new vendor
 * @param {Object} vendorData - Vendor data (name, type)
 * @returns {Promise<Object>} Created vendor
 */
const createVendor = async (vendorData) => {
  // Extract vendor data
  const { name, type = 'OPEN_MARKET' } = vendorData; // Extract data
  
  // Validate required fields
  if (!name) {
    throw new ValidationError('Vendor name is required'); // Throw error if name missing
  }
  
  // Validate vendor type
  const validTypes = ['OPEN_MARKET', 'REGISTERED']; // Valid vendor types
  if (!validTypes.includes(type)) {
    throw new ValidationError(`Vendor type must be one of: ${validTypes.join(', ')}`); // Throw error if invalid type
  }
  
  // Create vendor
  const vendor = await Vendor.create({
    name, // Vendor name
    type, // Vendor type
  });
  
  logger.info(`Vendor created: ${vendor.id} - ${vendor.name}`); // Log vendor creation
  
  // Return created vendor
  return vendor;
};

/**
 * Get vendor by ID
 * Retrieves a vendor by ID
 * @param {number} vendorId - Vendor ID
 * @returns {Promise<Object>} Vendor
 */
const getVendor = async (vendorId) => {
  // Validate vendor ID
  if (!vendorId) {
    throw new ValidationError('Vendor ID is required'); // Throw error if ID missing
  }
  
  // Find vendor
  const vendor = await Vendor.findByPk(vendorId); // Find by ID
  
  // Check if vendor exists
  if (!vendor) {
    throw new NotFoundError(`Vendor with ID ${vendorId} not found`); // Throw error if not found
  }
  
  // Return vendor
  return vendor;
};

/**
 * Update vendor
 * Updates an existing vendor
 * @param {number} vendorId - Vendor ID
 * @param {Object} updateData - Update data
 * @returns {Promise<Object>} Updated vendor
 */
const updateVendor = async (vendorId, updateData) => {
  // Validate vendor ID
  if (!vendorId) {
    throw new ValidationError('Vendor ID is required'); // Throw error if ID missing
  }
  
  // Find vendor
  const vendor = await Vendor.findByPk(vendorId); // Find by ID
  
  // Check if vendor exists
  if (!vendor) {
    throw new NotFoundError(`Vendor with ID ${vendorId} not found`); // Throw error if not found
  }
  
  // Extract update data
  const { name, type } = updateData; // Extract data
  
  // Validate vendor type if provided
  if (type !== undefined) {
    const validTypes = ['OPEN_MARKET', 'REGISTERED']; // Valid vendor types
    if (!validTypes.includes(type)) {
      throw new ValidationError(`Vendor type must be one of: ${validTypes.join(', ')}`); // Throw error if invalid type
    }
  }
  
  // Update vendor
  await vendor.update({
    ...(name !== undefined && { name }), // Update name if provided
    ...(type !== undefined && { type }), // Update type if provided
  });
  
  logger.info(`Vendor updated: ${vendorId}`); // Log vendor update
  
  // Return updated vendor
  return vendor;
};

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

/**
 * List vendors
 * Lists vendors with optional filters
 * @param {Object} filters - Filter options (type, search)
 * @param {Object} pagination - Pagination options (page, limit)
 * @returns {Promise<Object>} Paginated list of vendors
 */
const listVendors = async (filters = {}, pagination = {}) => {
  // Extract filters
  const {
    type, // Vendor type filter
    search, // Search term (name)
  } = filters; // Extract filters
  
  // Extract pagination options
  const page = parseInt(pagination.page, 10) || 1; // Current page (default 1)
  const limit = parseInt(pagination.limit, 10) || 50; // Items per page (default 50)
  const offset = (page - 1) * limit; // Calculate offset
  
  // Build where clause
  const where = {}; // Initialize where clause
  
  // Add type filter
  if (type) {
    where.type = type; // Filter by vendor type
  }
  
  // Add search filter
  if (search) {
    where.name = { [Op.like]: `%${search}%` }; // Search in name
  }
  
  // Find vendors with pagination
  const { count, rows } = await Vendor.findAndCountAll({
    where, // Where clause
    limit, // Limit results
    offset, // Offset results
    order: [['created_at', 'DESC']], // Order by creation date descending
  });
  
  // Calculate pagination metadata
  const totalPages = Math.ceil(count / limit); // Total pages
  const hasNextPage = page < totalPages; // Has next page
  const hasPrevPage = page > 1; // Has previous page
  
  // Return paginated results
  return {
    vendors: rows, // Vendors array
    pagination: {
      page, // Current page
      limit, // Items per page
      total: count, // Total count
      totalPages, // Total pages
      hasNextPage, // Has next page
      hasPrevPage, // Has previous page
    },
  };
};

// Export vendor service functions
module.exports = {
  createVendor,
  getVendor,
  updateVendor,
  deleteVendor,
  listVendors,
};

