defmodule PlausibleWeb.Components.TwoFactor do
  @moduledoc """
  Reusable components specific to 2FA
  """
  use PlausibleWeb, :component

  attr :text, :string, required: true
  attr :scale, :integer, default: 4

  def qr_code(assigns) do
    qr_code =
      assigns.text
      |> EQRCode.encode()
      |> EQRCode.svg(%{width: 160})

    assigns = assign(assigns, :code, qr_code)

    ~H"""
    {Phoenix.HTML.raw(@code)}
    """
  end

  attr :id, :string, default: "verify-button"
  attr :form, :any, required: true
  attr :field, :any, required: true
  attr :class, :string, default: ""
  attr :show_button?, :boolean, default: true

  def verify_2fa_input(assigns) do
    input_class =
      "font-mono tracking-[0.5em] w-36 pl-5 font-medium shadow-sm focus:ring-indigo-500 focus:border-indigo-500 block border-gray-300 dark:border-gray-500 dark:text-gray-200 dark:bg-gray-900 rounded-l-md"

    input_class =
      if assigns.show_button? do
        input_class
      else
        [input_class, "rounded-r-md"]
      end

    assigns = assign(assigns, :input_class, input_class)
    assigns = assign(assigns, :field, assigns[:form][assigns[:field]])

    ~H"""
    <div class={[@class, "flex items-center"]}>
      <input
        type="text"
        name={@field.name}
        value={@field.value}
        autocomplete="off"
        class={@input_class}
        oninput={
          if @show_button? do
            "this.value=this.value.replace(/[^0-9]/g, ''); if (this.value.length >= 6) document.getElementById('#{@id}').focus()"
          else
            "this.value=this.value.replace(/[^0-9]/g, '');"
          end
        }
        onclick="this.select();"
        oninvalid={@show_button? && "document.getElementById('#{@id}').disabled = false"}
        maxlength="6"
        placeholder="••••••"
        required="required"
      />
      <.button
        :if={@show_button?}
        type="submit"
        id={@id}
        mt?={false}
        class="rounded-l-none [&>span.label-enabled]:block [&>span.label-disabled]:hidden [&[disabled]>span.label-enabled]:hidden [&[disabled]>span.label-disabled]:block"
      >
        <span class="label-enabled pointer-events-none">
          Verify &rarr;
        </span>

        <span class="label-disabled">
          <.spinner class="inline-block h-5 w-5 mr-2 text-white dark:text-gray-400" /> Verifying...
        </span>
      </.button>
    </div>
    """
  end

  attr :id, :string, required: true
  attr :state_param, :string, required: true
  attr :form_data, :any, required: true
  attr :form_target, :string, required: true
  attr :onsubmit, :string, default: nil
  attr :title, :string, required: true

  slot :icon, required: true
  slot :inner_block, required: true
  slot :buttons, required: true

  def modal(assigns) do
    ~H"""
    <div
      id={@id}
      x-cloak
      x-show={@state_param}
      x-on:keyup.escape.window={"#{@state_param} = false"}
      class="fixed z-10 inset-0 overflow-y-auto"
      aria-labelledby="modal-title"
      role="dialog"
      aria-modal="true"
    >
      <div class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
        <div
          x-show={@state_param}
          x-transition:enter="transition ease-out duration-300"
          x-transition:enter-start="opacity-0"
          x-transition:enter-end="opacity-100"
          x-transition:leave="transition ease-in duration-200"
          x-transition:leave-start="opacity-100"
          x-transition:leave-end="opacity-0"
          class="fixed inset-0 bg-gray-500/75 dark:bg-gray-800/75 transition-opacity"
          aria-hidden="true"
          x-on:click={"#{@state_param} = false"}
        >
        </div>
        <!-- This element is to trick the browser into centering the modal contents. -->
        <span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">
          &#8203;
        </span>

        <div
          x-show={@state_param}
          x-transition:enter="transition ease-out duration-300"
          x-transition:enter-start="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
          x-transition:enter-end="opacity-100 translate-y-0 sm:scale-100"
          x-transition:leave="transition ease-in duration-200"
          x-transition:leave-start="opacity-100 translate-y-0 sm:scale-100"
          x-transition:leave-end="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
          class="inline-block align-bottom bg-white dark:bg-gray-900 rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full"
        >
          <.form :let={f} for={@form_data} action={@form_target} onsubmit={@onsubmit}>
            <div class="bg-white dark:bg-gray-800 px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
              <div class="hidden sm:block absolute top-0 right-0 pt-4 pr-4">
                <a
                  href="#"
                  x-on:click.prevent={"#{@state_param} = false"}
                  class="bg-white dark:bg-gray-800 rounded-md text-gray-400 dark:text-gray-500 hover:text-gray-500 dark:hover:text-gray-400 focus:outline-hidden"
                >
                  <span class="sr-only">Close</span>
                  <Heroicons.x_mark class="h-6 w-6" />
                </a>
              </div>
              <div class="sm:flex sm:items-start">
                <div class="mx-auto shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-green-100 sm:mx-0 sm:h-10 sm:w-10">
                  {render_slot(@icon)}
                </div>
                <div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left text-gray-900 dark:text-gray-100">
                  <h3 class="text-lg leading-6 font-medium" id="modal-title">
                    {@title}
                  </h3>

                  {render_slot(@inner_block, f)}
                </div>
              </div>
            </div>
            <div class="bg-gray-50 dark:bg-gray-850 px-4 py-3 sm:px-9 sm:flex sm:flex-row-reverse">
              {render_slot(@buttons)}
              <.button
                type="button"
                x-on:click={"#{@state_param} = false"}
                class="w-full sm:w-auto mr-2"
                theme="bright"
              >
                Cancel
              </.button>
            </div>
          </.form>
        </div>
      </div>
    </div>
    """
  end
end
