# frozen_string_literal: true

require "csv"
require "net/http"

require "provider/adapters/adapter"

class Provider
  module Adapters
    # Bank of England (BOE). Fetches daily spot exchange rates for 26 currencies
    # against the British pound from the Statistical Interactive Database.
    # The CSV API returns pivoted data with series codes as column headers.
    # Historical data available from 2000-01-04.
    class BOE < Adapter
      BASE_URL = "https://www.bankofengland.co.uk/boeapps/database/_iadb-fromshowcolumns.asp"
      # BOE series code => ISO 4217 currency code
      # Rates are "foreign currency per 1 GBP"
      SERIES = {
        "XUDLUSS" => "USD",
        "XUDLERS" => "EUR",
        "XUDLJYS" => "JPY",
        "XUDLCDS" => "CAD",
        "XUDLSFS" => "CHF",
        "XUDLADS" => "AUD",
        "XUDLNDS" => "NZD",
        "XUDLNKS" => "NOK",
        "XUDLSKS" => "SEK",
        "XUDLDKS" => "DKK",
        "XUDLHDS" => "HKD",
        "XUDLSGS" => "SGD",
        "XUDLSRS" => "SAR",
        "XUDLZRS" => "ZAR",
        "XUDLTWS" => "TWD",
        "XUDLBK25" => "CZK",
        "XUDLBK33" => "HUF",
        "XUDLBK47" => "PLN",
        "XUDLBK78" => "ILS",
        "XUDLBK83" => "MYR",
        "XUDLBK87" => "THB",
        "XUDLBK89" => "CNY",
        "XUDLBK93" => "KRW",
        "XUDLBK95" => "TRY",
        "XUDLBK97" => "INR",
        "XUDLZOS4" => "RON",
      }.freeze

      def fetch(after: nil, upto: nil)
        url = URI(BASE_URL)
        url.query = URI.encode_www_form(
          "csv.x" => "yes",
          "SeriesCodes" => SERIES.keys.join(","),
          "UsingCodes" => "Y",
          "CSVF" => "TN",
          "Datefrom" => after.strftime("%d/%b/%Y"),
          "Dateto" => (upto || Date.today).strftime("%d/%b/%Y"),
        )

        response = Net::HTTP.get(url)
        parse(response)
      end

      def parse(csv)
        rows = CSV.parse(csv, headers: true)

        rows.flat_map do |row|
          date_str = row["DATE"]
          next unless date_str

          date = Date.parse(date_str)

          SERIES.filter_map do |series_code, currency|
            rate_str = row[series_code]
            next if rate_str.nil? || rate_str.strip.empty?

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

            { date:, base: "GBP", quote: currency, rate: rate_value }
          end
        end.compact
      end
    end
  end
end
