# frozen_string_literal: true

require "json"
require "net/http"

require "provider/adapters/adapter"

class Provider
  module Adapters
    # Banco de México. Fetches daily FIX and reference exchange rates for 5
    # currencies against the Mexican peso (MXN) via the SIE REST API.
    # Supports batched series queries and date range filtering.
    class BANXICO < Adapter
      BASE_URL = "https://www.banxico.org.mx/SieAPIRest/service/v1/series"

      # series_id => base currency (all quoted against MXN)
      SERIES = {
        "SF43718" => "USD",
        "SF46410" => "EUR",
        "SF46407" => "GBP",
        "SF46406" => "JPY",
        "SF60632" => "CAD",
      }.freeze

      class << self
        def api_key = ENV["BANXICO_API_KEY"] || raise(Adapter::Unavailable, "no API key")
      end

      def fetch(after: nil, upto: nil)
        ids = SERIES.keys.join(",")
        url = if after
          end_date = upto || Date.today
          URI("#{BASE_URL}/#{ids}/datos/#{after}/#{end_date}")
        else
          URI("#{BASE_URL}/#{ids}/datos")
        end

        response = Net::HTTP.start(url.host, url.port, use_ssl: true) do |http|
          request = Net::HTTP::Get.new(url)
          request["Bmx-Token"] = self.class.api_key
          http.request(request)
        end

        parse(response.body)
      end

      def parse(json)
        data = JSON.parse(json)
        series = data.dig("bmx", "series") || []

        series.flat_map do |s|
          base = SERIES[s["idSerie"]]
          next [] unless base

          (s["datos"] || []).filter_map do |obs|
            value = obs["dato"]&.tr(",", "")
            next unless value

            # Skip "N/E" (not available) values
            rate = Float(value, exception: false)
            next unless rate&.positive?

            date = Date.strptime(obs["fecha"], "%d/%m/%Y")
            { date:, base:, quote: "MXN", rate: }
          end
        end
      end
    end
  end
end
