# frozen_string_literal: true

require "net/http"
require "oj"

require "provider/adapters/adapter"

class Provider
  module Adapters
    # National Bank of the Republic of Belarus. Publishes daily rates for ~30 currencies against BYN.
    # BYN was redenominated on 2016-07-01; earlier data uses different currency IDs.
    class NBRB < Adapter
      RATES_URL = "https://api.nbrb.by/exrates/rates"
      CHUNK_DAYS = 365

      def fetch(after: nil, upto: nil)
        currencies = current_currencies
        currencies.flat_map do |cur_id, iso, scale|
          chunked_dynamics(cur_id, iso, scale, after, upto || Date.today)
        end
      end

      private

      def parse_daily(data)
        data.filter_map do |row|
          date = Date.parse(row.fetch("Date"))
          next if date.saturday? || date.sunday?

          iso = row.fetch("Cur_Abbreviation")
          scale = Integer(row.fetch("Cur_Scale"))
          rate = Float(row.fetch("Cur_OfficialRate"))
          next if scale.zero?

          { date:, base: iso, quote: "BYN", rate: rate / scale }
        end
      end

      def current_currencies
        data = Oj.load(Net::HTTP.get(URI("#{RATES_URL}?periodicity=0")), mode: :strict)
        data.map { |row| [row.fetch("Cur_ID"), row.fetch("Cur_Abbreviation"), Integer(row.fetch("Cur_Scale"))] }
      end

      def chunked_dynamics(cur_id, iso, scale, start_date, end_date)
        records = []
        chunk_start = start_date

        while chunk_start <= end_date
          chunk_end = [chunk_start + CHUNK_DAYS - 1, end_date].min
          records.concat(fetch_dynamics(cur_id, iso, scale, chunk_start, chunk_end))
          chunk_start = chunk_end + 1
        end

        records
      end

      def fetch_dynamics(cur_id, iso, scale, start_date, end_date)
        url = URI("#{RATES_URL}/dynamics/#{cur_id}")
        url.query = URI.encode_www_form(startDate: start_date.to_s, endDate: end_date.to_s)
        data = Oj.load(Net::HTTP.get(url), mode: :strict)
        return [] unless data.is_a?(Array)

        data.filter_map do |row|
          date = Date.parse(row.fetch("Date"))
          next if date.saturday? || date.sunday?

          rate = Float(row.fetch("Cur_OfficialRate"))
          { date:, base: iso, quote: "BYN", rate: rate / scale }
        end
      end
    end
  end
end
