defmodule Mv.Accounts.UserMemberRelationshipTest do
  # Using async: true for faster test execution
  # This is safe because all database operations are sandboxed per test
  use Mv.DataCase, async: true
  alias Mv.Accounts
  alias Mv.Membership

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

  describe "User-Member Relationship - Basic Tests" do
    @valid_user_attrs %{
      email: "test@example.com"
    }

    @valid_member_attrs %{
      first_name: "John",
      last_name: "Doe",
      email: "john@example.com"
    }

    test "user can exist without member", %{actor: actor} do
      {:ok, user} = Accounts.create_user(@valid_user_attrs, actor: actor)
      assert user.member_id == nil

      # Load the relationship to test it
      {:ok, user_with_member} =
        Ash.get(Mv.Accounts.User, user.id, actor: actor, load: [:member])

      assert user_with_member.member == nil
    end

    test "member can exist without user", %{actor: actor} do
      {:ok, member} = Membership.create_member(@valid_member_attrs, actor: actor)
      assert member.id != nil
      assert member.first_name == "John"

      # Load the relationship to test it
      {:ok, member_with_user} =
        Ash.get(Mv.Membership.Member, member.id, actor: actor, load: [:user])

      assert member_with_user.user == nil
    end
  end

  describe "User-Member Relationship - Linking Tests" do
    @valid_user_attrs %{
      email: "test1@example.com"
    }

    @valid_member_attrs %{
      first_name: "Alice",
      last_name: "Johnson",
      email: "alice@example.com"
    }

    test "user can be linked to member during user creation", %{actor: actor} do
      {:ok, member} = Membership.create_member(@valid_member_attrs, actor: actor)

      user_attrs = Map.put(@valid_user_attrs, :member, %{id: member.id})
      {:ok, user} = Accounts.create_user(user_attrs, actor: actor)

      # Load the relationship to test it
      {:ok, user_with_member} =
        Ash.get(Mv.Accounts.User, user.id, actor: actor, load: [:member])

      assert user_with_member.member.id == member.id
    end

    test "member can be linked to user during member creation using manage_relationship", %{
      actor: actor
    } do
      {:ok, user} = Accounts.create_user(@valid_user_attrs, actor: actor)

      member_attrs = Map.put(@valid_member_attrs, :user, %{id: user.id})
      {:ok, member} = Membership.create_member(member_attrs, actor: actor)

      # Load the relationship to test it
      {:ok, member_with_user} =
        Ash.get(Mv.Membership.Member, member.id, actor: actor, load: [:user])

      assert member_with_user.user.id == user.id
    end

    test "user can be linked to member during update", %{actor: actor} do
      {:ok, user} = Accounts.create_user(@valid_user_attrs, actor: actor)
      {:ok, member} = Membership.create_member(@valid_member_attrs, actor: actor)

      {:ok, updated_user} = Accounts.update_user(user, %{member: %{id: member.id}}, actor: actor)

      # Load the relationship to test it
      {:ok, user_with_member} =
        Ash.get(Mv.Accounts.User, updated_user.id, actor: actor, load: [:member])

      assert user_with_member.member.id == member.id
    end

    test "member can be linked to user during update using manage_relationship", %{actor: actor} do
      {:ok, user} = Accounts.create_user(@valid_user_attrs, actor: actor)
      {:ok, member} = Membership.create_member(@valid_member_attrs, actor: actor)

      {:ok, _updated_member} =
        Membership.update_member(member, %{user: %{id: user.id}}, actor: actor)

      # Load the relationship to test it
      {:ok, member_with_user} =
        Ash.get(Mv.Membership.Member, member.id, actor: actor, load: [:user])

      assert member_with_user.user.id == user.id
    end
  end

  describe "User-Member Relationship - Inverse Relationship Tests" do
    @valid_user_attrs %{
      email: "test2@example.com"
    }

    @valid_member_attrs %{
      first_name: "Bob",
      last_name: "Smith",
      email: "bob@example.com"
    }

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

    test "ash resolves inverse relationship automatically", %{actor: actor} do
      {:ok, member} = Membership.create_member(@valid_member_attrs, actor: actor)

      user_attrs = Map.put(@valid_user_attrs, :member, %{id: member.id})
      {:ok, user} = Accounts.create_user(user_attrs, actor: actor)

      # Load relationships
      {:ok, user_with_member} =
        Ash.get(Mv.Accounts.User, user.id, actor: actor, load: [:member])

      {:ok, member_with_user} =
        Ash.get(Mv.Membership.Member, member.id, actor: actor, load: [:user])

      assert user_with_member.member.id == member.id
      assert member_with_user.user.id == user.id
    end

    test "member can find associated user", %{actor: actor} do
      {:ok, member} = Membership.create_member(@valid_member_attrs, actor: actor)

      {:ok, user} =
        Accounts.create_user(%{email: "test3@example.com", member: %{id: member.id}},
          actor: actor
        )

      {:ok, member_with_user} =
        Ash.get(Mv.Membership.Member, member.id, actor: actor, load: [:user])

      assert member_with_user.user.id == user.id
    end
  end

  describe "User-Member Relationship - Preventing Duplicates" do
    @valid_user_attrs %{
      email: "test4@example.com"
    }

    @valid_member_attrs %{
      first_name: "Charlie",
      last_name: "Brown",
      email: "charlie@example.com"
    }

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

    test "prevents overwriting a member of already linked user on update", %{actor: actor} do
      {:ok, existing_member} = Membership.create_member(@valid_member_attrs, actor: actor)

      user_attrs = Map.put(@valid_user_attrs, :member, %{id: existing_member.id})
      {:ok, user} = Accounts.create_user(user_attrs, actor: actor)

      {:ok, member2} =
        Membership.create_member(
          %{
            first_name: "Dave",
            last_name: "Wilson",
            email: "dave@example.com"
          },
          actor: actor
        )

      assert {:error, %Ash.Error.Invalid{}} =
               Accounts.update_user(user, %{member: %{id: member2.id}}, actor: actor)
    end

    test "prevents linking user to already linked member on update", %{actor: actor} do
      {:ok, existing_user} = Accounts.create_user(@valid_user_attrs, actor: actor)
      {:ok, member} = Membership.create_member(@valid_member_attrs, actor: actor)

      {:ok, _updated_user} =
        Accounts.update_user(existing_user, %{member: %{id: member.id}}, actor: actor)

      {:ok, user2} = Accounts.create_user(%{email: "test5@example.com"}, actor: actor)

      assert {:error, %Ash.Error.Invalid{}} =
               Accounts.update_user(user2, %{member: %{id: member.id}}, actor: actor)
    end

    test "prevents linking member to already linked user on creation", %{actor: actor} do
      {:ok, existing_member} = Membership.create_member(@valid_member_attrs, actor: actor)

      user_attrs = Map.put(@valid_user_attrs, :member, %{id: existing_member.id})
      {:ok, user} = Accounts.create_user(user_attrs, actor: actor)

      assert {:error, %Ash.Error.Invalid{}} =
               Membership.create_member(
                 %{
                   first_name: "Dave",
                   last_name: "Wilson",
                   email: "dave@example.com",
                   user: %{id: user.id}
                 },
                 actor: actor
               )
    end

    test "prevents linking user to already linked member on creation", %{actor: actor} do
      {:ok, existing_user} = Accounts.create_user(@valid_user_attrs, actor: actor)
      {:ok, member} = Membership.create_member(@valid_member_attrs, actor: actor)

      {:ok, _updated_user} =
        Accounts.update_user(existing_user, %{member: %{id: member.id}}, actor: actor)

      assert {:error, %Ash.Error.Invalid{}} =
               Accounts.create_user(
                 %{
                   email: "test5@example.com",
                   member: %{id: member.id}
                 },
                 actor: actor
               )
    end
  end
end
