defmodule MvWeb.CustomFieldLive.IndexComponent do
  @moduledoc """
  LiveComponent for managing custom field definitions (embedded in settings).

  ## Features
  - List all custom fields
  - Display type information (name, value type, description)
  - Show required flag
  - Create new custom fields
  - Edit existing custom fields
  - Delete custom fields with confirmation (cascades to all custom field values)
  """
  use MvWeb, :live_component

  require Logger

  @impl true
  def render(assigns) do
    assigns = assign(assigns, :field_type_label, &MvWeb.Translations.FieldTypes.label/1)

    ~H"""
    <div id={@id} class="mt-8">
      <div class="flex">
        <p class="text-sm text-base-content/70">
          {gettext("These will appear in addition to other data when adding new members.")}
        </p>
        <div class="ml-auto">
          <.button
            class="ml-auto"
            variant="primary"
            phx-click="new_custom_field"
            phx-target={@myself}
          >
            <.icon name="hero-plus" /> {gettext("New Data Field")}
          </.button>
        </div>
      </div>
      <%!-- Show form when creating or editing --%>
      <div :if={@show_form} class="mb-8">
        <.live_component
          module={MvWeb.CustomFieldLive.FormComponent}
          id={@form_id}
          actor={@actor}
          custom_field={@editing_custom_field}
          on_save={
            fn custom_field, action -> send(self(), {:custom_field_saved, custom_field, action}) end
          }
          on_cancel={fn -> send_update(__MODULE__, id: @id, show_form: false) end}
        />
      </div>

      <%!-- Hide table when form is visible --%>
      <div :if={!@show_form} id="custom_fields">
        <.table
          id="custom_fields_table"
          rows={@streams.custom_fields}
          row_click={
            fn {_id, custom_field} ->
              JS.push("edit_custom_field", value: %{id: custom_field.id}, target: @myself)
            end
          }
          row_tooltip={gettext("Click to edit datafield")}
        >
          <:col :let={{_id, custom_field}} label={gettext("Name")}>{custom_field.name}</:col>

          <:col :let={{_id, custom_field}} label={gettext("Value Type")}>
            {@field_type_label.(custom_field.value_type)}
          </:col>

          <:col :let={{_id, custom_field}} label={gettext("Description")}>
            {custom_field.description}
          </:col>

          <:col
            :let={{_id, custom_field}}
            label={gettext("Required")}
            class="max-w-[9.375rem] text-center"
          >
            <span :if={custom_field.required} class="text-base-content font-semibold">
              {gettext("Required")}
            </span>
            <span :if={!custom_field.required} class="text-base-content/70">
              {gettext("Optional")}
            </span>
          </:col>

          <:col
            :let={{_id, custom_field}}
            label={gettext("Show in overview")}
            class="max-w-[9.375rem] text-center"
          >
            <.badge :if={custom_field.show_in_overview} variant="success">
              {gettext("Yes")}
            </.badge>
            <.badge :if={!custom_field.show_in_overview} variant="neutral">
              {gettext("No")}
            </.badge>
          </:col>
        </.table>
      </div>

      <%!-- Delete Confirmation Modal --%>
      <dialog :if={@show_delete_modal} id="delete-custom-field-modal" class="modal modal-open">
        <div class="modal-box">
          <h3 class="text-lg font-bold">{gettext("Delete Data Field")}</h3>

          <div class="py-4 space-y-4">
            <div class="alert alert-warning">
              <.icon name="hero-exclamation-triangle" class="w-5 h-5" />
              <div>
                <p class="font-semibold">
                  {ngettext(
                    "%{count} member has a value assigned for this custom field.",
                    "%{count} members have values assigned for this custom field.",
                    @custom_field_to_delete.assigned_members_count,
                    count: @custom_field_to_delete.assigned_members_count
                  )}
                </p>
                <p class="mt-2 text-sm">
                  {gettext(
                    "All custom field values will be permanently deleted when you delete this custom field."
                  )}
                </p>
              </div>
            </div>

            <div>
              <label for="slug-confirmation" class="label">
                <span class="label-text">
                  {gettext("To confirm deletion, please enter this text:")}
                </span>
              </label>
              <div class="p-2 mb-2 font-mono text-lg font-bold break-all rounded bg-base-200">
                {@custom_field_to_delete.slug}
              </div>
              <form phx-change="update_slug_confirmation" phx-target={@myself}>
                <input
                  id="slug-confirmation"
                  name="slug"
                  type="text"
                  value={@slug_confirmation}
                  placeholder={gettext("Enter the text above to confirm")}
                  autocomplete="off"
                  phx-mounted={JS.focus()}
                  class="w-full input input-bordered"
                />
              </form>
            </div>
          </div>

          <div class="modal-action">
            <.button variant="neutral" phx-click="cancel_delete" phx-target={@myself}>
              {gettext("Cancel")}
            </.button>
            <.button
              variant="danger"
              phx-click="confirm_delete"
              phx-target={@myself}
              disabled={@slug_confirmation != @custom_field_to_delete.slug}
            >
              {gettext("Delete Datafields and All Values")}
            </.button>
          </div>
        </div>
      </dialog>
    </div>
    """
  end

  defp stream_custom_fields(actor, parent_pid) do
    case Ash.read(Mv.Membership.CustomField, actor: actor) do
      {:ok, custom_fields} ->
        custom_fields

      {:error, error} ->
        Logger.warning(
          "CustomFieldLive.IndexComponent: failed to load custom fields: #{inspect(error)}"
        )

        send(parent_pid, {:custom_fields_load_error, error})
        []
    end
  end

  @impl true
  def update(assigns, socket) do
    # Track previous show_form state to detect when form is closed
    previous_show_form = Map.get(socket.assigns, :show_form, false)

    # If show_form is explicitly provided in assigns, reset editing state
    socket =
      if Map.has_key?(assigns, :show_form) and assigns.show_form == false do
        socket
        |> assign(:editing_custom_field, nil)
        |> assign(:form_id, "custom-field-form-new")
      else
        socket
      end

    # Detect when form is closed (show_form changes from true to false)
    new_show_form = Map.get(assigns, :show_form, false)

    if previous_show_form and not new_show_form do
      send(self(), {:editing_section_changed, nil})
    end

    # Get actor from assigns or fall back to socket assigns
    actor = Map.get(assigns, :actor, socket.assigns[:actor])

    socket =
      socket
      |> assign(assigns)
      |> assign_new(:show_form, fn -> false end)
      |> assign_new(:form_id, fn -> "custom-field-form-new" end)
      |> assign_new(:editing_custom_field, fn -> nil end)
      |> assign_new(:show_delete_modal, fn -> false end)
      |> assign_new(:custom_field_to_delete, fn -> nil end)
      |> assign_new(:slug_confirmation, fn -> "" end)
      |> stream(:custom_fields, stream_custom_fields(actor, self()), reset: true)

    # Open delete modal when requested from form (e.g. Danger zone in FormComponent)
    socket =
      case Map.get(assigns, :open_delete_for_id) do
        nil ->
          socket

        id ->
          custom_field =
            Ash.get!(Mv.Membership.CustomField, id,
              load: [:assigned_members_count],
              actor: actor
            )

          socket
          |> assign(:show_delete_modal, true)
          |> assign(:custom_field_to_delete, custom_field)
          |> assign(:slug_confirmation, "")
          |> assign(:open_delete_for_id, nil)
      end

    {:ok, socket}
  end

  @impl true
  def handle_event("new_custom_field", _params, socket) do
    # Only send event if form was not already open
    if not socket.assigns[:show_form] do
      send(self(), {:editing_section_changed, :custom_fields})
    end

    {:noreply,
     socket
     |> assign(:show_form, true)
     |> assign(:editing_custom_field, nil)
     |> assign(:form_id, "custom-field-form-new")}
  end

  @impl true
  def handle_event("edit_custom_field", %{"id" => id}, socket) do
    actor = socket.assigns[:actor]
    custom_field = Ash.get!(Mv.Membership.CustomField, id, actor: actor)

    # Only send event if form was not already open
    if not socket.assigns[:show_form] do
      send(self(), {:editing_section_changed, :custom_fields})
    end

    {:noreply,
     socket
     |> assign(:show_form, true)
     |> assign(:editing_custom_field, custom_field)
     |> assign(:form_id, "custom-field-form-#{id}")}
  end

  @impl true
  def handle_event("prepare_delete", %{"id" => id}, socket) do
    actor = socket.assigns[:actor]

    custom_field =
      Ash.get!(Mv.Membership.CustomField, id,
        load: [:assigned_members_count],
        actor: actor
      )

    {:noreply,
     socket
     |> assign(:custom_field_to_delete, custom_field)
     |> assign(:show_delete_modal, true)
     |> assign(:slug_confirmation, "")}
  end

  @impl true
  def handle_event("update_slug_confirmation", %{"slug" => slug}, socket) do
    {:noreply, assign(socket, :slug_confirmation, slug)}
  end

  @impl true
  def handle_event("confirm_delete", _params, socket) do
    custom_field = socket.assigns.custom_field_to_delete
    actor = socket.assigns[:actor]

    if socket.assigns.slug_confirmation == custom_field.slug do
      case Ash.destroy(custom_field, actor: actor) do
        :ok ->
          send(self(), {:custom_field_deleted, custom_field})

          {:noreply,
           socket
           |> assign(:show_delete_modal, false)
           |> assign(:custom_field_to_delete, nil)
           |> assign(:slug_confirmation, "")
           |> stream_delete(:custom_fields, custom_field)}

        {:error, error} ->
          send(self(), {:custom_field_delete_error, error})

          {:noreply,
           socket
           |> assign(:show_delete_modal, false)
           |> assign(:custom_field_to_delete, nil)
           |> assign(:slug_confirmation, "")}
      end
    else
      send(self(), :custom_field_slug_mismatch)

      {:noreply,
       socket
       |> assign(:show_delete_modal, false)
       |> assign(:custom_field_to_delete, nil)
       |> assign(:slug_confirmation, "")}
    end
  end

  @impl true
  def handle_event("cancel_delete", _params, socket) do
    {:noreply,
     socket
     |> assign(:show_delete_modal, false)
     |> assign(:custom_field_to_delete, nil)
     |> assign(:slug_confirmation, "")}
  end
end
