# frozen_string_literal: true

RSpec.describe Dispatch::Adapter::Claude::Headers do
  let(:oauth_token) { "sk-ant-oat01-abc123" }
  let(:api_key)     { "sk-ant-api03-xyz789" }

  describe ".build" do
    context "with OAuth token" do
      subject(:headers) { described_class.build(api_key: oauth_token) }

      it "emits Authorization: Bearer ..." do
        expect(headers["Authorization"]).to eq("Bearer #{oauth_token}")
      end

      it "does not emit X-Api-Key" do
        expect(headers).not_to have_key("X-Api-Key")
      end

      it "sets User-Agent to the Claude CLI user agent" do
        expect(headers["User-Agent"]).to eq(Dispatch::Adapter::Claude::Headers::USER_AGENT)
      end

      it "sets Content-Type to application/json" do
        expect(headers["Content-Type"]).to eq("application/json")
      end

      it "sets Accept to application/json for non-streaming" do
        expect(headers["Accept"]).to eq("application/json")
      end

      it "sets Accept to text/event-stream for streaming" do
        h = described_class.build(api_key: oauth_token, stream: true)
        expect(h["Accept"]).to eq("text/event-stream")
      end

      it "includes anthropic-version header" do
        expect(headers["anthropic-version"]).to eq("2023-06-01")
      end
    end

    context "with raw API key" do
      subject(:headers) { described_class.build(api_key: api_key) }

      it "emits X-Api-Key" do
        expect(headers["X-Api-Key"]).to eq(api_key)
      end

      it "does not emit Authorization" do
        expect(headers).not_to have_key("Authorization")
      end

      it "does not set User-Agent" do
        expect(headers).not_to have_key("User-Agent")
      end
    end

    context "with explicit is_oauth: true override" do
      it "treats the key as OAuth even when it doesn't start with sk-ant-oat" do
        h = described_class.build(api_key: "some-other-token", is_oauth: true)
        expect(h["Authorization"]).to eq("Bearer some-other-token")
        expect(h).not_to have_key("X-Api-Key")
      end
    end

    context "with explicit is_oauth: false override" do
      it "treats an oat token as API key" do
        h = described_class.build(api_key: oauth_token, is_oauth: false)
        expect(h["X-Api-Key"]).to eq(oauth_token)
        expect(h).not_to have_key("Authorization")
      end
    end

    context "Anthropic-Beta header" do
      it "includes all DEFAULT_BETAS" do
        h = described_class.build(api_key: api_key)
        beta_values = h["anthropic-beta"].split(",")
        Dispatch::Adapter::Claude::Headers::DEFAULT_BETAS.each do |b|
          expect(beta_values).to include(b)
        end
      end

      it "includes interleaved-thinking beta by default" do
        h = described_class.build(api_key: api_key)
        expect(h["anthropic-beta"]).to include(
          Dispatch::Adapter::Claude::Headers::INTERLEAVED_THINKING_BETA
        )
      end

      it "omits interleaved-thinking beta when interleaved_thinking: false" do
        h = described_class.build(api_key: api_key, interleaved_thinking: false)
        expect(h["anthropic-beta"]).not_to include(
          Dispatch::Adapter::Claude::Headers::INTERLEAVED_THINKING_BETA
        )
      end

      it "includes extra_betas in the beta header" do
        h = described_class.build(api_key: api_key, extra_betas: ["my-beta-2025-01-01"])
        expect(h["anthropic-beta"]).to include("my-beta-2025-01-01")
      end

      it "deduplicates beta values" do
        dup_beta = Dispatch::Adapter::Claude::Headers::DEFAULT_BETAS.first
        h = described_class.build(api_key: api_key, extra_betas: [dup_beta])
        values = h["anthropic-beta"].split(",")
        expect(values.count(dup_beta)).to eq(1)
      end
    end

    context "with caller extra headers" do
      it "includes extra headers" do
        h = described_class.build(api_key: api_key, extra: { "X-Custom" => "value" })
        expect(h["X-Custom"]).to eq("value")
      end

      it "caller extra does NOT clobber Authorization for OAuth tokens" do
        h = described_class.build(
          api_key: oauth_token,
          extra: { "Authorization" => "Bearer malicious" }
        )
        expect(h["Authorization"]).to eq("Bearer #{oauth_token}")
      end

      it "caller extra does NOT clobber X-Api-Key for API keys" do
        h = described_class.build(
          api_key: api_key,
          extra: { "X-Api-Key" => "stolen-key" }
        )
        expect(h["X-Api-Key"]).to eq(api_key)
      end

      it "accepts extra keys as symbols and converts them to strings" do
        h = described_class.build(api_key: api_key, extra: { "X-Custom": "value" })
        expect(h["X-Custom"]).to eq("value")
      end
    end

    context "Stainless metadata headers" do
      subject(:headers) { described_class.build(api_key: api_key) }

      it "includes x-stainless-lang: ruby" do
        expect(headers["x-stainless-lang"]).to eq("ruby")
      end

      it "includes x-stainless-package-version" do
        expect(headers["x-stainless-package-version"]).to eq(
          Dispatch::Adapter::Claude::Headers::STAINLESS_PACKAGE_VERSION
        )
      end

      it "includes x-stainless-runtime: ruby" do
        expect(headers["x-stainless-runtime"]).to eq("ruby")
      end

      it "includes x-stainless-runtime-version matching RUBY_VERSION" do
        expect(headers["x-stainless-runtime-version"]).to eq(RUBY_VERSION)
      end
    end
  end
end
