const { Service, Category } = require('../models');
const CacheService = require('./cacheService');
const logger = require('../config/logger');

/**
 * Service business logic
 */
class ServiceService {
  /**
   * Get all categories
   * @param {string} language - Language preference (zh, en, es)
   * @returns {Promise<Array>} - List of categories
   */
  static async getCategories(language = 'zh') {
    try {
      // Try to get from cache
      const cached = await CacheService.getCategoryList();
      if (cached) {
        logger.debug('Categories retrieved from cache');
        return this.formatCategories(cached, language);
      }

      // Fetch from database
      const categories = await Category.findAll({
        order: [['sortOrder', 'ASC'], ['createdAt', 'ASC']],
        raw: true,
      });

      // Cache the raw data
      await CacheService.setCategoryList(categories);

      return this.formatCategories(categories, language);
    } catch (error) {
      logger.error('Error fetching categories:', error);
      throw error;
    }
  }

  /**
   * Get services with pagination and filtering
   * @param {Object} options - Query options
   * @param {number} options.page - Page number
   * @param {number} options.limit - Items per page
   * @param {string} options.categoryKey - Filter by category key
   * @param {string} options.language - Language preference
   * @returns {Promise<Object>} - Paginated services
   */
  static async getServices({ page = 1, limit = 10, categoryKey, language = 'zh' }) {
    try {
      const offset = (page - 1) * limit;
      const cacheParams = { page, limit, categoryKey: categoryKey || 'all' };

      // Try to get from cache
      const cached = await CacheService.getServiceList(cacheParams);
      if (cached) {
        logger.debug('Services retrieved from cache');
        return {
          ...cached,
          data: this.formatServices(cached.data, language),
        };
      }

      // Build query
      const where = { status: 'active' };
      
      // Build include with optional category filter
      const include = [
        {
          model: Category,
          as: 'category',
          attributes: ['id', 'key', 'nameZh', 'nameEn', 'nameEs', 'icon'],
          ...(categoryKey ? { where: { key: categoryKey }, required: true } : {}),
        },
      ];

      // Fetch from database
      const { count, rows } = await Service.findAndCountAll({
        where,
        include,
        order: [['sortOrder', 'ASC'], ['createdAt', 'DESC']],
        limit: parseInt(limit),
        offset: parseInt(offset),
      });

      const result = {
        data: rows.map(service => service.toJSON()),
        pagination: {
          page: parseInt(page),
          limit: parseInt(limit),
          total: count,
          totalPages: Math.ceil(count / limit),
        },
      };

      // Cache the raw data
      await CacheService.setServiceList(cacheParams, result);

      return {
        ...result,
        data: this.formatServices(result.data, language),
      };
    } catch (error) {
      logger.error('Error fetching services:', error);
      throw error;
    }
  }

  /**
   * Get service by key
   * @param {string} serviceKey - Service key
   * @param {string} language - Language preference
   * @returns {Promise<Object>} - Service details
   */
  static async getServiceByKey(serviceKey, language = 'zh') {
    try {
      // Try to get from cache
      const cached = await CacheService.getServiceDetail(serviceKey);
      if (cached) {
        logger.debug(`Service ${serviceKey} retrieved from cache`);
        return this.formatService(cached, language);
      }

      // Fetch from database by key
      const service = await Service.findOne({
        where: { key: serviceKey },
        include: [
          {
            model: Category,
            as: 'category',
            attributes: ['id', 'key', 'nameZh', 'nameEn', 'nameEs', 'icon'],
          },
        ],
      });

      if (!service) {
        return null;
      }

      const serviceData = service.toJSON();

      // Cache the raw data
      await CacheService.setServiceDetail(serviceKey, serviceData);

      return this.formatService(serviceData, language);
    } catch (error) {
      logger.error(`Error fetching service ${serviceKey}:`, error);
      throw error;
    }
  }

  /**
   * Format categories for response based on language
   * @param {Array} categories - Raw categories
   * @param {string} language - Language preference
   * @returns {Array} - Formatted categories
   */
  static formatCategories(categories, language) {
    return categories.map(category => ({
      key: category.key,
      name: category[`name${this.capitalizeFirst(language)}`] || category.nameZh,
      icon: category.icon,
      sortOrder: category.sortOrder,
    }));
  }

  /**
   * Format services for response based on language
   * @param {Array} services - Raw services
   * @param {string} language - Language preference
   * @returns {Array} - Formatted services
   */
  static formatServices(services, language) {
    return services.map(service => this.formatService(service, language));
  }

  /**
   * Format single service for response based on language
   * @param {Object} service - Raw service
   * @param {string} language - Language preference
   * @returns {Object} - Formatted service
   */
  static formatService(service, language) {
    const langSuffix = this.capitalizeFirst(language);
    
    const formatted = {
      id: service.id,
      key: service.key,
      categoryId: service.categoryId,
      serviceType: service.serviceType,
      title: service[`title${langSuffix}`] || service.titleZh,
      description: service[`description${langSuffix}`] || service.descriptionZh,
      image: service.image,
      price: service.price,
      status: service.status,
      sortOrder: service.sortOrder,
    };

    // Include category if present
    if (service.category) {
      formatted.category = {
        key: service.category.key,
        name: service.category[`name${langSuffix}`] || service.category.nameZh,
        icon: service.category.icon,
      };
    }

    return formatted;
  }

  /**
   * Capitalize first letter
   * @param {string} str - String to capitalize
   * @returns {string} - Capitalized string
   */
  static capitalizeFirst(str) {
    return str.charAt(0).toUpperCase() + str.slice(1);
  }
}

module.exports = ServiceService;
