/**
 * NewsStorageService
 *
 * Coordinates category validation, refresh logic, and repository access.
 */
class NewsStorageService {
  constructor(categoryCatalog, repository, apiClient) {
    this._categoryCatalog = categoryCatalog
    this._repository = repository
    this._apiClient = apiClient
  }

  /**
   * @returns {Promise<object[]>}
   */
  async refreshAll() {
    const results = []
    for (const category of this._categoryCatalog.all()) {
      results.push(await this.refreshCategory(category.key))
    }
    return results
  }

  /**
   * @param {string} categoryKey
   * @returns {Promise<object>}
   */
  async refreshCategory(categoryKey) {
    const category = this._resolveCategory(categoryKey)
    const articles = await this._apiClient.fetchArticlesByCategory(category)
    return this._repository.saveCategory(category, articles)
  }

  /**
   * @param {string} categoryKey
   * @param {number} limit
   * @returns {Promise<object>}
   */
  async getCategoryNews(categoryKey, limit) {
    const category = this._resolveCategory(categoryKey)
    const document = await this._repository.readCategory(category)
    return this._applyLimit(document, limit)
  }

  /**
   * @param {string} categoryKey
   * @param {number} page
   * @param {number} pageSize
   * @returns {Promise<object>}
   */
  async getCategoryNewsPage(categoryKey, page, pageSize) {
    const category = this._resolveCategory(categoryKey)
    const document = await this._repository.readCategory(category)
    const safePage = Number.isInteger(page) && page > 0 ? page : 1
    const safePageSize = Number.isInteger(pageSize) && pageSize > 0 ? pageSize : document.articles.length
    const start = (safePage - 1) * safePageSize
    const end = start + safePageSize

    return {
      ...document,
      total: document.total,
      page: safePage,
      pageSize: safePageSize,
      articles: document.articles.slice(start, end)
    }
  }

  /**
   * @param {number} limit
   * @returns {Promise<object[]>}
   */
  async getAllNews(limit) {
    const results = []
    for (const category of this._categoryCatalog.all()) {
      const document = await this._repository.readCategory(category)
      results.push(this._applyLimit(document, limit))
    }
    return results
  }

  /**
   * @returns {object[]}
   */
  getCategories() {
    return this._categoryCatalog.all().map((category) => ({
      key: category.key,
      label: category.label,
      query: category.query,
      fileName: category.fileName,
      apiUrl: category.apiUrl
    }))
  }

  /**
   * @param {string} categoryKey
   * @returns {import('../config/CategoryCatalog').NewsCategory}
   */
  _resolveCategory(categoryKey) {
    const category = this._categoryCatalog.getByKey(categoryKey)
    if (!category) {
      throw new Error(`Unsupported category: ${categoryKey}`)
    }
    return category
  }

  /**
   * @param {object} document
   * @param {number} limit
   * @returns {object}
   */
  _applyLimit(document, limit) {
    if (!limit || limit < 1) {
      return document
    }
    return {
      ...document,
      total: Math.min(document.total, limit),
      articles: document.articles.slice(0, limit)
    }
  }
}

module.exports = {
  NewsStorageService
}
