use actix_web::{web, HttpResponse, Responder};
use lettre::{SmtpTransport, Transport};
use serde::Deserialize;
use sqlx::PgPool;

use crate::{
    endpoints::user::handle_password_change_request,
    models::{PasswordReset, User},
    utils::{email, ApplicationError},
};

#[derive(Deserialize, Debug)]
struct ResetPasswordForm {
    email: Option<String>,
    token: Option<String>,
    password: Option<String>,
    passwordretyped: Option<String>,
    dry: Option<bool>,
}

#[actix_web::post("/reset-password")]
async fn post(
    form: web::Form<ResetPasswordForm>,
    pool: web::Data<PgPool>,
    mailer: web::Data<SmtpTransport>,
) -> Result<impl Responder, ApplicationError> {
    if form.email.is_some()
        && form.token.is_none()
        && form.password.is_none()
        && form.passwordretyped.is_none()
    {
        if let Ok(user) = User::read_for_login(pool.get_ref(), form.email.as_ref().unwrap()).await {
            let reset = PasswordReset::insert_new_for_user(pool.get_ref(), user.id).await?;

            let message = email::build_forgot_password_message(&user, &reset.token);

            mailer.send(&message)?;
        }

        return Ok(HttpResponse::Ok().body("E-Mail versandt!"));
    } else if form.email.is_none()
        && form.token.is_some()
        && form.password.is_some()
        && form.passwordretyped.is_some()
    {
        // TODO: refactor into check if HX-TARGET = #password-strength exists
        let is_dry = form.dry.is_some_and(|b| b);

        let token = if let Some(token) =
            PasswordReset::does_token_exist(pool.get_ref(), &form.token.as_ref().unwrap()).await?
        {
            token
        } else {
            return Ok(HttpResponse::NoContent().finish());
        };

        let response = handle_password_change_request(
            pool.get_ref(),
            Some(&token),
            token.userid,
            form.password.as_ref().unwrap(),
            form.passwordretyped.as_ref().unwrap(),
            None,
            is_dry,
        )
        .await?;

        return Ok(response);
    } else {
        return Ok(HttpResponse::BadRequest().finish());
    }
}
