# frozen_string_literal: true

RSpec.describe DiscourseIpInfo do
  describe ".get" do
    let(:ip) { "81.2.69.142" }
    let(:expected_ip_info) do
      {
        city: "London",
        country: "United Kingdom",
        country_code: "GB",
        geoname_ids: [6_255_148, 2_635_167, 2_643_743, 6_269_131],
        location: "London, England, United Kingdom",
        region: "England",
        latitude: 51.5142,
        longitude: -0.0931,
      }
    end

    before { described_class.open_db(Rails.root.join("spec/fixtures/mmdb").to_s) }

    it "returns IP info without hostname when reverse DNS is interrupted" do
      Resolv::DNS.any_instance.stubs(:getname).with(ip).raises(Timeout::Error)

      result = described_class.get(ip, resolve_hostname: true)

      expect(result).to eq(expected_ip_info)
    end

    it "sets a timeout for reverse DNS" do
      resolver = Resolv::DNS.new
      resolver
        .expects(:timeouts=)
        .with { |timeouts| Array(timeouts).present? && Array(timeouts).sum <= 5 }
      resolver.stubs(:getname).with(ip).raises(Resolv::ResolvError)

      Resolv::DNS.stubs(:new).returns(resolver)

      result = described_class.get(ip, resolve_hostname: true)

      expect(result).to eq(expected_ip_info)
    end
  end

  describe ".mmdb_download" do
    before { Discourse::Utils.stubs(:execute_command) }

    it "downloads MaxMind databases from permalinks when the license key and account ID are set" do
      global_setting :maxmind_license_key, "license_key"
      global_setting :maxmind_account_id, "account_id"

      stub_request(
        :get,
        "https://download.maxmind.com/geoip/databases/GeoLite2-City/download?suffix=tar.gz",
      ).with(basic_auth: %w[account_id license_key]).to_return(
        status: 302,
        body: "",
        headers: {
          location:
            "https://mm-prod-geoip-databases.a2649acb697e2c09b632799562c076f2.r2.cloudflarestorage.com/some-path",
        },
      )

      stub_request(
        :get,
        "https://mm-prod-geoip-databases.a2649acb697e2c09b632799562c076f2.r2.cloudflarestorage.com/some-path",
      ).with { |req| expect(req.headers.key?("Authorization")).to eq(false) }.to_return(status: 200)

      described_class.mmdb_download("GeoLite2-City")
    end

    it "uses the legacy MaxMind download URL when only the license key is set" do
      global_setting :maxmind_license_key, "license_key"

      stub_request(
        :get,
        "https://download.maxmind.com/app/geoip_download?license_key=license_key&edition_id=GeoLite2-City&suffix=tar.gz",
      ).to_return(status: 200, body: "", headers: {})

      described_class.mmdb_download("GeoLite2-City")
    end

    it "downloads MaxMind databases from the configured mirror" do
      global_setting :maxmind_mirror_url, "https://b.www.example.com/mirror"

      stub_request(:get, "https://b.www.example.com/mirror/GeoLite2-City.tar.gz").to_return(
        status: 200,
        body: "",
      )

      described_class.mmdb_download("GeoLite2-City")
    end

    it "downloads MaxMind databases from a mirror URL with a trailing slash" do
      global_setting :maxmind_mirror_url, "https://b.www.example.com/mirror/"

      stub_request(:get, "https://b.www.example.com/mirror/GeoLite2-City.tar.gz").to_return(
        status: 200,
        body: "",
      )

      described_class.mmdb_download("GeoLite2-City")
    end

    it "logs database download exceptions without raising them" do
      fake_logger = FakeLogger.new
      Rails.logger.broadcast_to(fake_logger)

      global_setting :maxmind_license_key, "license_key"
      global_setting :maxmind_account_id, "account_id"

      stub_request(
        :get,
        "https://download.maxmind.com/geoip/databases/GeoLite2-City/download?suffix=tar.gz",
      ).with(basic_auth: %w[account_id license_key]).to_return(status: 500, body: nil, headers: {})

      expect do described_class.mmdb_download("GeoLite2-City") end.not_to raise_error

      expect(fake_logger.warnings.length).to eq(1)

      expect(fake_logger.warnings.first).to include(
        "MaxMind database GeoLite2-City download failed. 500 Error",
      )
    ensure
      Rails.logger.stop_broadcasting_to(fake_logger)
    end
  end
end
