defmodule ToweropsWeb.UserSudoController do
  @moduledoc """
  Controller for sudo mode verification.

  Handles re-authentication for sensitive operations by requiring TOTP verification
  (no recovery codes allowed).
  """

  use ToweropsWeb, :controller

  import ToweropsWeb.UserAuth, only: [require_authenticated_user: 2]

  alias Towerops.Accounts

  plug :require_authenticated_user

  def new(conn, _params) do
    user = conn.assigns.current_scope.user

    cond do
      # Already in sudo mode (verified within last 10 minutes), redirect to destination
      recently_verified_sudo?(user) ->
        return_to = get_session(conn, :user_return_to) || ~p"/users/settings"

        conn
        |> delete_session(:user_return_to)
        |> redirect(to: return_to)

      # No TOTP devices, must enroll first
      !Accounts.totp_enabled?(user) ->
        conn
        |> put_flash(:error, "Two-factor authentication is required for this action.")
        |> redirect(to: ~p"/account/totp-enrollment")

      # Show verification form
      true ->
        form = Phoenix.Component.to_form(%{}, as: "user")
        render(conn, :verify, form: form)
    end
  end

  # Check if user verified sudo mode within the last 10 minutes
  # Uses last_sudo_at timestamp instead of authenticated_at to distinguish
  # between regular login and explicit sudo verification
  defp recently_verified_sudo?(%{last_sudo_at: nil}), do: false

  defp recently_verified_sudo?(%{last_sudo_at: last_sudo_at}) do
    ten_minutes_ago = DateTime.add(DateTime.utc_now(), -10, :minute)
    DateTime.after?(last_sudo_at, ten_minutes_ago)
  end

  def verify(conn, %{"user" => %{"totp_code" => totp_code}}) do
    user = conn.assigns.current_scope.user

    case Accounts.verify_totp_only(user, totp_code) do
      {:ok, _verified_user} ->
        # Grant sudo mode (updates last_sudo_at in database)
        case Accounts.grant_sudo_mode(user) do
          {:ok, _updated_user} ->
            # Redirect to return_to path or default
            return_to = get_session(conn, :user_return_to) || ~p"/users/settings"

            conn
            |> put_flash(:info, "Identity verified.")
            |> delete_session(:user_return_to)
            |> redirect(to: return_to)

          {:error, _changeset} ->
            # Shouldn't happen, but handle gracefully
            form = Phoenix.Component.to_form(%{"totp_code" => totp_code}, as: "user")

            conn
            |> put_flash(:error, "Failed to grant sudo mode. Please try again.")
            |> render(:verify, form: form)
        end

      {:error, :recovery_code_not_allowed} ->
        form = Phoenix.Component.to_form(%{"totp_code" => totp_code}, as: "user")

        conn
        |> put_flash(
          :error,
          "Recovery codes are not allowed for sudo mode verification. Please use your authenticator app."
        )
        |> render(:verify, form: form)

      {:error, :invalid_code} ->
        form = Phoenix.Component.to_form(%{"totp_code" => totp_code}, as: "user")

        conn
        |> put_flash(:error, "Invalid authentication code. Please try again.")
        |> render(:verify, form: form)
    end
  end

  def verify(conn, _params) do
    # Handle missing totp_code parameter
    form = Phoenix.Component.to_form(%{}, as: "user")
    render(conn, :verify, form: form)
  end
end
