use crate::{build_totp_2fa, generate_totp_2fa_secret};
use activitypub_federation::config::Data;
use actix_web::web::Json;
use lemmy_api_common::{
  context::LemmyContext,
  person::GenerateTotpSecretResponse,
  sensitive::Sensitive,
};
use lemmy_db_schema::{
  source::local_user::{LocalUser, LocalUserUpdateForm},
  traits::Crud,
};
use lemmy_db_views::structs::{LocalUserView, SiteView};
use lemmy_utils::error::{LemmyError, LemmyErrorType};

/// Generate a new secret for two-factor-authentication. Afterwards you need to call [toggle_totp]
/// to enable it. This can only be called if 2FA is currently disabled.
#[tracing::instrument(skip(context))]
pub async fn generate_totp_secret(
  local_user_view: LocalUserView,
  context: Data<LemmyContext>,
) -> Result<Json<GenerateTotpSecretResponse>, LemmyError> {
  let site_view = SiteView::read_local(&mut context.pool()).await?;

  if local_user_view.local_user.totp_2fa_enabled {
    return Err(LemmyErrorType::TotpAlreadyEnabled)?;
  }

  let secret = generate_totp_2fa_secret();
  let secret_url =
    build_totp_2fa(&site_view.site.name, &local_user_view.person.name, &secret)?.get_url();

  let local_user_form = LocalUserUpdateForm {
    totp_2fa_secret: Some(Some(secret)),
    ..Default::default()
  };
  LocalUser::update(
    &mut context.pool(),
    local_user_view.local_user.id,
    &local_user_form,
  )
  .await?;

  Ok(Json(GenerateTotpSecretResponse {
    totp_secret_url: Sensitive::new(secret_url),
  }))
}
