const Translation = require('../models/Translation');
const { Op } = require('sequelize');
const logger = require('../config/logger');
const { DEFAULT_LANGUAGE, SUPPORTED_LANGUAGES } = require('../middleware/language');

/**
 * Translation Service
 * Handles translation management operations
 */
class TranslationService {
  /**
   * Get all translations with optional filtering
   * @param {Object} options - Query options
   * @param {string} options.category - Filter by category
   * @param {string} options.language - Filter by language
   * @param {string} options.search - Search in key or value
   * @param {number} options.page - Page number
   * @param {number} options.limit - Items per page
   * @returns {Promise<Object>} - Paginated translations
   */
  static async getTranslations({ category, language, search, page = 1, limit = 20 }) {
    try {
      const offset = (page - 1) * limit;
      const where = {};

      if (category) {
        where.category = category;
      }

      if (language && SUPPORTED_LANGUAGES.includes(language)) {
        where.language = language;
      }

      if (search) {
        where[Op.or] = [
          { key: { [Op.like]: `%${search}%` } },
          { value: { [Op.like]: `%${search}%` } },
        ];
      }

      const { count, rows } = await Translation.findAndCountAll({
        where,
        order: [['category', 'ASC'], ['key', 'ASC'], ['language', 'ASC']],
        limit: parseInt(limit),
        offset: parseInt(offset),
      });

      return {
        data: rows,
        pagination: {
          page: parseInt(page),
          limit: parseInt(limit),
          total: count,
          totalPages: Math.ceil(count / limit),
        },
      };
    } catch (error) {
      logger.error('Error fetching translations:', error);
      throw error;
    }
  }

  /**
   * Get translation by key and language
   * @param {string} key - Translation key
   * @param {string} language - Language code
   * @returns {Promise<Object|null>} - Translation or null
   */
  static async getTranslation(key, language = DEFAULT_LANGUAGE) {
    try {
      // Try to get translation in requested language
      let translation = await Translation.findOne({
        where: { key, language },
      });

      // Fall back to default language if not found
      if (!translation && language !== DEFAULT_LANGUAGE) {
        translation = await Translation.findOne({
          where: { key, language: DEFAULT_LANGUAGE },
        });
      }

      return translation;
    } catch (error) {
      logger.error(`Error fetching translation for key ${key}:`, error);
      throw error;
    }
  }

  /**
   * Get all translations for a key (all languages)
   * @param {string} key - Translation key
   * @returns {Promise<Array>} - Translations in all languages
   */
  static async getTranslationsByKey(key) {
    try {
      const translations = await Translation.findAll({
        where: { key },
        order: [['language', 'ASC']],
      });

      return translations;
    } catch (error) {
      logger.error(`Error fetching translations for key ${key}:`, error);
      throw error;
    }
  }

  /**
   * Create a new translation
   * @param {Object} data - Translation data
   * @param {string} data.key - Translation key
   * @param {string} data.category - Translation category
   * @param {string} data.language - Language code
   * @param {string} data.value - Translated value
   * @param {string} data.description - Optional description
   * @returns {Promise<Object>} - Created translation
   */
  static async createTranslation(data) {
    try {
      const { key, category, language, value, description } = data;

      // Validate language
      if (!SUPPORTED_LANGUAGES.includes(language)) {
        const error = new Error(`Invalid language code. Must be one of: ${SUPPORTED_LANGUAGES.join(', ')}`);
        error.statusCode = 400;
        error.code = 'INVALID_LANGUAGE';
        throw error;
      }

      // Check if translation already exists
      const existing = await Translation.findOne({
        where: { key, language },
      });

      if (existing) {
        const error = new Error('Translation already exists for this key and language');
        error.statusCode = 409;
        error.code = 'TRANSLATION_EXISTS';
        throw error;
      }

      const translation = await Translation.create({
        key,
        category: category || 'general',
        language,
        value,
        description,
      });

      return translation;
    } catch (error) {
      logger.error('Error creating translation:', error);
      throw error;
    }
  }

  /**
   * Create or update translations for a key in multiple languages
   * @param {Object} data - Translation data
   * @param {string} data.key - Translation key
   * @param {string} data.category - Translation category
   * @param {Object} data.translations - Object with language codes as keys
   * @param {string} data.description - Optional description
   * @returns {Promise<Array>} - Created/updated translations
   */
  static async upsertTranslations(data) {
    try {
      const { key, category, translations, description } = data;
      const results = [];

      for (const [language, value] of Object.entries(translations)) {
        if (!SUPPORTED_LANGUAGES.includes(language)) {
          continue;
        }

        const [translation, created] = await Translation.upsert({
          key,
          category: category || 'general',
          language,
          value,
          description,
        }, {
          returning: true,
        });

        results.push({ translation, created });
      }

      return results;
    } catch (error) {
      logger.error('Error upserting translations:', error);
      throw error;
    }
  }

  /**
   * Update a translation
   * @param {string} id - Translation ID
   * @param {Object} data - Update data
   * @returns {Promise<Object>} - Updated translation
   */
  static async updateTranslation(id, data) {
    try {
      const translation = await Translation.findByPk(id);

      if (!translation) {
        const error = new Error('Translation not found');
        error.statusCode = 404;
        error.code = 'TRANSLATION_NOT_FOUND';
        throw error;
      }

      const allowedFields = ['value', 'category', 'description'];
      const updateData = {};

      allowedFields.forEach(field => {
        if (data[field] !== undefined) {
          updateData[field] = data[field];
        }
      });

      await translation.update(updateData);

      return translation;
    } catch (error) {
      logger.error(`Error updating translation ${id}:`, error);
      throw error;
    }
  }

  /**
   * Delete a translation
   * @param {string} id - Translation ID
   * @returns {Promise<boolean>} - Success status
   */
  static async deleteTranslation(id) {
    try {
      const translation = await Translation.findByPk(id);

      if (!translation) {
        const error = new Error('Translation not found');
        error.statusCode = 404;
        error.code = 'TRANSLATION_NOT_FOUND';
        throw error;
      }

      await translation.destroy();

      return true;
    } catch (error) {
      logger.error(`Error deleting translation ${id}:`, error);
      throw error;
    }
  }

  /**
   * Delete all translations for a key
   * @param {string} key - Translation key
   * @returns {Promise<number>} - Number of deleted translations
   */
  static async deleteTranslationsByKey(key) {
    try {
      const count = await Translation.destroy({
        where: { key },
      });

      return count;
    } catch (error) {
      logger.error(`Error deleting translations for key ${key}:`, error);
      throw error;
    }
  }

  /**
   * Get translation value with fallback
   * @param {string} key - Translation key
   * @param {string} language - Target language
   * @param {string} defaultValue - Default value if not found
   * @returns {Promise<string>} - Translation value
   */
  static async getValue(key, language = DEFAULT_LANGUAGE, defaultValue = '') {
    try {
      const translation = await this.getTranslation(key, language);
      return translation ? translation.value : defaultValue;
    } catch (error) {
      logger.error(`Error getting translation value for ${key}:`, error);
      return defaultValue;
    }
  }

  /**
   * Get all categories
   * @returns {Promise<Array>} - List of unique categories
   */
  static async getCategories() {
    try {
      const categories = await Translation.findAll({
        attributes: ['category'],
        group: ['category'],
        order: [['category', 'ASC']],
      });

      return categories.map(c => c.category);
    } catch (error) {
      logger.error('Error fetching translation categories:', error);
      throw error;
    }
  }
}

module.exports = TranslationService;
