defmodule WhoNeedHelpWeb.SupportController do
  use WhoNeedHelpWeb, :controller

  alias WhoNeedHelp.Support
  alias WhoNeedHelp.Support.SupportRequest

  def index(conn, _params) do
    requests =
      case conn.assigns.current_scope do
        nil -> []
        scope -> Support.list_for_user(scope)
      end

    render(conn, :index, requests: requests)
  end

  def new(conn, _params) do
    render_form(conn, %SupportRequest{}, %{}, :new)
  end

  def create(conn, %{"support_request" => params}) when is_map(params) do
    case Support.create_request(conn.assigns.current_scope, params) do
      {:ok, request} ->
        redirect(conn, to: ~p"/support/received?reference=#{request.reference}")

      {:error, %Ecto.Changeset{} = changeset} ->
        conn
        |> put_status(:unprocessable_entity)
        |> render_form(changeset, %{}, :new)

      {:error, :rate_limited} ->
        conn
        |> put_status(:too_many_requests)
        |> put_flash(:error, gettext("Too many support requests. Please try again later."))
        |> render_form(%SupportRequest{}, params, :new)
    end
  end

  def create(conn, _params), do: send_resp(conn, :bad_request, "Bad Request")

  def delete_account(conn, _params) do
    render_form(
      conn,
      %SupportRequest{},
      %{
        "kind" => "account_deletion",
        "subject" => gettext("Delete my Who Need Help account"),
        "details" => gettext("Please delete my account and associated personal data.")
      },
      :delete_account
    )
  end

  def request_account_deletion(conn, %{"support_request" => params}) when is_map(params) do
    params =
      params
      |> Map.put("kind", "account_deletion")
      |> Map.put("subject", gettext("Delete my Who Need Help account"))

    case Support.create_request(conn.assigns.current_scope, params) do
      {:ok, request} ->
        redirect(conn, to: ~p"/support/received?reference=#{request.reference}")

      {:error, %Ecto.Changeset{} = changeset} ->
        conn
        |> put_status(:unprocessable_entity)
        |> render_form(changeset, params, :delete_account)

      {:error, :rate_limited} ->
        conn
        |> put_status(:too_many_requests)
        |> put_flash(:error, gettext("Too many support requests. Please try again later."))
        |> render_form(%SupportRequest{}, params, :delete_account)
    end
  end

  def request_account_deletion(conn, _params),
    do: send_resp(conn, :bad_request, "Bad Request")

  def show(conn, %{"id" => id} = params) do
    token = params["token"]

    result =
      case conn.assigns.current_scope do
        nil ->
          Support.get_by_access_token(id, token)

        scope ->
          case Support.get_for_user(scope, id) do
            {:ok, request} -> {:ok, request}
            _ -> Support.get_by_access_token(id, token)
          end
      end

    case result do
      {:ok, request} -> render(conn, :show, request: request)
      {:error, :not_found} -> send_resp(conn, :not_found, "Not found")
    end
  end

  def received(conn, %{"reference" => reference}) when is_binary(reference) do
    render(conn, :received, reference: String.slice(reference, 0, 64))
  end

  def received(conn, _params), do: redirect(conn, to: ~p"/support")

  defp render_form(conn, %Ecto.Changeset{} = changeset, _attrs, page) do
    render(conn, page,
      form: Phoenix.Component.to_form(changeset, as: :support_request),
      contact_email: current_email(conn)
    )
  end

  defp render_form(conn, %SupportRequest{} = request, attrs, page) do
    changeset = Support.change_request(request, with_contact_email(conn, attrs))
    render_form(conn, changeset, attrs, page)
  end

  defp with_contact_email(conn, attrs) do
    case current_email(conn) do
      nil -> attrs
      email -> Map.put(attrs, "contact_email", email)
    end
  end

  defp current_email(%{assigns: %{current_scope: %{user: %{email: email}}}}), do: email
  defp current_email(_conn), do: nil
end
