defmodule MvWeb.MembershipFeeTypeLive.Index do
  @moduledoc """
  LiveView for managing membership fee types (Admin).

  ## Features
  - List all membership fee types
  - Display: Name, Amount, Interval, Member count
  - Create new membership fee types
  - Edit existing membership fee types (name, amount, description - NOT interval)
  - Delete membership fee types (if no members assigned)

  ## Permissions
  - Admin only
  """
  use MvWeb, :live_view

  import MvWeb.LiveHelpers, only: [current_actor: 1]

  require Ash.Query

  alias Mv.Membership
  alias Mv.Membership.Member
  alias Mv.MembershipFees
  alias Mv.MembershipFees.MembershipFeeType
  alias MvWeb.Helpers.MembershipFeeHelpers

  @impl true
  def mount(_params, _session, socket) do
    actor = current_actor(socket)
    fee_types = load_membership_fee_types(actor)
    member_counts = load_member_counts(fee_types, actor)

    {:ok,
     socket
     |> assign(:page_title, gettext("Membership Fee Types"))
     |> assign(:membership_fee_types, fee_types)
     |> assign(:member_counts, member_counts)}
  end

  @impl true
  def render(assigns) do
    ~H"""
    <Layouts.app flash={@flash} current_user={@current_user}>
      <.header>
        {gettext("Membership Fee Types")}
        <:subtitle>
          {gettext("Manage membership fee types for membership fees.")}
        </:subtitle>
        <:actions>
          <.button variant="primary" navigate={~p"/membership_fee_types/new"}>
            <.icon name="hero-plus" /> {gettext("New Membership Fee Type")}
          </.button>
        </:actions>
      </.header>

      <.table
        id="membership_fee_types"
        rows={@membership_fee_types}
        row_id={fn mft -> "mft-#{mft.id}" end}
      >
        <:col :let={mft} label={gettext("Name")}>
          <span class="font-medium">{mft.name}</span>
          <p :if={mft.description} class="text-sm text-base-content/70">{mft.description}</p>
        </:col>

        <:col :let={mft} label={gettext("Amount")}>
          <span class="font-mono">{MembershipFeeHelpers.format_currency(mft.amount)}</span>
        </:col>

        <:col :let={mft} label={gettext("Interval")}>
          <span class="badge badge-outline">
            {MembershipFeeHelpers.format_interval(mft.interval)}
          </span>
        </:col>

        <:col :let={mft} label={gettext("Members")}>
          <span class="badge badge-ghost">{get_member_count(mft, @member_counts)}</span>
        </:col>

        <:action :let={mft}>
          <.link
            navigate={~p"/membership_fee_types/#{mft.id}/edit"}
            class="btn btn-ghost btn-xs"
            aria-label={gettext("Edit membership fee type")}
          >
            <.icon name="hero-pencil" class="size-4" />
          </.link>
        </:action>

        <:action :let={mft}>
          <div
            :if={get_member_count(mft, @member_counts) > 0}
            class="tooltip tooltip-left"
            data-tip={
              gettext("Cannot delete - %{count} member(s) assigned",
                count: get_member_count(mft, @member_counts)
              )
            }
          >
            <button
              phx-click="delete"
              phx-value-id={mft.id}
              data-confirm={gettext("Are you sure?")}
              class="btn btn-ghost btn-xs text-error opacity-50 cursor-not-allowed"
              aria-label={
                gettext("Cannot delete - %{count} member(s) assigned",
                  count: get_member_count(mft, @member_counts)
                )
              }
              disabled={true}
            >
              <.icon name="hero-trash" class="size-4" />
            </button>
          </div>
          <button
            :if={get_member_count(mft, @member_counts) == 0}
            phx-click="delete"
            phx-value-id={mft.id}
            data-confirm={gettext("Are you sure?")}
            class="btn btn-ghost btn-xs text-error"
            aria-label={gettext("Delete Membership Fee Type")}
          >
            <.icon name="hero-trash" class="size-4" />
          </button>
        </:action>
      </.table>

      <.info_card />
    </Layouts.app>
    """
  end

  @impl true
  def handle_event("delete", %{"id" => id}, socket) do
    actor = current_actor(socket)

    case Ash.get(MembershipFeeType, id, domain: MembershipFees, actor: actor) do
      {:ok, fee_type} ->
        case Ash.destroy(fee_type, domain: MembershipFees, actor: actor) do
          :ok ->
            updated_types = Enum.reject(socket.assigns.membership_fee_types, &(&1.id == id))
            updated_counts = Map.delete(socket.assigns.member_counts, id)

            {:noreply,
             socket
             |> assign(:membership_fee_types, updated_types)
             |> assign(:member_counts, updated_counts)
             |> put_flash(:info, gettext("Membership fee type deleted"))}

          {:error, %Ash.Error.Forbidden{}} ->
            {:noreply,
             put_flash(
               socket,
               :error,
               gettext("You do not have permission to delete this membership fee type")
             )}

          {:error, error} ->
            {:noreply, put_flash(socket, :error, format_error(error))}
        end

      {:error, %Ash.Error.Query.NotFound{}} ->
        {:noreply, put_flash(socket, :error, gettext("Membership fee type not found"))}

      {:error, %Ash.Error.Forbidden{} = _error} ->
        {:noreply,
         put_flash(
           socket,
           :error,
           gettext("You do not have permission to access this membership fee type")
         )}

      {:error, error} ->
        {:noreply, put_flash(socket, :error, format_error(error))}
    end
  end

  # Helper functions

  defp load_membership_fee_types(actor) do
    MembershipFeeType
    |> Ash.Query.sort(name: :asc)
    |> Ash.read!(domain: MembershipFees, actor: actor)
  end

  # Loads all member counts for fee types in a single query to avoid N+1 queries
  defp load_member_counts(fee_types, actor) do
    fee_type_ids = Enum.map(fee_types, & &1.id)

    # Load all members with membership_fee_type_id in a single query
    members =
      Member
      |> Ash.Query.filter(membership_fee_type_id in ^fee_type_ids)
      |> Ash.Query.select([:membership_fee_type_id])
      |> Ash.read!(domain: Membership, actor: actor)

    # Group by membership_fee_type_id and count
    members
    |> Enum.group_by(& &1.membership_fee_type_id)
    |> Enum.map(fn {fee_type_id, members_list} -> {fee_type_id, length(members_list)} end)
    |> Map.new()
  end

  # Gets member count from preloaded assigns map
  defp get_member_count(fee_type, member_counts) do
    Map.get(member_counts, fee_type.id, 0)
  end

  defp format_error(%Ash.Error.Invalid{} = error) do
    Enum.map_join(error.errors, ", ", fn e -> e.message end)
  end

  defp format_error(error) when is_binary(error), do: error
  defp format_error(_error), do: gettext("An error occurred")

  # Info card explaining the membership fee type concept
  defp info_card(assigns) do
    ~H"""
    <div class="card bg-base-200 mt-6">
      <div class="card-body">
        <h2 class="card-title">
          <.icon name="hero-information-circle" class="size-5" />
          {gettext("About Membership Fee Types")}
        </h2>
        <div class="prose prose-sm max-w-none">
          <p>
            {gettext(
              "Membership fee types define different membership fee structures. Each type has a fixed interval (monthly, quarterly, half-yearly, yearly) that cannot be changed after creation."
            )}
          </p>
          <ul>
            <li>
              <strong>{gettext("Name & Amount")}</strong>
              - {gettext("Can be changed at any time. Amount changes affect future periods only.")}
            </li>
            <li>
              <strong>{gettext("Interval")}</strong>
              - {gettext(
                "Fixed after creation. Members can only switch between types with the same interval."
              )}
            </li>
            <li>
              <strong>{gettext("Deletion")}</strong>
              - {gettext("Only possible if no members are assigned to this type.")}
            </li>
          </ul>
        </div>
      </div>
    </div>
    """
  end
end
