# frozen_string_literal: true

require_relative "../../helper"
require "provider/adapters/imf"

class Provider < Sequel::Model(:providers)
  module Adapters
    describe IMF do
      before do
        VCR.insert_cassette("imf", match_requests_on: [:method, :uri])
      end

      after do
        VCR.eject_cassette
      end

      let(:adapter) { IMF.new }

      it "fetches rates across both Currency blocks in the TSV response" do
        dataset = adapter.fetch(after: Date.new(2026, 3, 1), upto: Date.new(2026, 3, 31))
        dates = dataset.map { |r| r[:date] }.uniq

        _(dates).must_include(Date.new(2026, 3, 17))
        _(dates.size).must_be(:>, 11)
      end

      it "fetches multiple currencies per date without duplicating records" do
        dataset = adapter.fetch(after: Date.new(2026, 3, 1), upto: Date.new(2026, 3, 31))
        dates = dataset.map { |r| r[:date] }.uniq
        sample = dataset.select { |r| r[:date] == dates.first }

        _(sample.size).must_be(:>, 1)

        keys = dataset.map { |r| [r[:date], r[:base], r[:quote]] }

        _(keys.size).must_equal(keys.uniq.size)
      end

      it "parses indirect quotes with (1) suffix" do
        tsv = <<~TSV
          Representative Exchange Rates for Selected Currencies for January 2026
          Currency\tJanuary 02, 2026\tJanuary 05, 2026
          Euro(1)\t1.1698\t1.1606
          Japanese yen\t156.40\t157.41
          U.S. dollar\t1.0000\t1.0000
        TSV

        records = adapter.parse(tsv)

        eur = records.select { |r| r[:base] == "EUR" || r[:quote] == "EUR" }

        _(eur.first[:base]).must_equal("EUR")
        _(eur.first[:quote]).must_equal("USD")

        jpy = records.select { |r| r[:base] == "USD" && r[:quote] == "JPY" }

        _(jpy.first[:rate]).must_equal(156.4)
      end

      it "parses KWD as direct quote (units per USD)" do
        tsv = <<~TSV
          Representative Exchange Rates for Selected Currencies for March 2026
          Currency\tMarch 02, 2026
          Kuwaiti dinar\t0.306600
        TSV

        records = adapter.parse(tsv)
        kwd = records.find { |r| r[:quote] == "KWD" || r[:base] == "KWD" }

        _(kwd[:base]).must_equal("USD")
        _(kwd[:quote]).must_equal("KWD")
        _(kwd[:rate]).must_equal(0.3066)
      end

      it "skips USD rows" do
        tsv = <<~TSV
          Representative Exchange Rates for Selected Currencies for January 2026
          Currency\tJanuary 02, 2026
          U.S. dollar\t1.0000
          Euro(1)\t1.1698
        TSV

        records = adapter.parse(tsv)

        _(records.none? { |r| r[:base] == "USD" && r[:quote] == "USD" }).must_equal(true)
      end

      it "parses Continued blocks with their own date header" do
        tsv = <<~TSV
          Representative Exchange Rates for Selected Currencies for March 2026
          Currency\tMarch 02, 2026\tMarch 03, 2026
          Chinese yuan\t6.882900\t6.897100
          U.S. dollar\t1.000000\t1.000000

          Representative Exchange Rates for Selected Currencies for March 2026 Continued

          Currency\tMarch 17, 2026\tMarch 18, 2026
          Chinese yuan\t6.888300\t6.875600
          U.S. dollar\t1.000000\t1.000000
        TSV

        records = adapter.parse(tsv)
        cny = records.select { |r| r[:quote] == "CNY" }.sort_by { |r| r[:date] }

        _(cny.map { |r| r[:date] }).must_equal([
          Date.new(2026, 3, 2),
          Date.new(2026, 3, 3),
          Date.new(2026, 3, 17),
          Date.new(2026, 3, 18),
        ])
        _(cny.find { |r| r[:date] == Date.new(2026, 3, 17) }[:rate]).must_equal(6.8883)
      end

      it "does not emit duplicate (date, base, quote) records across blocks" do
        tsv = <<~TSV
          Currency\tMarch 02, 2026\tMarch 03, 2026
          Chinese yuan\t6.882900\t6.897100

          Currency\tMarch 17, 2026\tMarch 18, 2026
          Chinese yuan\t6.888300\t6.875600
        TSV

        records = adapter.parse(tsv)
        keys = records.map { |r| [r[:date], r[:base], r[:quote]] }

        _(keys.size).must_equal(keys.uniq.size)
      end

      it "emits SDR cross rates only as USD/XDR" do
        dataset = adapter.fetch(after: Date.new(2026, 3, 1), upto: Date.new(2026, 3, 31))
        sdr = dataset.select { |r| r[:quote] == "XDR" }

        _(sdr).wont_be_empty
        _(sdr.map { |r| r[:base] }.uniq).must_equal(["USD"])
      end

      it "parses USD/XDR from SDR cross rates and ignores other currencies" do
        tsv = <<~TSV
          SDRs per Currency unit for April 2026
          Currency\tApril 01, 2026\tApril 02, 2026
          Euro\t0.8507900000\t0.8483160000
          Japanese yen\t0.0046154900\t0.0046392700
          U.S. dollar\t0.7331240000\t0.7360660000
        TSV

        records = adapter.parse_sdrcv(tsv)

        _(records.map { |r| r[:base] }.uniq).must_equal(["USD"])
        _(records.size).must_equal(2)

        usd = records.find { |r| r[:date] == Date.new(2026, 4, 1) }

        _(usd[:quote]).must_equal("XDR")
        _(usd[:rate]).must_equal(0.7331240)
      end

      it "skips SDR rows with NA values" do
        tsv = <<~TSV
          SDRs per Currency unit for April 2026
          Currency\tApril 01, 2026\tApril 02, 2026
          U.S. dollar\tNA\t0.7360660000
        TSV

        records = adapter.parse_sdrcv(tsv)

        _(records.size).must_equal(1)
        _(records.first[:date]).must_equal(Date.new(2026, 4, 2))
      end
    end
  end
end
