defmodule Mv.Authorization.Checks.HasPermissionIntegrationTest do
  @moduledoc """
  Integration tests for HasPermission policy check.

  These tests verify that the filter expressions generated by HasPermission
  have the correct structure for relationship-based filtering.

  Note: Full integration tests with real queries require resources to have
  policies that use HasPermission. These tests validate filter expression
  structure and ensure the relationship paths are correct.
  """
  use ExUnit.Case, async: true

  alias Mv.Authorization.Checks.HasPermission

  # Helper to create mock actor with role
  defp create_actor_with_role(permission_set_name, opts \\ []) do
    actor = %{
      id: "user-#{System.unique_integer([:positive])}",
      role: %{permission_set_name: permission_set_name}
    }

    # Add member_id if provided (needed for :linked scope tests)
    case Keyword.get(opts, :member_id) do
      nil -> actor
      member_id -> Map.put(actor, :member_id, member_id)
    end
  end

  describe "Filter Expression Structure - :linked scope" do
    test "Member filter uses actor.member_id (inverse relationship)" do
      actor = create_actor_with_role("own_data", member_id: "member-123")
      authorizer = create_authorizer(Mv.Membership.Member, :read)

      filter = HasPermission.auto_filter(actor, authorizer, [])

      # Verify filter is not nil (should return a filter for :linked scope)
      assert not is_nil(filter)

      # The filter should be a valid expression (keyword list or Ash.Expr)
      # We verify it's not nil and can be used in queries
      assert is_list(filter) or is_map(filter)
    end

    test "CustomFieldValue filter uses actor.member_id (via member relationship)" do
      actor = create_actor_with_role("own_data", member_id: "member-123")
      authorizer = create_authorizer(Mv.Membership.CustomFieldValue, :read)

      filter = HasPermission.auto_filter(actor, authorizer, [])

      # Verify filter is not nil
      assert not is_nil(filter)

      # The filter should be a valid expression
      assert is_list(filter) or is_map(filter)
    end
  end

  describe "Filter Expression Structure - :own scope" do
    test "User filter uses id == actor.id" do
      actor = create_actor_with_role("own_data")
      authorizer = create_authorizer(Mv.Accounts.User, :read)

      filter = HasPermission.auto_filter(actor, authorizer, [])

      # Verify filter is not nil (should return a filter for :own scope)
      assert not is_nil(filter)

      # The filter should be a valid expression
      assert is_list(filter) or is_map(filter)
    end
  end

  describe "Filter Expression Structure - :all scope" do
    test "Admin can read all members without filter (returns expr(true))" do
      actor = create_actor_with_role("admin")
      authorizer = create_authorizer(Mv.Membership.Member, :read)

      filter = HasPermission.auto_filter(actor, authorizer, [])

      # :all scope should return [] (empty keyword list = no filter = allow all records)
      # After auto_filter fix: no longer returns nil, returns [] instead
      assert filter == []
    end
  end

  # Helper to create a mock authorizer
  defp create_authorizer(resource, action) do
    %Ash.Policy.Authorizer{
      resource: resource,
      subject: %{
        action: %{type: action},
        data: nil
      }
    }
  end
end
