# frozen_string_literal: true

require "test_helper"

class DsnAuthenticationServiceTest < ActiveSupport::TestCase
  def setup
    @dsn = Dsn.create!(name: "Test DSN", key: "test-auth-key-1234567890abcdef")
  end

  test "should authenticate via query parameter baffle_key" do
    request = ActionDispatch::TestRequest.create
    request.query_parameters = { "baffle_key" => @dsn.key }

    authenticated_dsn = DsnAuthenticationService.authenticate(request)
    assert_equal @dsn, authenticated_dsn
  end

  test "should authenticate via query parameter sentry_key" do
    request = ActionDispatch::TestRequest.create
    request.query_parameters = { "sentry_key" => @dsn.key }

    authenticated_dsn = DsnAuthenticationService.authenticate(request)
    assert_equal @dsn, authenticated_dsn
  end

  test "should authenticate via query parameter glitchtip_key" do
    request = ActionDispatch::TestRequest.create
    request.query_parameters = { "glitchtip_key" => @dsn.key }

    authenticated_dsn = DsnAuthenticationService.authenticate(request)
    assert_equal @dsn, authenticated_dsn
  end

  test "should authenticate via X-Baffle-Auth header" do
    request = ActionDispatch::TestRequest.create
    request.headers["X-Baffle-Auth"] = "Baffle baffle_key=#{@dsn.key}, baffle_version=1"

    authenticated_dsn = DsnAuthenticationService.authenticate(request)
    assert_equal @dsn, authenticated_dsn
  end

  test "should authenticate via X-Sentry-Auth header" do
    request = ActionDispatch::TestRequest.create
    request.headers["X-Sentry-Auth"] = "Sentry sentry_key=#{@dsn.key}, sentry_version=7"

    authenticated_dsn = DsnAuthenticationService.authenticate(request)
    assert_equal @dsn, authenticated_dsn
  end

  test "should authenticate via Authorization Bearer header" do
    request = ActionDispatch::TestRequest.create
    request.headers["Authorization"] = "Bearer #{@dsn.key}"

    authenticated_dsn = DsnAuthenticationService.authenticate(request)
    assert_equal @dsn, authenticated_dsn
  end

  test "should authenticate via Basic auth with username as key" do
    request = ActionDispatch::TestRequest.create
    credentials = Base64.strict_encode64("#{@dsn.key}:ignored-password")
    request.headers["Authorization"] = "Basic #{credentials}"

    authenticated_dsn = DsnAuthenticationService.authenticate(request)
    assert_equal @dsn, authenticated_dsn
  end

  test "should prioritize query parameter over other methods" do
    request = ActionDispatch::TestRequest.create
    request.query_parameters = { "baffle_key" => @dsn.key }
    request.headers["Authorization"] = "Bearer wrong-key"

    authenticated_dsn = DsnAuthenticationService.authenticate(request)
    assert_equal @dsn, authenticated_dsn
  end

  test "should fail authentication with disabled DSN" do
    @dsn.update!(enabled: false)

    request = ActionDispatch::TestRequest.create
    request.query_parameters = { "baffle_key" => @dsn.key }

    assert_raises(DsnAuthenticationService::AuthenticationError) do
      DsnAuthenticationService.authenticate(request)
    end
  end

  test "should fail authentication with non-existent key" do
    request = ActionDispatch::TestRequest.create
    request.query_parameters = { "baffle_key" => "non-existent-key" }

    assert_raises(DsnAuthenticationService::AuthenticationError) do
      DsnAuthenticationService.authenticate(request)
    end
  end

  test "should fail authentication with no authentication method" do
    request = ActionDispatch::TestRequest.create

    assert_raises(DsnAuthenticationService::AuthenticationError) do
      DsnAuthenticationService.authenticate(request)
    end
  end

  test "should handle malformed Authorization header" do
    request = ActionDispatch::TestRequest.create
    request.headers["Authorization"] = "InvalidHeader"

    assert_nil DsnAuthenticationService.authenticate(request)
  end

  test "should handle malformed Basic auth" do
    request = ActionDispatch::TestRequest.create
    request.headers["Authorization"] = "Basic invalid-base64"

    assert_nil DsnAuthenticationService.authenticate(request)
  end

  test "should handle malformed X-Baffle-Auth header" do
    request = ActionDispatch::TestRequest.create
    request.headers["X-Baffle-Auth"] = "Invalid format"

    assert_nil DsnAuthenticationService.authenticate(request)
  end

  test "should handle empty query parameters" do
    request = ActionDispatch::TestRequest.create
    request.query_parameters = { "baffle_key" => "" }

    assert_nil DsnAuthenticationService.authenticate(request)
  end

  test "should extract key from complex X-Baffle-Auth header" do
    request = ActionDispatch::TestRequest.create
    request.headers["X-Baffle-Auth"] = "Baffle baffle_key=#{@dsn.key}, baffle_version=1, baffle_client=ruby-2.0.0"

    authenticated_dsn = DsnAuthenticationService.authenticate(request)
    assert_equal @dsn, authenticated_dsn
  end

  test "should handle URL-style DSN in Basic auth" do
    # This simulates using the full DSN URL: https://key@domain.com
    request = ActionDispatch::TestRequest.create
    credentials = Base64.strict_encode64("#{@dsn.key}:")
    request.headers["Authorization"] = "Basic #{credentials}"

    authenticated_dsn = DsnAuthenticationService.authenticate(request)
    assert_equal @dsn, authenticated_dsn
  end

  test "should handle special characters in DSN keys" do
    special_dsn = Dsn.create!(name: "Special DSN", key: "special-key-with-dashes_123")
    request = ActionDispatch::TestRequest.create
    request.headers["Authorization"] = "Bearer #{special_dsn.key}"

    authenticated_dsn = DsnAuthenticationService.authenticate(request)
    assert_equal special_dsn, authenticated_dsn
  end
end