defmodule MvWeb.MemberFieldLive.FormComponent do
  @moduledoc """
  LiveComponent form for editing member field properties (embedded in settings).

  ## Features
  - Edit member field visibility (show_in_overview)
  - Display member field information from Member Resource (read-only)
  - Restrict editing for email field (only show_in_overview can be changed)
  - Real-time validation
  - Updates Settings.member_field_visibility atomically

  ## Props
  - `member_field` - The member field atom to edit (e.g., :first_name, :email)
  - `settings` - The current Settings resource
  - `on_save` - Callback function to call when form is saved
  - `on_cancel` - Callback function to call when form is cancelled

  ## Note
  Member fields are technical fields that cannot be changed (name, value_type, description, required).
  Only the visibility (show_in_overview) can be modified.
  """
  use MvWeb, :live_component

  alias Mv.Helpers.TypeParsers
  alias Mv.Membership
  alias Mv.Membership.Helpers.VisibilityConfig
  alias MvWeb.Helpers.FieldTypeFormatter
  alias MvWeb.Translations.MemberFields

  @required_fields [:first_name, :last_name, :email]

  @impl true
  def render(assigns) do
    assigns =
      assigns
      |> assign(:field_attributes, get_field_attributes(assigns.member_field))
      |> assign(:is_email_field?, assigns.member_field == :email)
      |> assign(:field_label, MemberFields.label(assigns.member_field))

    ~H"""
    <div id={@id} class="mb-8 border shadow-xl card border-base-300">
      <div class="card-body">
        <div class="flex items-center gap-4 mb-4">
          <.button
            type="button"
            phx-click="cancel"
            phx-target={@myself}
            aria-label={gettext("Back to Settings")}
          >
            <.icon name="hero-arrow-left" class="w-4 h-4" />
          </.button>
          <h3 class="card-title">
            {gettext("Edit Field: %{field}", field: @field_label)}
          </h3>
        </div>

        <.form
          for={@form}
          id={@id <> "-form"}
          phx-change="validate"
          phx-submit="save"
          phx-target={@myself}
        >
          <div
            class="tooltip tooltip-right"
            data-tip={gettext("This is a technical field and cannot be changed")}
            aria-label={gettext("This is a technical field and cannot be changed")}
          >
            <fieldset class="mb-2 fieldset">
              <label>
                <span class="mb-1 label flex items-center gap-2">
                  {gettext("Name")}
                  <.icon
                    name="hero-information-circle"
                    class="w-4 h-4 text-base-content/60 cursor-help"
                    aria-hidden="true"
                  />
                </span>
                <input
                  type="text"
                  name={@form[:name].name}
                  id={@form[:name].id}
                  value={@field_label}
                  disabled
                  readonly
                  class="w-full input"
                />
              </label>
            </fieldset>
          </div>

          <div
            class="tooltip tooltip-right"
            data-tip={gettext("This is a technical field and cannot be changed")}
            aria-label={gettext("This is a technical field and cannot be changed")}
          >
            <fieldset class="mb-2 fieldset">
              <label>
                <span class="mb-1 label flex items-center gap-2">
                  {gettext("Value type")}
                  <.icon
                    name="hero-information-circle"
                    class="w-4 h-4 text-base-content/60 cursor-help"
                    aria-hidden="true"
                  />
                </span>
                <input
                  type="text"
                  name={@form[:value_type].name}
                  id={@form[:value_type].id}
                  value={FieldTypeFormatter.format(@field_attributes.value_type)}
                  disabled
                  readonly
                  class="w-full input"
                />
              </label>
            </fieldset>
          </div>

          <div
            :if={@is_email_field?}
            class="tooltip tooltip-right"
            data-tip={gettext("This is a technical field and cannot be changed")}
            aria-label={gettext("This is a technical field and cannot be changed")}
          >
            <fieldset class="mb-2 fieldset">
              <label>
                <span class="mb-1 label flex items-center gap-2">
                  {gettext("Description")}
                  <.icon
                    name="hero-information-circle"
                    class="w-4 h-4 text-base-content/60 cursor-help"
                    aria-hidden="true"
                  />
                </span>
                <input
                  type="text"
                  name={@form[:description].name}
                  id={@form[:description].id}
                  value={@form[:description].value}
                  disabled
                  readonly
                  class="w-full input"
                />
              </label>
            </fieldset>
          </div>
          <.input
            :if={not @is_email_field?}
            field={@form[:description]}
            type="text"
            label={gettext("Description")}
            disabled={@is_email_field?}
            readonly={@is_email_field?}
          />

          <div
            :if={@is_email_field?}
            class="tooltip tooltip-right"
            data-tip={gettext("This is a technical field and cannot be changed")}
            aria-label={gettext("This is a technical field and cannot be changed")}
          >
            <fieldset class="mb-2 fieldset">
              <label>
                <input type="hidden" name={@form[:required].name} value="false" disabled />
                <span class="label flex items-center gap-2">
                  <input
                    type="checkbox"
                    name={@form[:required].name}
                    id={@form[:required].id}
                    value="true"
                    checked={@form[:required].value}
                    disabled
                    readonly
                    class="checkbox checkbox-sm"
                  />
                  <span class="flex items-center gap-2">
                    {gettext("Required")}
                    <.icon
                      name="hero-information-circle"
                      class="w-4 h-4 text-base-content/60 cursor-help"
                      aria-hidden="true"
                    />
                  </span>
                </span>
              </label>
            </fieldset>
          </div>
          <.input
            :if={not @is_email_field?}
            field={@form[:required]}
            type="checkbox"
            label={gettext("Required")}
            disabled={@is_email_field?}
            readonly={@is_email_field?}
          />

          <.input
            field={@form[:show_in_overview]}
            type="checkbox"
            label={gettext("Show in overview")}
          />

          <div class="justify-end mt-4 card-actions">
            <.button type="button" phx-click="cancel" phx-target={@myself}>
              {gettext("Cancel")}
            </.button>
            <.button phx-disable-with={gettext("Saving...")} variant="primary">
              {gettext("Save Field")}
            </.button>
          </div>
        </.form>
      </div>
    </div>
    """
  end

  @impl true
  def update(assigns, socket) do
    {:ok,
     socket
     |> assign(assigns)
     |> assign_form()}
  end

  @impl true
  def handle_event("validate", %{"member_field" => member_field_params}, socket) do
    # For member fields, we only validate show_in_overview
    # Other fields are read-only or derived from the Member Resource
    form = socket.assigns.form

    updated_params =
      member_field_params
      |> Map.put(
        "show_in_overview",
        TypeParsers.parse_boolean(member_field_params["show_in_overview"])
      )
      |> Map.put("name", form.source["name"])
      |> Map.put("value_type", form.source["value_type"])
      |> Map.put("description", form.source["description"])
      |> Map.put("required", form.source["required"])

    updated_form =
      form
      |> Map.put(:value, updated_params)
      |> Map.put(:errors, [])

    {:noreply, assign(socket, form: updated_form)}
  end

  @impl true
  def handle_event("save", %{"member_field" => member_field_params}, socket) do
    # Only show_in_overview can be changed for member fields
    show_in_overview = TypeParsers.parse_boolean(member_field_params["show_in_overview"])
    field_string = Atom.to_string(socket.assigns.member_field)

    # Use atomic action to update only this single field
    # This prevents lost updates in concurrent scenarios
    case Membership.update_single_member_field_visibility(
           socket.assigns.settings,
           field: field_string,
           show_in_overview: show_in_overview
         ) do
      {:ok, _updated_settings} ->
        socket.assigns.on_save.(socket.assigns.member_field, "update")
        {:noreply, socket}

      {:error, error} ->
        # Add error to form
        form =
          socket.assigns.form
          |> Map.put(:errors, [
            %{field: :show_in_overview, message: format_error(error)}
          ])

        {:noreply, assign(socket, form: form)}
    end
  end

  @impl true
  def handle_event("cancel", _params, socket) do
    socket.assigns.on_cancel.()
    {:noreply, socket}
  end

  # Helper functions

  defp assign_form(%{assigns: %{member_field: member_field, settings: settings}} = socket) do
    field_attributes = get_field_attributes(member_field)
    visibility_config = settings.member_field_visibility || %{}
    normalized_config = VisibilityConfig.normalize(visibility_config)
    show_in_overview = Map.get(normalized_config, member_field, true)

    # Create a manual form structure with string keys
    # Note: immutable is not included as it's not editable for member fields
    form_data = %{
      "name" => MemberFields.label(member_field),
      "value_type" => FieldTypeFormatter.format(field_attributes.value_type),
      "description" => field_attributes.description || "",
      "required" => field_attributes.required,
      "show_in_overview" => show_in_overview
    }

    form = to_form(form_data, as: "member_field")

    assign(socket, form: form)
  end

  defp get_field_attributes(field) when is_atom(field) do
    # Get attribute info from Member Resource
    alias Ash.Resource.Info

    case Info.attribute(Mv.Membership.Member, field) do
      nil ->
        # Fallback for fields not in resource (shouldn't happen with Constants)
        %{
          value_type: :string,
          description: nil,
          required: field in @required_fields
        }

      attribute ->
        %{
          value_type: attribute.type,
          description: nil,
          required: not attribute.allow_nil?
        }
    end
  end

  defp format_error(%Ash.Error.Invalid{} = error) do
    Ash.ErrorKind.message(error)
  end

  defp format_error(error) do
    inspect(error)
  end
end
