const express = require('express')

/**
 * NewsController
 *
 * Exposes HTTP routes for querying and refreshing cached news data.
 */
class NewsController {
  constructor(storageService) {
    this._storageService = storageService
    this.router = express.Router()
    this._registerRoutes()
  }

  /**
   * @returns {void}
   */
  _registerRoutes() {
    this.router.get('/categories', this._wrap(async (_request, response) => {
      response.json({ data: this._storageService.getCategories() })
    }))

    this.router.get('/all', this._wrap(async (request, response) => {
      const limit = this._parseLimit(request.query.limit)
      const data = await this._storageService.getAllNews(limit)
      response.json({ data })
    }))

    this.router.get('/', this._wrap(async (request, response) => {
      const category = request.query.category
      if (!category) {
        response.status(400).json({ message: 'category query parameter is required' })
        return
      }
      const limit = this._parseLimit(request.query.limit)
      const data = await this._storageService.getCategoryNews(String(category), limit)
      response.json({ data })
    }))

    this.router.get('/:category', this._wrap(async (request, response) => {
      const limit = this._parseLimit(request.query.limit)
      const data = await this._storageService.getCategoryNews(request.params.category, limit)
      response.json({ data })
    }))

    this.router.post('/refresh', this._wrap(async (request, response) => {
      const category = request.query.category
      const data = category
        ? await this._storageService.refreshCategory(String(category))
        : await this._storageService.refreshAll()
      response.json({ data })
    }))
  }

  /**
   * @param {string | undefined} limitValue
   * @returns {number}
   */
  _parseLimit(limitValue) {
    const parsed = Number(limitValue)
    return Number.isInteger(parsed) && parsed > 0 ? parsed : 0
  }

  /**
   * @param {(request: import('express').Request, response: import('express').Response) => Promise<void>} handler
   * @returns {(request: import('express').Request, response: import('express').Response, next: import('express').NextFunction) => void}
   */
  _wrap(handler) {
    return (request, response, next) => {
      handler(request, response).catch(next)
    }
  }
}

module.exports = {
  NewsController
}