# frozen_string_literal: true

require "tmpdir"
require "fileutils"

# ---------------------------------------------------------------------------
# SAFETY: sandbox the developer's real home directory.
#
# Several constants in this gem (notably TokenStore::DEFAULT_PATH and the
# rate-limiter state file derived from it) freeze a path under Dir.home at
# class-load time. If we don't redirect HOME before the `require` below,
# every spec that constructs an adapter without an explicit token_store:
# would read/write ~/.config/dispatch/claude_oauth.json AND
# ~/.config/dispatch/claude_rate_limit on the developer's real machine —
# leaking state across runs and (because the default min_request_interval
# is 1.0s) silently injecting up to a full second of sleep before every
# stubbed HTTP call. That is what makes a fast unit suite take 10 minutes.
#
# We point HOME at a fresh tmp dir for the entire rspec process and clean
# it up on exit. This MUST happen before `require "dispatch/adapter/claude"`.
# ---------------------------------------------------------------------------
SPEC_SANDBOX_HOME = Dir.mktmpdir("dispatch-claude-spec-home-")
ENV["HOME"] = SPEC_SANDBOX_HOME
at_exit { FileUtils.rm_rf(SPEC_SANDBOX_HOME) }

require "dispatch/adapter/claude"

# ---------------------------------------------------------------------------
# SAFETY: block ALL real network traffic from every spec, unconditionally.
#
# This gem talks to the live Anthropic API, which costs real money and can
# hit production rate limits / billing. Tests must NEVER make a real
# outbound HTTP request, even if a spec author forgets to
# `require "webmock/rspec"` or to stub a request explicitly.
#
# Loading webmock here ensures Net::HTTP is monkey-patched process-wide for
# every rspec invocation — including running a single spec file in isolation.
# `disable_net_connect!` then makes any unstubbed request raise
# WebMock::NetConnectNotAllowedError instead of silently going to the wire.
#
# `allow_localhost: false` is explicit: even loopback traffic must be stubbed
# (the OAuth callback-server specs need to stub their own 127.0.0.1 calls).
# ---------------------------------------------------------------------------
require "webmock/rspec"
WebMock.disable_net_connect!(allow_localhost: false)

# Disable interactive OAuth auto-recovery during specs — otherwise an
# unstubbed 401 would attempt to spawn a browser and run the full OAuth
# login flow, which would hang the suite.
ENV["AUTH_RECOVERY"] = "0"

RSpec.configure do |config|
  # Enable flags like --only-failures and --next-failure
  config.example_status_persistence_file_path = ".rspec_status"

  # Disable RSpec exposing methods globally on `Module` and `main`
  config.disable_monkey_patching!

  config.expect_with :rspec do |c|
    c.syntax = :expect
  end

  # Belt-and-braces: re-assert net-connect lockdown before every example,
  # so a spec that calls WebMock.allow_net_connect! cannot leak that state
  # to subsequent specs.
  config.before(:each) do
    WebMock.disable_net_connect!(allow_localhost: false)
  end

  # ── Speed: neutralise the 1-second-per-request cooldown ────────────────
  #
  # Dispatch::Adapter::Claude defaults `min_request_interval` to 1.0, which
  # makes RateLimiter#wait! flock a state file and sleep up to a full
  # second before every API call. With WebMock stubs that cost is pure
  # waste — it added many minutes to the suite. For every spec EXCEPT
  # rate_limiter_spec.rb (which explicitly verifies real cooldown timing),
  # we stub the constant down to 0 so wait! short-circuits as a no-op.
  config.before(:each) do |example|
    stub_const("Dispatch::Adapter::Claude::DEFAULT_MIN_REQUEST_INTERVAL", 0) unless example.metadata[:file_path].to_s.include?("rate_limiter_spec")

    # Also wipe the sandboxed rate-limit / token files between examples so
    # state from one example can never bleed into the next.
    config_dir = File.join(SPEC_SANDBOX_HOME, ".config", "dispatch")
    if Dir.exist?(config_dir)
      Dir.glob(File.join(config_dir, "*")).each do |f|
        File.delete(f)
      rescue StandardError
        nil
      end
    end
  end
end
