defmodule Mv.Authorization.ActorTest do
  @moduledoc """
  Tests for the Actor helper module.
  """
  use Mv.DataCase, async: false

  alias Mv.Accounts
  alias Mv.Authorization.Actor

  setup do
    system_actor = Mv.Helpers.SystemActor.get_system_actor()
    %{actor: system_actor}
  end

  describe "ensure_loaded/1" do
    test "returns nil when actor is nil" do
      assert Actor.ensure_loaded(nil) == nil
    end

    test "returns actor as-is when role is already loaded", %{actor: actor} do
      # Create user with role
      {:ok, user} =
        Accounts.User
        |> Ash.Changeset.for_create(:register_with_password, %{
          email: "test#{System.unique_integer([:positive])}@example.com",
          password: "testpassword123"
        })
        |> Ash.create(actor: actor)

      # Load role
      {:ok, user_with_role} = Ash.load(user, :role, domain: Mv.Accounts, actor: actor)

      # Should return as-is (no additional load)
      result = Actor.ensure_loaded(user_with_role)
      assert result.id == user.id
      assert result.role != %Ash.NotLoaded{}
    end

    test "loads role when it's NotLoaded", %{actor: actor} do
      # Create a role first
      {:ok, role} =
        Mv.Authorization.Role
        |> Ash.Changeset.for_create(:create_role, %{
          name: "Test Role #{System.unique_integer([:positive])}",
          description: "Test role",
          permission_set_name: "own_data"
        })
        |> Ash.create(actor: actor)

      # Create user with role
      {:ok, user} =
        Accounts.User
        |> Ash.Changeset.for_create(:register_with_password, %{
          email: "test#{System.unique_integer([:positive])}@example.com",
          password: "testpassword123"
        })
        |> Ash.create(actor: actor)

      # Assign role to user
      {:ok, user_with_role} =
        user
        |> Ash.Changeset.for_update(:update, %{})
        |> Ash.Changeset.manage_relationship(:role, role, type: :append_and_remove)
        |> Ash.update(actor: actor)

      # Fetch user again WITHOUT loading role (simulates "role not preloaded" scenario)
      {:ok, user_without_role_loaded} =
        Ash.get(Accounts.User, user_with_role.id, domain: Mv.Accounts, actor: actor)

      # User has role as NotLoaded (relationship not preloaded)
      assert match?(%Ash.NotLoaded{}, user_without_role_loaded.role)

      # ensure_loaded should load it
      result = Actor.ensure_loaded(user_without_role_loaded)
      assert result.id == user.id
      refute match?(%Ash.NotLoaded{}, result.role)
      assert result.role.id == role.id
    end

    test "returns non-User actors as-is (no-op)" do
      # Create a plain map (not Mv.Accounts.User)
      other_actor = %{id: "fake", role: %Ash.NotLoaded{field: :role}}

      # Should return as-is (pattern match doesn't apply to non-User)
      result = Actor.ensure_loaded(other_actor)
      assert result == other_actor
    end
  end
end
