import IExchange from '@/models/IExchange'
import couchService from '@/services/CouchService'
import formatDate from '@/utils/format-date'

class ExchangeService {
  private baseUrl: string = 'https://api.exchangeratesapi.io/'

  /**
   * Get an exchange with defined date and desired currencies
   * @param base currency of reference
   * @param date date of the transaction
   * @param rates multiple currencies needed
   */
  public async get(
    base: string = '',
    date: Date | null = null,
    rates: string[] = []
  ): Promise<IExchange | null> {
    const formattedDate: string = formatDate(date || new Date())
    const needFetch = rates.length > 1
    let couchResponse: any | null = null
    try {
      const id: string = needFetch
        ? `cur-${base}-${formattedDate}`
        : `cur-${base}`
      try {
        couchResponse = await couchService.get(id)
      } catch (error) {
        // tslint:disable-next-line
        console.info({ error })
      }
      if (!couchResponse) {
        let exchange: IExchange | null = null
        // No need to fetch currencies if only one money
        if (!needFetch) {
          exchange = {
            base,
            date: formattedDate,
            rates: {
              [base]: 1
            }
          }
        } else {
          const url = new URL(
            date ? `${this.baseUrl}${formattedDate}` : 'latest'
          )
          if (base) {
            url.searchParams.append('base', base)
          }
          const response = await fetch(url.toString())
          if (response.ok) {
            exchange = await response.json()
          }
        }
        if (exchange) {
          exchange = {
            ...exchange,
            doctype: 'exchange',
            _id: id
          }
          exchange.rates[base] = 1
          couchService.save(exchange)
          return exchange
        }
      }
      return couchResponse
    } catch (error) {
      // tslint:disable-next-line
      console.info({ error })
    }
    return null
  }

  /**
   * Get amount in base with exchange.
   * @param amount Raw amount
   * @param toCurrency Currency in which it need to be converted
   * @param exchange Exchange for the date and currencies
   */
  public getAmountInBase(
    amount: number,
    toCurrency: string,
    exchange: IExchange | null
  ): number {
    if (!exchange || !(toCurrency in exchange.rates)) {
      return amount
    }
    return amount * exchange.rates[toCurrency]
  }
}

export default new ExchangeService()
