# frozen_string_literal: true

require "net/http"
require "oj"

require "provider/adapters/adapter"

class Provider
  module Adapters
    # South African Reserve Bank. Publishes daily weighted-average exchange rates
    # for 24 currencies. USD, GBP, EUR are quoted as ZAR per foreign unit (foreign
    # base); all others as foreign per ZAR (ZAR base).
    class SARB < Adapter
      BASE_URL = "https://custom.resbank.co.za/SarbWebApi/WebIndicators/Shared/GetTimeseriesObservations"

      SERIES = {
        "EXCX135D" => ["USD", "ZAR"],
        "EXCZ001D" => ["GBP", "ZAR"],
        "EXCZ002D" => ["EUR", "ZAR"],
        "EXCB080D" => ["ZAR", "AUD"],
        "EXCB051D" => ["ZAR", "BWP"],
        "EXCB036D" => ["ZAR", "BRL"],
        "EXCB031D" => ["ZAR", "CAD"],
        "EXCB121D" => ["ZAR", "CNY"],
        "EXCB003D" => ["ZAR", "DKK"],
        "EXCB122D" => ["ZAR", "HKD"],
        "EXCB123D" => ["ZAR", "INR"],
        "EXCB094D" => ["ZAR", "ILS"],
        "EXCB120D" => ["ZAR", "JPY"],
        "EXCB059D" => ["ZAR", "KES"],
        "EXCB063D" => ["ZAR", "MWK"],
        "EXCB081D" => ["ZAR", "NZD"],
        "EXCB013D" => ["ZAR", "NOK"],
        "EXCB015D" => ["ZAR", "SEK"],
        "EXCB016D" => ["ZAR", "CHF"],
        "EXCB126D" => ["ZAR", "TWD"],
        "EXCB115D" => ["ZAR", "THB"],
        "EXCB071D" => ["ZAR", "ZMW"],
        "EXCB118D" => ["ZAR", "KRW"],
      }.freeze

      class << self
        def backfill_range = 365
      end

      def fetch(after: nil, upto: nil)
        start_date = after.to_s
        end_date = (upto || Date.today).to_s

        SERIES.flat_map do |code, (base, quote)|
          sleep(0.2)
          fetch_series(code, start_date, end_date, base:, quote:)
        end
      end

      def parse(json, base:, quote:)
        observations = Oj.load(json, mode: :strict)

        observations.filter_map do |obs|
          value = obs["Value"]
          next if value.nil? || value.to_s.strip.empty?

          rate = Float(value)
          next if rate.zero?

          date = Date.parse(obs["Period"])
          { date:, base:, quote:, rate: }
        end
      end

      private

      def fetch_series(code, start_date, end_date, base:, quote:)
        url = URI("#{BASE_URL}/#{code}/#{start_date}/#{end_date}")
        response = Net::HTTP.get(url)
        parse(response, base:, quote:)
      end
    end
  end
end
