# frozen_string_literal: true

require "net/http"
require "ox"

require "provider/adapters/adapter"

class Provider
  module Adapters
    # Seðlabanki Íslands (Central Bank of Iceland). Publishes daily reference
    # exchange rates for 30+ currencies against the Icelandic króna (ISK).
    # Two GroupIDs are needed: 9 (official reference, 10 currencies from 1981)
    # and 7 (registered mid-rate, 22 currencies from 2006).
    class SBI < Adapter
      BASE_URL = "https://sedlabanki.is/xmltimeseries/Default.aspx"
      # TimeSeries ID to ISO currency code mapping
      # GroupID=9 (official reference rates)
      GROUP9_CURRENCIES = {
        "4055" => "USD",
        "4061" => "DKK",
        "4064" => "EUR",
        "4085" => "JPY",
        "4088" => "CAD",
        "4091" => "NOK",
        "4097" => "XDR",
        "4103" => "GBP",
        "4106" => "CHF",
        "4109" => "SEK",
      }.freeze

      # GroupID=7 (registered mid-rates)
      GROUP7_CURRENCIES = {
        "29" => "CNY",
        "31" => "PLN",
        "35" => "NGN",
        "36" => "TWD",
        "37" => "KRW",
        "38" => "SRD",
        "39" => "AUD",
        "40" => "NZD",
        "41" => "HKD",
        "42" => "HUF",
        "43" => "ILS",
        "44" => "ZAR",
        "45" => "SGD",
        "46" => "MXN",
        "48" => "TRY",
        "50" => "INR",
        "52" => "CZK",
        "53" => "BRL",
        "74" => "THB",
        "288" => "JMD",
        "3503" => "SAR",
        "19254" => "KWD",
      }.freeze

      class << self
        def backfill_range = 365
      end

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

        xml9 = fetch_group(after, end_date, 9)
        xml7 = fetch_group(after, end_date, 7)

        parse(xml9, GROUP9_CURRENCIES) + parse(xml7, GROUP7_CURRENCIES)
      end

      def parse(xml, currency_map = GROUP9_CURRENCIES.merge(GROUP7_CURRENCIES))
        doc = Ox.load(xml, mode: :generic)
        records = []

        doc.locate("*/TimeSeries").each do |ts|
          id = ts.attributes[:ID]
          currency = currency_map[id]
          next unless currency

          ts.locate("TimeSeriesData/Entry").each do |entry|
            date_node = entry.locate("Date").first
            value_node = entry.locate("Value").first
            next unless date_node && value_node

            date_str = date_node.text
            rate_str = value_node.text
            next unless date_str && rate_str

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

            date = parse_date(date_str)
            records << { date:, base: currency, quote: "ISK", rate: }
          end
        end

        records
      end

      private

      def fetch_group(start_date, end_date, group_id)
        url = URI(BASE_URL)
        url.query = URI.encode_www_form(
          "DagsFra" => start_date.to_s,
          "DagsTil" => end_date.to_s,
          "GroupID" => group_id,
          "Type" => "xml",
        )

        Net::HTTP.get(url)
      end

      def parse_date(str)
        # Format: "M/D/YYYY 12:00:00 AM"
        date_part = str.split(" ").first
        month, day, year = date_part.split("/").map(&:to_i)
        Date.new(year, month, day)
      end
    end
  end
end
