defmodule MvWeb.GroupLive.Form do
  @moduledoc """
  LiveView form for creating and editing groups.

  ## Features
  - Create new groups with name and description
  - Edit existing group details (name and description)
  - Slug is automatically generated and immutable
  - Form validation with visual feedback

  ## Security
  - Only admin users can create/edit groups
  - Non-admin users are redirected
  """
  use MvWeb, :live_view

  import MvWeb.LiveHelpers, only: [current_actor: 1, submit_form: 3]
  import MvWeb.Authorization

  alias Mv.Membership

  @impl true
  def mount(params, _session, socket) do
    actor = current_actor(socket)

    # Check authorization based on whether we are creating or updating
    action = if params["slug"], do: :update, else: :create
    resource = Mv.Membership.Group

    if can?(actor, action, resource) do
      {:ok,
       socket
       |> assign(:actor, actor)
       |> assign(:group, nil)
       |> assign(:page_title, page_title_for_params(params))
       |> assign(:return_to, return_to_for_params(params))}
    else
      {:ok, redirect(socket, to: ~p"/groups")}
    end
  end

  @impl true
  def handle_params(params, _url, socket) do
    actor = socket.assigns.actor

    case params do
      %{"slug" => slug} when is_binary(slug) ->
        case Membership.get_group_by_slug(slug, actor: actor, load: []) do
          {:ok, nil} ->
            {:noreply,
             socket
             |> put_flash(:error, gettext("Group not found."))
             |> redirect(to: ~p"/groups")}

          {:ok, group} ->
            {:noreply,
             socket
             |> assign(:group, group)
             |> assign(:page_title, gettext("Edit Group"))
             |> assign(:return_to, :show)
             |> assign_form(actor)}

          {:error, _error} ->
            {:noreply,
             socket
             |> put_flash(:error, gettext("Failed to load group."))
             |> redirect(to: ~p"/groups")}
        end

      _ ->
        # New group - ensure form is initialized for create
        {:noreply, assign_form(socket, actor)}
    end
  end

  @impl true
  def render(assigns) do
    ~H"""
    <Layouts.app flash={@flash} current_user={@current_user}>
      <.form for={@form} id="group-form" phx-change="validate" phx-submit="save">
        <.header>
          <:leading>
            <.button navigate={return_path(@return_to, @group)} variant="neutral">
              <.icon name="hero-arrow-left" class="size-4" />
              {gettext("Back")}
            </.button>
          </:leading>
          {@page_title}
          <:actions>
            <.button phx-disable-with={gettext("Saving...")} variant="primary" type="submit">
              {gettext("Save")}
            </.button>
          </:actions>
        </.header>

        <div class="mt-6 space-y-6">
          <div class="max-w-2xl space-y-4">
            <.input field={@form[:name]} label={gettext("Name")} required />
            <.input
              field={@form[:description]}
              type="textarea"
              label={gettext("Description")}
              rows="4"
            />
          </div>

          <%!-- Danger zone: canonical pattern (same as member form) --%>
          <%= if @group && can?(@current_user, :destroy, @group) do %>
            <section class="mt-8 mb-6" aria-labelledby="danger-zone-heading">
              <h2 id="danger-zone-heading" class="text-lg font-semibold mb-3 text-error">
                {gettext("Danger zone")}
              </h2>
              <div class="border border-base-300 rounded-lg p-4 bg-base-100">
                <p class="text-base-content/70 mb-4">
                  {gettext(
                    "Deleting this group cannot be undone. All member-group associations will be permanently removed."
                  )}
                </p>
                <.button
                  variant="danger"
                  navigate={~p"/groups/#{@group.slug}?confirm_delete=1"}
                  data-testid="group-form-delete-btn"
                  aria-label={gettext("Delete group %{name}", name: @group.name)}
                >
                  <.icon name="hero-trash" class="size-4" />
                  {gettext("Delete group")}
                </.button>
              </div>
            </section>
          <% end %>
        </div>
      </.form>
    </Layouts.app>
    """
  end

  @impl true
  def handle_event("validate", %{"group" => group_params}, socket) do
    validated_form = AshPhoenix.Form.validate(socket.assigns.form, group_params)
    {:noreply, assign(socket, form: validated_form)}
  end

  def handle_event("save", %{"group" => group_params}, socket) do
    actor = socket.assigns.actor

    case submit_form(socket.assigns.form, group_params, actor) do
      {:ok, group} ->
        notify_parent({:saved, group})

        redirect_path =
          case socket.assigns.return_to do
            :show -> ~p"/groups/#{group.slug}"
            _ -> ~p"/groups"
          end

        socket =
          socket
          |> put_flash(:success, gettext("Group saved successfully."))
          |> push_navigate(to: redirect_path)

        {:noreply, socket}

      {:error, form} ->
        {:noreply, assign(socket, form: form)}
    end
  end

  defp notify_parent(msg), do: send(self(), {__MODULE__, msg})

  defp assign_form(%{assigns: assigns} = socket, actor) do
    group = Map.get(assigns, :group)

    form =
      if group do
        AshPhoenix.Form.for_update(
          group,
          :update,
          api: Membership,
          as: "group",
          actor: actor
        )
      else
        AshPhoenix.Form.for_create(
          Mv.Membership.Group,
          :create,
          api: Membership,
          as: "group",
          actor: actor
        )
      end

    assign(socket, form: to_form(form))
  end

  defp page_title_for_params(%{"slug" => _slug}), do: gettext("Edit Group")
  defp page_title_for_params(_params), do: gettext("Create Group")

  defp return_to_for_params(%{"slug" => _slug}), do: :show
  defp return_to_for_params(_params), do: :index

  defp return_path(:index, _group), do: ~p"/groups"

  defp return_path(:show, group) when not is_nil(group), do: ~p"/groups/#{group.slug}"

  defp return_path(:show, _group), do: ~p"/groups"

  defp return_path(_, group) when not is_nil(group), do: ~p"/groups/#{group.slug}"

  defp return_path(_, _group), do: ~p"/groups"
end
