Skip to content
use crate::db::DbConfig;
use actix_web::HttpRequest;
use argon2::password_hash::SaltString;
use argon2::password_hash::rand_core::OsRng;
use argon2::{Argon2, PasswordHash, PasswordHasher, PasswordVerifier};
use uuid::Uuid;

pub fn hash_password(password: &str) -> Result<String, Box<dyn std::error::Error + Send + Sync>> {
    let salt = SaltString::generate(&mut OsRng);
    let argon2 = Argon2::default();
    let hash = argon2
        .hash_password(password.as_bytes(), &salt)
        .map_err(|e| format!("Failed to hash password: {e}"))?;
    Ok(hash.to_string())
}

pub fn verify_password(password: &str, hash: &str) -> bool {
    let parsed = match PasswordHash::new(hash) {
        Ok(h) => h,
        Err(_) => return false,
    };
    Argon2::default()
        .verify_password(password.as_bytes(), &parsed)
        .is_ok()
}

pub async fn get_current_author(req: &HttpRequest, db: &DbConfig) -> Option<(Uuid, String)> {
    let cookie = req.cookie("session_token")?;
    let token = Uuid::parse_str(cookie.value()).ok()?;
    let client = db.connect().await.ok()?;

    let row = client
        .query_opt(
            "SELECT s.author_id, a.display_name FROM sessions s JOIN authors a ON s.author_id = a.id WHERE s.token = $1",
            &[&token],
        )
        .await
        .ok()??;

    let author_id: Uuid = row.get(0);
    let display_name: String = row.get(1);
    Some((author_id, display_name))
}

pub async fn create_session(
    db: &DbConfig,
    author_id: Uuid,
) -> Result<Uuid, Box<dyn std::error::Error + Send + Sync>> {
    let client = db.connect().await?;
    let token = Uuid::new_v4();
    client
        .execute(
            "INSERT INTO sessions (token, author_id) VALUES ($1, $2)",
            &[&token, &author_id],
        )
        .await?;
    Ok(token)
}

pub async fn delete_session(
    db: &DbConfig,
    token: Uuid,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    let client = db.connect().await?;
    client
        .execute("DELETE FROM sessions WHERE token = $1", &[&token])
        .await?;
    Ok(())
}