defmodule Plausible.Session.SaltsTest do
  use Plausible.DataCase, async: false

  alias Plausible.Session.Salts
  import Ecto.Query

  test "agent starts and responds with current salt" do
    {:ok, _} = Salts.start_link(name: __MODULE__)
    %{current: current, previous: nil} = Salts.fetch(__MODULE__)
    assert is_binary(current)
  end

  test "agent starts and responds with current and previous salt after rotation" do
    {:ok, _} = Salts.start_link(name: __MODULE__)
    %{current: first, previous: nil} = Salts.fetch(__MODULE__)
    :ok = Salts.rotate(__MODULE__)

    %{current: current, previous: ^first} = Salts.fetch(__MODULE__)
    assert is_binary(current)
  end

  test "old salts can be cleaned" do
    t1 = ~U[2025-06-10 15:29:40Z]

    {:ok, _} = Salts.start_link(name: __MODULE__, now: t1)

    t2 = ~U[2025-06-11 15:29:40Z]

    :ok = Salts.rotate(__MODULE__, t2)

    %{current: old_current, previous: _old_previous} =
      Salts.fetch(__MODULE__)

    q = from(s in "salts")
    count = Repo.aggregate(q, :count)
    assert count == 2

    t3 = ~U[2025-06-13 15:34:40Z]

    :ok = Salts.rotate(__MODULE__, t3)

    %{current: _current, previous: ^old_current} =
      Salts.fetch(__MODULE__)

    q = from(s in "salts")
    count = Repo.aggregate(q, :count)
    assert count == 2
  end

  test "salts refresh when another node rotates them" do
    t1 = ~U[2024-06-10 15:29:40Z]
    {:ok, _} = Salts.start_link(name: :node_1, now: t1)
    {:ok, _} = Salts.start_link(name: :node_2, now: t1)

    t2 = ~U[2024-06-11 15:29:40Z]

    :ok = Salts.rotate(:node_2, t2)

    assert Salts.fetch(:node_1) != Salts.fetch(:node_2)

    send(:node_1, {:refresh, t2})

    assert eventually(fn ->
             {Salts.fetch(:node_1) == Salts.fetch(:node_2), :ok}
           end)
  end
end
