defmodule Mv.Membership.MemberEmailSyncTest do
  @moduledoc """
  Tests for email synchronization from Member to User.
  When a member and user are linked, email changes should sync bidirectionally.
  User.email is the source of truth when linking occurs.
  """
  use Mv.DataCase, async: false
  alias Mv.Accounts
  alias Mv.Membership

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

  describe "Member email synchronization to linked User" do
    @valid_user_attrs %{
      email: "user@example.com"
    }

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

    test "updating member email syncs to linked user", %{actor: actor} do
      # Create a user
      {:ok, user} = Accounts.create_user(@valid_user_attrs, actor: actor)
      assert to_string(user.email) == "user@example.com"

      # Create a member linked to the user
      {:ok, member} =
        Membership.create_member(Map.put(@valid_member_attrs, :user, %{id: user.id}),
          actor: actor
        )

      # Verify initial state - member email should be overridden by user email
      {:ok, member_after_create} = Ash.get(Mv.Membership.Member, member.id, actor: actor)
      assert member_after_create.email == "user@example.com"

      # Update member email
      {:ok, updated_member} =
        Membership.update_member(member, %{email: "newmember@example.com"}, actor: actor)

      assert updated_member.email == "newmember@example.com"

      # Verify user email was also updated
      {:ok, synced_user} = Ash.get(Mv.Accounts.User, user.id, actor: actor)
      assert to_string(synced_user.email) == "newmember@example.com"
    end

    test "creating member linked to user syncs user email to member", %{actor: actor} do
      # Create a user with their own email
      {:ok, user} = Accounts.create_user(@valid_user_attrs, actor: actor)
      assert to_string(user.email) == "user@example.com"

      # Create a member linked to this user
      {:ok, member} =
        Membership.create_member(Map.put(@valid_member_attrs, :user, %{id: user.id}),
          actor: actor
        )

      # Member should have been created with user's email (user is source of truth)
      assert member.email == "user@example.com"

      # Verify the link
      {:ok, loaded_member} = Ash.get(Mv.Membership.Member, member.id, load: [:user], actor: actor)
      assert loaded_member.user.id == user.id
    end

    test "linking member to existing user syncs user email to member", %{actor: actor} do
      # Create a standalone user
      {:ok, user} = Accounts.create_user(@valid_user_attrs, actor: actor)
      assert to_string(user.email) == "user@example.com"

      # Create a standalone member
      {:ok, member} = Membership.create_member(@valid_member_attrs, actor: actor)
      assert member.email == "member@example.com"

      # Link the member to the user
      {:ok, linked_member} =
        Membership.update_member(member, %{user: %{id: user.id}}, actor: actor)

      # Verify the link
      {:ok, loaded_member} =
        Ash.get(Mv.Membership.Member, linked_member.id, load: [:user], actor: actor)

      assert loaded_member.user.id == user.id

      # Verify member email was overridden with user email
      assert loaded_member.email == "user@example.com"
    end

    test "updating member email when no user linked does not error", %{actor: actor} do
      # Create a standalone member without user link
      {:ok, member} = Membership.create_member(@valid_member_attrs, actor: actor)
      assert member.email == "member@example.com"

      # Load to verify no user link
      {:ok, loaded_member} = Ash.get(Mv.Membership.Member, member.id, load: [:user], actor: actor)
      assert loaded_member.user == nil

      # Update member email - should work fine without error
      {:ok, updated_member} =
        Membership.update_member(member, %{email: "newemail@example.com"}, actor: actor)

      assert updated_member.email == "newemail@example.com"
    end

    test "unlinking member from user does not sync email", %{actor: actor} do
      # Create user
      {:ok, user} = Accounts.create_user(@valid_user_attrs, actor: actor)

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

      # Verify member email was synced to user email
      {:ok, synced_member} = Ash.get(Mv.Membership.Member, member.id, actor: actor)
      assert synced_member.email == "user@example.com"

      # Verify link exists
      {:ok, loaded_member} = Ash.get(Mv.Membership.Member, member.id, load: [:user], actor: actor)
      assert loaded_member.user != nil

      # Unlink member from user
      {:ok, unlinked_member} = Membership.update_member(member, %{user: nil}, actor: actor)

      # Verify unlink
      {:ok, loaded_unlinked} =
        Ash.get(Mv.Membership.Member, unlinked_member.id, load: [:user], actor: actor)

      assert loaded_unlinked.user == nil

      # User email should remain unchanged after unlinking
      {:ok, user_after_unlink} = Ash.get(Mv.Accounts.User, user.id, actor: actor)
      assert to_string(user_after_unlink.email) == "user@example.com"
    end
  end
end
