defmodule Mv.Membership.Member.Validations.EmailNotUsedByOtherUser do
  @moduledoc """
  Validates that the member's email is not already used by another user.
  Only validates when:
  - Member is already linked to a user (user != nil) AND email is changing
  - Member is being linked to a user (user relationship is changing)

  This allows creating members with the same email as unlinked users.
  """
  use Ash.Resource.Validation

  alias Mv.EmailSync.Loader
  alias Mv.Helpers

  require Logger

  @doc """
  Validates email uniqueness across linked Member-User pairs.

  This validation ensures that when a member is linked to a user, their email
  does not conflict with another user's email. It only runs when necessary
  to avoid blocking valid operations (see `@moduledoc` for trigger conditions).

  ## Parameters
  - `changeset` - The Ash changeset being validated
  - `_opts` - Options passed to the validation (unused)
  - `_context` - Ash context map (unused)

  ## Returns
  - `:ok` if validation passes or should be skipped
  - `{:error, field: :email, message: ..., value: ...}` if validation fails
  """
  @impl true
  def validate(changeset, _opts, _context) do
    email_changing? = Ash.Changeset.changing_attribute?(changeset, :email)

    linked_user = Loader.get_linked_user(changeset.data)
    linked_user_id = if linked_user, do: linked_user.id, else: nil
    is_linked? = not is_nil(linked_user_id)

    # Only validate if member is already linked AND email is changing
    # Do NOT validate when member is being linked (email will be overridden from user)
    should_validate? = is_linked? and email_changing?

    if should_validate? do
      new_email = Ash.Changeset.get_attribute(changeset, :email)
      check_email_uniqueness(new_email, linked_user_id)
    else
      :ok
    end
  end

  defp check_email_uniqueness(email, exclude_user_id) do
    alias Mv.Helpers.SystemActor

    query =
      Mv.Accounts.User
      |> Ash.Query.filter(email == ^email)
      |> Mv.Helpers.query_exclude_id(exclude_user_id)

    system_actor = SystemActor.get_system_actor()
    opts = Helpers.ash_actor_opts(system_actor)

    case Ash.read(query, opts) do
      {:ok, []} ->
        :ok

      {:ok, _} ->
        {:error, field: :email, message: "is already used by another user", value: email}

      {:error, reason} ->
        Logger.warning(
          "Email uniqueness validation query failed for member email '#{email}': #{inspect(reason)}. Allowing operation to proceed (fail-open)."
        )

        :ok
    end
  end
end
