use rusqlite::Connection;
use serde::Serialize;

use crate::crypto::encryption::{decrypt_data_with_user_key, encrypt_data_with_user_key, hash_element};
use crate::crypto::key_manager::get_user_encryption_key;
use crate::domains::issue::repo;
use crate::domains::tombstone::repo as tombstone_repo;
use crate::error::AppResult;
use crate::helpers::{create_unique_id, timestamp_in_seconds};
use crate::shared::types::Lang;

#[derive(Serialize)]
pub struct IssueProps {
    pub id: String,
    pub name: String,
}

/// Retrieves all issues associated with a specific book.
/// Decrypts issue names using the user's encryption key.
/// * `conn` - Database connection
/// * `user_id` - The unique identifier of the user
/// * `book_id` - The unique identifier of the book
/// * `lang` - The language for error messages ("fr" or "en")
/// Returns a list of decrypted issues.
pub fn get_issues_from_book(conn: &Connection, user_id: &str, book_id: &str, lang: Lang) -> AppResult<Vec<IssueProps>> {
    let issue_query_results: Vec<repo::IssueQuery> = repo::fetch_issues_from_book(conn, user_id, book_id, lang)?;
    let user_encryption_key: String = get_user_encryption_key(user_id)?;
    let mut decrypted_issues: Vec<IssueProps> = Vec::new();

    if !issue_query_results.is_empty() {
        for issue_record in issue_query_results {
            decrypted_issues.push(IssueProps {
                id: issue_record.issue_id,
                name: decrypt_data_with_user_key(&issue_record.name, &user_encryption_key)?,
            });
        }
    }

    Ok(decrypted_issues)
}

/// Creates a new issue for a book.
/// Encrypts and hashes the issue name before storage.
/// * `conn` - Database connection
/// * `user_id` - The unique identifier of the user
/// * `book_id` - The unique identifier of the book
/// * `name` - The plain text name of the issue
/// * `lang` - The language for error messages ("fr" or "en")
/// * `existing_issue_id` - Optional existing issue ID for syncing purposes
/// Returns the unique identifier of the created issue.
pub fn add_new_issue(conn: &Connection, user_id: &str, book_id: &str, name: &str, lang: Lang, existing_issue_id: Option<&str>) -> AppResult<String> {
    let user_encryption_key: String = get_user_encryption_key(user_id)?;
    let encrypted_name: String = encrypt_data_with_user_key(name, &user_encryption_key)?;
    let hashed_name: String = hash_element(name);
    let issue_id: String = create_unique_id(existing_issue_id);
    let last_update: i64 = timestamp_in_seconds();

    repo::insert_new_issue(conn, &issue_id, user_id, book_id, &encrypted_name, &hashed_name, last_update, lang)
}

/// Removes an issue from the database.
/// * `conn` - Database connection
/// * `user_id` - The unique identifier of the user
/// * `book_id` - The unique identifier of the book
/// * `issue_id` - The unique identifier of the issue to remove
/// * `deleted_at` - The timestamp of deletion
/// * `lang` - The language for error messages ("fr" or "en")
/// Returns true if the issue was successfully removed, false otherwise.
pub fn remove_issue(conn: &Connection, user_id: &str, book_id: &str, issue_id: &str, deleted_at: i64, lang: Lang) -> AppResult<bool> {
    let deleted: bool = repo::delete_issue(conn, user_id, issue_id, lang)?;
    if deleted {
        tombstone_repo::insert(conn, book_id, "book_issues", issue_id, Some(book_id), user_id, deleted_at, lang)?;
    }
    Ok(deleted)
}
