use rusqlite::Connection;

use crate::crypto::encryption::{encrypt_data_with_user_key, decrypt_data_with_user_key, hash_element};
use crate::crypto::key_manager::get_user_encryption_key;
use crate::domains::user::repo;
use crate::error::AppResult;
use crate::shared::types::Lang;

pub struct UserInfoResponse {
    pub id: String,
    pub username: String,
    pub email: String,
    pub author_name: String,
    pub group_id: i64,
}

/// Retrieves complete user information including associated books.
pub fn return_user_infos(conn: &Connection, user_id: &str, lang: Lang) -> AppResult<UserInfoResponse> {
    let user_infos_data: repo::UserInfosQueryResponse = repo::fetch_user_infos(conn, user_id, lang)?;
    let user_encryption_key: String = get_user_encryption_key(user_id)?;

    let username: String = decrypt_data_with_user_key(&user_infos_data.username, &user_encryption_key)?;
    let email: String = decrypt_data_with_user_key(&user_infos_data.email, &user_encryption_key)?;
    let author_name: String = if let Some(ref author_name_val) = user_infos_data.author_name { if author_name_val.is_empty() { String::new() } else { decrypt_data_with_user_key(author_name_val, &user_encryption_key)? } } else { String::new() };

    Ok(UserInfoResponse {
        id: user_id.to_string(),
        username, email, author_name,
        group_id: user_infos_data.user_group,
    })
}

/// Creates a new user in the database with encrypted personal information.
pub fn add_user(conn: &Connection, user_id: &str, username: &str, email: &str, lang: Lang) -> AppResult<String> {
    let user_encryption_key: String = get_user_encryption_key(user_id)?;
    let encrypted_username: String = encrypt_data_with_user_key(username, &user_encryption_key)?;
    let encrypted_email: String = encrypt_data_with_user_key(email, &user_encryption_key)?;
    let hashed_email: String = hash_element(email);
    let hashed_username: String = hash_element(username);

    repo::insert_user(conn, user_id, &encrypted_username, &hashed_username, &encrypted_email, &hashed_email, lang)
}

/// Updates an existing user's profile information in the database.
pub fn update_user_infos(
    conn: &Connection, user_key: &str, user_id: &str,
    username: &str, email: &str, author_name: Option<&str>, lang: Lang,
) -> AppResult<bool> {
    let encrypted_username: String = encrypt_data_with_user_key(username, user_key)?;
    let encrypted_email: String = encrypt_data_with_user_key(email, user_key)?;
    let hashed_email: String = hash_element(email);
    let hashed_username: String = hash_element(username);
    let mut encrypted_author_name: String = String::new();
    let mut hashed_author_name: String = String::new();
    if let Some(author_name_val) = author_name {
        encrypted_author_name = encrypt_data_with_user_key(author_name_val, user_key)?;
        hashed_author_name = hash_element(author_name_val);
    }

    repo::update_user_infos(conn, user_id, &encrypted_username, &hashed_username, &encrypted_email, &hashed_email, &hashed_author_name, &encrypted_author_name, lang)
}
