# frozen_string_literal: true

require "csv"
require "net/http"

require "provider/adapters/adapter"

class Provider
  module Adapters
    class NB < Adapter
      SDMX_URL = "https://data.norges-bank.no/api/data/EXR/B..NOK.SP"
      class << self
        def backfill_range = 365
      end

      def fetch(after: nil, upto: nil)
        url = URI(SDMX_URL)
        params = { format: "csvdata" }
        params[:startPeriod] = after.to_s if after
        params[:endPeriod] = upto.to_s if upto
        url.query = URI.encode_www_form(params)

        dataset = []
        stream_csv(url) do |row|
          record = parse_row(row)
          dataset << record if record
        end

        dataset
      end

      def parse(csv)
        CSV.parse(csv, headers: true, liberal_parsing: true).filter_map do |row|
          parse_row(row)
        end
      end

      private

      def parse_row(row)
        return unless row["FREQ"] == "B"

        base = row["BASE_CUR"]
        return unless base

        rate = Float(row["OBS_VALUE"])
        unit_mult = Integer(row["UNIT_MULT"] || "0")
        rate /= 10**unit_mult if unit_mult > 0
        date = Date.parse(row["TIME_PERIOD"])

        { date:, base:, quote: "NOK", rate: }
      end

      def stream_csv(url)
        uri = URI(url)
        Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
          request = Net::HTTP::Get.new(uri)
          http.request(request) do |response|
            headers = nil
            buffer = +""

            response.read_body do |chunk|
              buffer << chunk
              while (line_end = buffer.index("\n"))
                line = buffer.slice!(0..line_end)
                if headers.nil?
                  headers = CSV.parse_line(line, liberal_parsing: true)
                else
                  values = CSV.parse_line(line, liberal_parsing: true)
                  next unless values

                  row = CSV::Row.new(headers, values)
                  yield row
                end
              end
            end

            # Process remaining buffer
            if headers && !buffer.empty?
              values = CSV.parse_line(buffer, liberal_parsing: true)
              yield CSV::Row.new(headers, values) if values
            end
          end
        end
      end
    end
  end
end
