defmodule TarakanWeb.Plugs.CodeBrowserRateLimitTest do
  use Tarakan.DataCase, async: true

  import Plug.Conn
  import Plug.Test

  alias TarakanWeb.Plugs.CodeBrowserRateLimit

  test "allows requests under the per-IP budget" do
    opts = CodeBrowserRateLimit.init(limit: 2, window_seconds: 60)

    for path <- [
          "/findings/55d5c681-240a-4e3a-a1f8-45933a30c4ef/code",
          "/github.com/openai/codex"
        ] do
      conn = conn(:get, path) |> CodeBrowserRateLimit.call(opts)
      refute conn.halted
    end
  end

  test "answers 429 once the per-IP budget is exceeded" do
    opts = CodeBrowserRateLimit.init(limit: 2, window_seconds: 60)

    for _ <- 1..2 do
      conn = conn(:get, "/github.com/openai/codex") |> CodeBrowserRateLimit.call(opts)
      refute conn.halted
    end

    conn = conn(:get, "/github.com/openai/codex") |> CodeBrowserRateLimit.call(opts)

    assert conn.halted
    assert conn.status == 429
    assert [retry_after] = get_resp_header(conn, "retry-after")
    assert String.to_integer(retry_after) > 0
  end

  test "IPv6 clients in the same /64 share one bucket" do
    opts = CodeBrowserRateLimit.init(limit: 1, window_seconds: 60)

    first =
      conn(:get, "/github.com/openai/codex")
      |> Map.put(:remote_ip, {0x2001, 0x0DB8, 0, 0, 0, 0, 0, 1})
      |> CodeBrowserRateLimit.call(opts)

    refute first.halted

    second =
      conn(:get, "/github.com/openai/codex")
      |> Map.put(:remote_ip, {0x2001, 0x0DB8, 0, 0, 0xFFFF, 0xEEEE, 0xDDDD, 0xCCCC})
      |> CodeBrowserRateLimit.call(opts)

    assert second.halted
    assert second.status == 429
  end

  test "admins and moderators are exempt from the budget" do
    opts = CodeBrowserRateLimit.init(limit: 1, window_seconds: 60)

    for role <- ["admin", "moderator"], _ <- 1..3 do
      conn =
        conn(:get, "/github.com/openai/codex")
        |> assign(:current_scope, %{platform_role: role})
        |> CodeBrowserRateLimit.call(opts)

      refute conn.halted
    end
  end
end
