# frozen_string_literal: true

module Dispatch
  module Adapter
    class Claude < Base
      module Headers
        CLAUDE_CODE_VERSION = "2.1.63"
        STAINLESS_PACKAGE_VERSION = "0.74.0"
        DEFAULT_BETAS = %w[
          claude-code-20250219
          oauth-2025-04-20
          context-management-2025-06-27
          prompt-caching-scope-2026-01-05
        ].freeze
        INTERLEAVED_THINKING_BETA = "interleaved-thinking-2025-05-14"
        USER_AGENT = "claude-cli/#{CLAUDE_CODE_VERSION} (external, cli)".freeze

        module_function

        # Build the full set of request headers.
        #
        # @param api_key [String] OAuth access token or raw API key
        # @param is_oauth [Boolean, nil] nil = auto-detect from token prefix
        # @param stream [Boolean] set Accept to text/event-stream when true
        # @param extra_betas [Array<String>] additional beta header values
        # @param interleaved_thinking [Boolean] include the interleaved-thinking beta
        # @param base_url [String] (unused in headers but kept for symmetry)
        # @param extra [Hash] low-precedence caller overrides
        # @param claude_code_only [Boolean] when true, omit SDK-identifying
        #   headers (anthropic-version, x-stainless-*) so the request looks
        #   like real Claude Code rather than the Anthropic SDK. Required
        #   for /api/oauth/* endpoints which reject SDK-style requests with
        #   "OAuth authentication is currently not supported". Also adds the
        #   accept-encoding and connection headers that Claude Code sends.
        # @return [Hash<String,String>]
        def build(
          api_key:,
          is_oauth: nil,
          stream: false,
          extra_betas: [],
          interleaved_thinking: true,
          base_url: "https://api.anthropic.com", # rubocop:disable Lint/UnusedMethodArgument
          extra: {},
          claude_code_only: false
        )
          oauth = is_oauth.nil? ? api_key.to_s.start_with?("sk-ant-oat") : is_oauth

          # Start with the lowest-priority caller extras (these can be
          # clobbered by anything below).
          headers = extra.transform_keys(&:to_s)

          if claude_code_only
            # Real Claude Code header set — no SDK identifiers.
            # NOTE: do NOT set `accept-encoding` here. Net::HTTP only
            # auto-decompresses responses when it added the accept-encoding
            # header itself; setting it manually leaves us with raw gzip
            # bytes that JSON.parse cannot handle.
            headers["connection"] = "keep-alive"
          else
            # Stainless / SDK metadata headers
            headers.merge!(
              "anthropic-version" => "2023-06-01",
              "x-stainless-lang" => "ruby",
              "x-stainless-package-version" => STAINLESS_PACKAGE_VERSION,
              "x-stainless-runtime" => "ruby",
              "x-stainless-runtime-version" => RUBY_VERSION
            )
          end

          # User-Agent (OAuth only — raw API-key callers don't set it)
          headers["User-Agent"] = USER_AGENT if oauth

          # Content-Type / Accept
          headers["Content-Type"] = "application/json"
          headers["Accept"]       = if stream
                                      "text/event-stream"
                                    elsif claude_code_only
                                      "application/json, text/plain, */*"
                                    else
                                      "application/json"
                                    end

          # Anthropic-Beta
          betas = DEFAULT_BETAS.dup
          betas << INTERLEAVED_THINKING_BETA if interleaved_thinking
          betas.concat(Array(extra_betas))
          betas = betas.uniq
          headers["anthropic-beta"] = betas.join(",")

          # Auth — highest priority, never overridable by caller extras
          if oauth
            headers["Authorization"] = "Bearer #{api_key}"
            headers.delete("X-Api-Key")
          else
            headers["X-Api-Key"] = api_key.to_s
            headers.delete("Authorization")
          end

          headers
        end
      end
    end
  end
end
