defmodule MvWeb.MembershipFeeSettingsLive do
  @moduledoc """
  LiveView for membership fee settings and fee types (Admin).

  Combines:
  - Global settings (default fee type, include joining cycle)
  - Membership fee types table (CRUD links to new/edit routes; delete inline)
  Examples and info are collapsible to save space.
  """
  use MvWeb, :live_view

  require Ash.Query

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

  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)
    {:ok, settings} = Membership.get_settings()

    membership_fee_types =
      MembershipFeeType
      |> Ash.Query.sort(name: :asc)
      |> Ash.read!(domain: Mv.MembershipFees, actor: actor)

    member_counts = load_member_counts(membership_fee_types, actor)

    {:ok,
     socket
     |> assign(:page_title, gettext("Membership Fee Settings"))
     |> assign(:settings, settings)
     |> assign(:membership_fee_types, membership_fee_types)
     |> assign(:member_counts, member_counts)
     |> assign_form()}
  end

  @impl true
  def handle_event("validate", %{"settings" => params}, socket) do
    # Normalize checkbox value: "on" -> true, missing -> false
    normalized_params =
      if Map.has_key?(params, "include_joining_cycle") do
        params
        |> Map.update("include_joining_cycle", false, fn
          "on" -> true
          "true" -> true
          true -> true
          _ -> false
        end)
      else
        Map.put(params, "include_joining_cycle", false)
      end

    {:noreply,
     assign(socket, form: AshPhoenix.Form.validate(socket.assigns.form, normalized_params))}
  end

  def handle_event("save", %{"settings" => params}, socket) do
    # Normalize checkbox value: "on" -> true, missing -> false
    normalized_params =
      if Map.has_key?(params, "include_joining_cycle") do
        params
        |> Map.update("include_joining_cycle", false, fn
          "on" -> true
          "true" -> true
          true -> true
          _ -> false
        end)
      else
        Map.put(params, "include_joining_cycle", false)
      end

    actor = MvWeb.LiveHelpers.current_actor(socket)

    case MvWeb.LiveHelpers.submit_form(socket.assigns.form, normalized_params, actor) do
      {:ok, updated_settings} ->
        {:noreply,
         socket
         |> assign(:settings, updated_settings)
         |> put_flash(:success, gettext("Settings saved successfully."))
         |> assign_form()}

      {:error, form} ->
        {:noreply, assign(socket, form: form)}
    end
  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(:success, 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{}} ->
        {: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

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

      <div class="grid gap-6 lg:grid-cols-2">
        <%!-- Settings Form --%>
        <div class="card bg-base-100 shadow-xl">
          <div class="card-body">
            <h2 class="card-title">
              <.icon name="hero-cog-6-tooth" class="size-5" />
              {gettext("Global Settings")}
            </h2>

            <.form
              for={@form}
              phx-change="validate"
              phx-submit="save"
              class="space-y-6"
            >
              <%!-- Default Membership Fee Type --%>
              <fieldset class="fieldset">
                <label for="default_membership_fee_type_id" class="label">
                  <span class="label-text font-semibold">
                    {gettext("Default Membership Fee Type")}
                  </span>
                </label>
                <select
                  id="default_membership_fee_type_id"
                  name="settings[default_membership_fee_type_id]"
                  class={[
                    "select select-bordered",
                    if(@form.errors[:default_membership_fee_type_id], do: "select-error", else: "")
                  ]}
                  phx-debounce="blur"
                  aria-label={gettext("Default Membership Fee Type")}
                >
                  <option value="">{gettext("None (no default)")}</option>
                  <option
                    :for={fee_type <- @membership_fee_types}
                    value={fee_type.id}
                    selected={fee_type.id == @form[:default_membership_fee_type_id].value}
                  >
                    {fee_type.name} ({format_currency(fee_type.amount)}, {format_interval(
                      fee_type.interval
                    )})
                  </option>
                </select>
                <%= if @form.errors[:default_membership_fee_type_id] do %>
                  <%= for error <- List.wrap(@form.errors[:default_membership_fee_type_id]) do %>
                    <% {msg, _opts} = if is_tuple(error), do: error, else: {error, []} %>
                    <p class="text-error text-sm mt-1">{msg}</p>
                  <% end %>
                <% end %>
                <p class="text-sm text-base-content/60 mt-2">
                  {gettext(
                    "This membership fee type is automatically assigned to all new members. Can be changed individually per member."
                  )}
                </p>
              </fieldset>

              <%!-- Include Joining Cycle --%>
              <fieldset class="fieldset">
                <label class="label cursor-pointer justify-start gap-3">
                  <input
                    type="checkbox"
                    name="settings[include_joining_cycle]"
                    class="checkbox checkbox-primary"
                    checked={@form[:include_joining_cycle].value}
                    phx-debounce="blur"
                  />
                  <span class="label-text font-semibold">
                    {gettext("Include joining cycle")}
                  </span>
                </label>
                <%= if @form.errors[:include_joining_cycle] do %>
                  <%= for error <- List.wrap(@form.errors[:include_joining_cycle]) do %>
                    <% {msg, _opts} = if is_tuple(error), do: error, else: {error, []} %>
                    <p class="text-error text-sm ml-9 mt-1">{msg}</p>
                  <% end %>
                <% end %>
                <div class="ml-9 space-y-2">
                  <p class="text-sm text-base-content/60">
                    {gettext("When active: Members pay from the cycle of their joining.")}
                  </p>
                  <p class="text-sm text-base-content/60">
                    {gettext("When inactive: Members pay from the next full cycle after joining.")}
                  </p>
                </div>
              </fieldset>

              <div class="divider"></div>

              <.button type="submit" variant="primary" class="w-full">
                <.icon name="hero-check" class="size-5" />
                {gettext("Save Settings")}
              </.button>
            </.form>
          </div>
        </div>

        <%!-- Examples Card (collapsible) --%>
        <div class="card bg-base-200">
          <div class="card-body">
            <details class="group">
              <summary class="card-title cursor-pointer list-none flex items-center gap-2">
                <.icon name="hero-chevron-right" class="size-5 transition group-open:rotate-90" />
                <.icon name="hero-light-bulb" class="size-5" />
                {gettext("Examples")}
              </summary>

              <div class="pt-4 space-y-4">
                <.example_section
                  title={gettext("Yearly Interval - Joining Cycle Included")}
                  joining_date="15.03.2023"
                  include_joining={true}
                  start_date="01.01.2023"
                  periods={["2023", "2024", "2025"]}
                  note={gettext("Member pays for the year they joined")}
                />

                <div class="divider"></div>

                <.example_section
                  title={gettext("Yearly Interval - Joining Cycle Excluded")}
                  joining_date="15.03.2023"
                  include_joining={false}
                  start_date="01.01.2024"
                  periods={["2024", "2025"]}
                  note={gettext("Member pays from the next full year")}
                />

                <div class="divider"></div>

                <.example_section
                  title={gettext("Quarterly Interval - Joining Cycle Excluded")}
                  joining_date="15.05.2024"
                  include_joining={false}
                  start_date="01.07.2024"
                  periods={["Q3/2024", "Q4/2024", "Q1/2025"]}
                  note={gettext("Member pays from the next full quarter")}
                />

                <div class="divider"></div>

                <.example_section
                  title={gettext("Monthly Interval - Joining Cycle Included")}
                  joining_date="15.03.2024"
                  include_joining={true}
                  start_date="01.03.2024"
                  periods={["03/2024", "04/2024", "05/2024", "..."]}
                  note={gettext("Member pays from the joining month")}
                />
              </div>
            </details>
          </div>
        </div>
      </div>

      <%!-- Fee Types Table --%>
      <div class="mt-8">
        <h2 class="text-lg font-semibold mb-4">{gettext("Membership Fee Types")}</h2>
        <.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")}>
            <.badge variant="neutral" style="outline">
              {MembershipFeeHelpers.format_interval(mft.interval)}
            </.badge>
          </:col>

          <:col :let={mft} label={gettext("Members")}>
            <.badge variant="neutral">{get_member_count(mft, @member_counts)}</.badge>
          </:col>

          <:action :let={mft}>
            <.tooltip content={gettext("Edit membership fee type")} position="left">
              <.button
                variant="ghost"
                size="sm"
                navigate={~p"/membership_fee_settings/#{mft.id}/edit_fee_type"}
                aria-label={gettext("Edit membership fee type")}
              >
                <.icon name="hero-pencil" class="size-4" />
              </.button>
            </.tooltip>
          </:action>

          <:action :let={mft}>
            <.tooltip
              :if={get_member_count(mft, @member_counts) > 0}
              content={
                gettext("Cannot delete - %{count} member(s) assigned",
                  count: get_member_count(mft, @member_counts)
                )
              }
              position="left"
            >
              <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>
            </.tooltip>
            <.button
              :if={get_member_count(mft, @member_counts) == 0}
              variant="danger"
              size="sm"
              phx-click="delete"
              phx-value-id={mft.id}
              data-confirm={gettext("Are you sure?")}
              aria-label={gettext("Delete Membership Fee Type")}
            >
              <.icon name="hero-trash" class="size-4" />
            </.button>
          </:action>
        </.table>

        <details class="mt-6 card bg-base-200">
          <summary class="card-body cursor-pointer list-none card-title">
            <.icon name="hero-information-circle" class="size-5" />
            {gettext("About Membership Fee Types")}
          </summary>
          <div class="card-body pt-0 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>
        </details>
      </div>
    </Layouts.app>
    """
  end

  # Example section component
  attr :title, :string, required: true
  attr :joining_date, :string, required: true
  attr :include_joining, :boolean, required: true
  attr :start_date, :string, required: true
  attr :periods, :list, required: true
  attr :note, :string, required: true

  defp example_section(assigns) do
    ~H"""
    <div class="space-y-2">
      <h3 class="font-semibold text-sm">{@title}</h3>
      <div class="bg-base-300 rounded-lg p-3 text-sm space-y-1">
        <p>
          <span class="text-base-content/80">{gettext("Joining date")}:</span>
          <span class="font-mono">{@joining_date}</span>
        </p>
        <p>
          <span class="text-base-content/80">{gettext("Membership fee start")}:</span>
          <span class="font-mono font-semibold text-base-content">{@start_date}</span>
        </p>
        <p>
          <span class="text-base-content/80">{gettext("Generated cycles")}:</span>
          <span class="font-mono">
            {Enum.join(@periods, ", ")}
          </span>
        </p>
      </div>
      <p class="text-xs text-base-content/80 italic">→ {@note}</p>
    </div>
    """
  end

  defp format_currency(%Decimal{} = amount) do
    "#{Decimal.to_string(amount)} €"
  end

  defp format_interval(:monthly), do: gettext("Monthly")
  defp format_interval(:quarterly), do: gettext("Quarterly")
  defp format_interval(:half_yearly), do: gettext("Half-yearly")
  defp format_interval(:yearly), do: gettext("Yearly")

  defp load_member_counts(fee_types, actor) do
    fee_type_ids = Enum.map(fee_types, & &1.id)

    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)

    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

  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")

  defp assign_form(%{assigns: %{settings: settings}} = socket) do
    form =
      AshPhoenix.Form.for_update(
        settings,
        :update_membership_fee_settings,
        api: Membership,
        as: "settings",
        forms: [auto?: true]
      )

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