/*
    This file is part of jellything (https://codeberg.org/metamuffin/jellything)
    which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
    Copyright (C) 2026 metamuffin <metamuffin.org>
*/
use crate::{CONF, DATABASE, session::create};
use anyhow::{Result, anyhow};
use argon2::{Argon2, PasswordHasher, password_hash::Salt};
use jellycommon::user::UserPermission;
use log::info;
use std::{collections::HashSet, time::Duration};

pub fn create_admin_account() -> Result<()> {
    if let Some(username) = &CONF.admin_username
        && let Some(password) = &CONF.admin_password
    {
        DATABASE
            .create_admin_user(username, hash_password(username, password))
            .unwrap();
    } else {
        info!("admin account disabled")
    }
    Ok(())
}

pub fn login_logic(
    username: &str,
    password: &str,
    expire: Option<i64>,
    drop_permissions: Option<HashSet<UserPermission>>,
) -> Result<String> {
    // hashing the password regardless if the accounts exists to better resist timing attacks
    let password = hash_password(username, password);

    let mut user = DATABASE
        .get_user(username)?
        .ok_or(anyhow!("invalid password"))?;

    if user.password != password {
        Err(anyhow!("invalid password"))?
    }

    if let Some(ep) = drop_permissions {
        // remove all grant perms that are in `ep`
        user.permissions
            .0
            .retain(|p, val| if *val { !ep.contains(p) } else { true })
    }

    Ok(create(
        user.name,
        user.permissions,
        Duration::from_days(
            CONF.login_expire
                .min(expire.unwrap_or(i64::MAX))
                .try_into()
                .unwrap(),
        ),
    ))
}

pub fn hash_password(username: &str, password: &str) -> Vec<u8> {
    Argon2::default()
        .hash_password(
            format!("{username}\0{password}").as_bytes(),
            <&str as TryInto<Salt>>::try_into("IYMa13osbNeLJKnQ1T8LlA").unwrap(),
        )
        .unwrap()
        .hash
        .unwrap()
        .as_bytes()
        .to_vec()
}
