defmodule WhoNeedHelpWeb.CategoryProposalLive do
  use WhoNeedHelpWeb, :live_view

  alias WhoNeedHelp.Catalog
  alias WhoNeedHelp.Catalog.CategoryProposal

  @impl true
  def mount(_params, _session, socket) do
    {:ok, load(socket)}
  end

  @impl true
  def handle_event("propose", %{"category_proposal" => params}, socket) do
    case Catalog.propose(socket.assigns.current_scope, params) do
      {:ok, _} ->
        {:noreply,
         socket
         |> put_flash(:info, gettext("Proposal published for community voting."))
         |> load()
         |> push_event("reset-message-form", %{id: "category-proposal-form"})}

      {:error, %Ecto.Changeset{} = changeset} ->
        {:noreply, assign(socket, :form, to_form(changeset))}

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

  def handle_event("vote", %{"id" => id}, socket) do
    case Catalog.vote(socket.assigns.current_scope, id) do
      {:ok, _} -> {:noreply, load(socket)}
      {:error, reason} -> {:noreply, put_flash(socket, :error, action_error(reason))}
    end
  end

  def handle_event("load-more-proposals", _params, socket) do
    page = Catalog.paginate_proposals(after: socket.assigns.proposals_cursor)
    existing_ids = MapSet.new(socket.assigns.proposals, & &1.id)

    {:noreply,
     socket
     |> assign(
       :proposals,
       socket.assigns.proposals ++
         Enum.reject(page.entries, &MapSet.member?(existing_ids, &1.id))
     )
     |> assign(:proposals_cursor, page.next_cursor)}
  end

  defp action_error(:account_not_eligible),
    do: gettext("Confirm your account and ensure it is active first.")

  defp action_error(:rate_limited),
    do: gettext("Too many actions in the configured time window.")

  defp action_error(:proposal_closed), do: gettext("This proposal is already closed.")
  defp action_error(:not_found), do: gettext("This proposal is no longer available.")
  defp action_error(%Ecto.Changeset{}), do: gettext("You already voted for this proposal.")

  defp action_error(_reason), do: gettext("Could not complete the action. Please try again.")

  defp load(socket) do
    proposals = Catalog.paginate_proposals()

    socket
    |> assign(:page_title, gettext("Category proposals"))
    |> assign(:proposals, proposals.entries)
    |> assign(:proposals_cursor, proposals.next_cursor)
    |> assign(:categories, Catalog.list_all_categories())
    |> assign(:form, to_form(Catalog.change_proposal(%CategoryProposal{})))
  end

  @impl true
  def render(assigns) do
    ~H"""
    <Layouts.app flash={@flash} current_scope={@current_scope}>
      <div class="grid gap-8 lg:grid-cols-[.8fr_1.2fr]">
        <section>
          <div class="text-sm font-semibold text-success">
            {gettext("COMMUNITY-DRIVEN TAXONOMY")}
          </div>
          <h1 class="mt-2 text-4xl font-black">
            {gettext("What help category is missing?")}
          </h1>
          <p class="mt-3 text-base-content/65">
            {gettext("Proposals and votes guide moderators. Approval remains a human decision.")}
          </p>
          <.form
            for={@form}
            id="category-proposal-form"
            phx-submit="propose"
            class="mt-7 space-y-4 rounded-3xl bg-base-200 p-6"
          >
            <.input
              field={@form[:proposed_name]}
              label={gettext("Proposed category")}
              placeholder={gettext("Bicycle puncture")}
            />
            <.input
              field={@form[:mode]}
              type="select"
              label={gettext("Mode")}
              options={[
                {gettext("Urgent help"), "help"},
                {gettext("Social activity"), "activity"}
              ]}
            />
            <.input
              field={@form[:parent_id]}
              type="select"
              label={gettext("Parent (optional)")}
              prompt={gettext("Top level")}
              options={
                Enum.map(
                  @categories,
                  &{WhoNeedHelp.Catalog.Category.name(
                     &1,
                     Gettext.get_locale(WhoNeedHelpWeb.Gettext)
                   ), &1.id}
                )
              }
            />
            <.input
              field={@form[:reason]}
              type="textarea"
              label={gettext("Why is this useful?")}
            />
            <.button class="btn btn-primary w-full">{gettext("Publish proposal")}</.button>
          </.form>
        </section>

        <section>
          <h2 class="text-2xl font-bold">{gettext("Open proposals")}</h2>
          <div class="mt-5 space-y-3">
            <div
              :if={@proposals == []}
              class="rounded-2xl border border-dashed p-8 text-center text-base-content/55"
            >
              {gettext("No proposals yet.")}
            </div>
            <article :for={proposal <- @proposals} class="rounded-2xl border border-base-300 p-5">
              <div class="flex items-start justify-between gap-4">
                <div>
                  <h3 class="text-lg font-bold">{proposal.proposed_name}</h3>
                  <span class="badge badge-sm badge-outline">
                    {if proposal.mode == :help,
                      do: gettext("Urgent help"),
                      else: gettext("Social activity")}
                  </span>
                  <p class="mt-2 text-sm text-base-content/65">{proposal.reason}</p>
                  <p class="mt-3 text-xs text-base-content/45">
                    {gettext("by %{name}", name: proposal.proposer.display_name)}
                  </p>
                </div>
                <button phx-click="vote" phx-value-id={proposal.id} class="btn btn-outline btn-sm">
                  ▲ {proposal.vote_count}
                </button>
              </div>
            </article>
          </div>
          <button
            :if={@proposals_cursor}
            type="button"
            phx-click="load-more-proposals"
            class="btn btn-outline btn-sm mt-4"
          >
            {gettext("Load more")}
          </button>
        </section>
      </div>
    </Layouts.app>
    """
  end
end
