defmodule Berrypod.RateLimitTest do
  use ExUnit.Case, async: true

  alias Berrypod.RateLimit

  describe "check_login/1" do
    test "allows requests within limit" do
      ip = {192, 168, 1, unique_integer()}

      for _i <- 1..5 do
        assert :ok = RateLimit.check_login(ip)
      end
    end

    test "blocks requests exceeding limit" do
      ip = {192, 168, 2, unique_integer()}

      for _i <- 1..5 do
        assert :ok = RateLimit.check_login(ip)
      end

      assert {:error, retry_after} = RateLimit.check_login(ip)
      assert is_integer(retry_after)
      assert retry_after > 0
    end

    test "handles string IP addresses" do
      ip = "10.0.0.#{unique_integer()}"

      assert :ok = RateLimit.check_login(ip)
    end
  end

  describe "check_magic_link/1" do
    test "allows requests within limit" do
      email = "test#{unique_integer()}@example.com"

      for _i <- 1..3 do
        assert :ok = RateLimit.check_magic_link(email)
      end
    end

    test "blocks requests exceeding limit" do
      email = "blocked#{unique_integer()}@example.com"

      for _i <- 1..3 do
        assert :ok = RateLimit.check_magic_link(email)
      end

      assert {:error, retry_after} = RateLimit.check_magic_link(email)
      assert is_integer(retry_after)
      assert retry_after > 0
    end
  end

  describe "check_newsletter/1" do
    test "allows requests within limit" do
      ip = {172, 16, 1, unique_integer()}

      for _i <- 1..10 do
        assert :ok = RateLimit.check_newsletter(ip)
      end
    end

    test "blocks requests exceeding limit" do
      ip = {172, 16, 2, unique_integer()}

      for _i <- 1..10 do
        assert :ok = RateLimit.check_newsletter(ip)
      end

      assert {:error, retry_after} = RateLimit.check_newsletter(ip)
      assert is_integer(retry_after)
    end
  end

  describe "check_api/1" do
    test "allows requests within limit" do
      ip = {10, 10, 1, unique_integer()}

      for _i <- 1..60 do
        assert :ok = RateLimit.check_api(ip)
      end
    end

    test "blocks requests exceeding limit" do
      ip = {10, 10, 2, unique_integer()}

      for _i <- 1..60 do
        assert :ok = RateLimit.check_api(ip)
      end

      assert {:error, retry_after} = RateLimit.check_api(ip)
      assert is_integer(retry_after)
    end
  end

  defp unique_integer do
    System.unique_integer([:positive]) |> rem(256)
  end
end
