# frozen_string_literal: true

require "json"
require "net/http"

require "provider/adapters/adapter"

class Provider
  module Adapters
    # Bank Negara Malaysia daily exchange rates. Data available from 2006-01-03.
    # Historical rates are fetched per-currency per-month.
    class BNM < Adapter
      BASE_URL = "https://api.bnm.gov.my/public/exchange-rate"
      SESSION = "0900"
      HEADERS = { "Accept" => "application/vnd.BNM.API.v1+json" }.freeze

      class << self
        def backfill_range = 30
      end

      def fetch(after: nil, upto: nil)
        start_date = Date.parse(after.to_s)
        end_date = upto || Date.today
        currencies = fetch_currencies
        currencies.flat_map { |code| fetch_currency(code, start_date, end_date) }
      end

      private

      def fetch_currencies
        uri = URI("#{BASE_URL}?session=#{SESSION}")
        response = Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
          http.get("#{uri.path}?#{uri.query}", HEADERS)
        end
        data = JSON.parse(response.body)
        data["data"].map { |item| item["currency_code"] }
      end

      def fetch_currency(code, start_date, end_date)
        records = []
        each_month(start_date, end_date) do |year, month|
          uri = URI("#{BASE_URL}/#{code}/year/#{year}/month/#{month}?session=#{SESSION}")
          response = Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
            http.get("#{uri.path}?#{uri.query}", HEADERS)
          end
          data = JSON.parse(response.body)
          currency_data = data["data"]
          next if currency_data.nil? || currency_data.is_a?(Array)

          unit = currency_data["unit"] || 1
          rates = currency_data["rate"]
          rates = [rates] unless rates.is_a?(Array)

          rates.each do |rate|
            mid = rate["middle_rate"]
            next unless mid

            date = Date.parse(rate["date"])
            next if date > end_date

            records << { date:, base: code, quote: "MYR", rate: mid / unit }
          end

          sleep(1)
        end
        records
      end

      def each_month(start_date, end_date)
        date = Date.new(start_date.year, start_date.month, 1)
        while date <= end_date
          yield date.year, date.month
          date = date.next_month
        end
      end
    end
  end
end
