defmodule BerrypodWeb.Auth.TotpVerification do
  use BerrypodWeb, :live_view

  alias Berrypod.Accounts

  @impl true
  def mount(_params, session, socket) do
    user_id = session["totp_pending_user_id"]
    remember_me = session["totp_pending_remember_me"]

    if user_id do
      {:ok,
       socket
       |> assign(:user_id, user_id)
       |> assign(:remember_me, remember_me)
       |> assign(:form, to_form(%{"code" => ""}, as: :totp))
       |> assign(:trigger_submit, false)}
    else
      {:ok,
       socket
       |> put_flash(:error, "Session expired. Please log in again.")
       |> redirect(to: ~p"/users/log-in")}
    end
  end

  @impl true
  def render(assigns) do
    ~H"""
    <Layouts.app flash={@flash} current_scope={@current_scope}>
      <div class="setup-page">
        <div class="setup-header">
          <.header>
            Two-factor authentication
            <:subtitle>
              Enter the 6-digit code from your authenticator app.
            </:subtitle>
          </.header>
        </div>

        <.form
          for={@form}
          id="totp_form"
          action={~p"/users/verify-totp"}
          phx-submit="verify"
          phx-trigger-action={@trigger_submit}
        >
          <input type="hidden" name="remember_me" value={to_string(@remember_me)} />

          <.input
            field={@form[:code]}
            type="text"
            label="Verification code"
            placeholder="000000"
            inputmode="numeric"
            pattern="[0-9]*"
            autocomplete="one-time-code"
            maxlength="6"
            autofocus
            phx-mounted={JS.focus()}
          />

          <.button variant="primary" class="admin-btn-block">
            Verify <span aria-hidden="true">&rarr;</span>
          </.button>
        </.form>

        <p class="setup-footer admin-text-tertiary">
          Lost your device? Enter one of your backup codes instead.
        </p>
      </div>
    </Layouts.app>
    """
  end

  @impl true
  def handle_event("verify", %{"totp" => %{"code" => code}}, socket) do
    user = Accounts.get_user!(socket.assigns.user_id)

    case Accounts.verify_totp(user, code) do
      :ok ->
        {:noreply, assign(socket, :trigger_submit, true)}

      :error ->
        {:noreply,
         socket
         |> assign(:form, to_form(%{"code" => ""}, as: :totp))
         |> put_flash(:error, "Invalid code. Please try again.")}
    end
  end
end
