use rusqlite::Connection;

use crate::crypto::encryption::decrypt_data_with_user_key;
use crate::crypto::key_manager::get_user_encryption_key;
use crate::domains::act::repo as act_repo;
use crate::domains::book::repo as book_repo;
use crate::domains::book::service::{
    BookActSummariesTable, BookAIGuideLineTable, BookChapterContentTable, BookChapterInfosTable,
    BookChaptersTable, BookCharactersAttributesTable, BookCharactersTable, BookGuideLineTable,
    BookIncidentsTable, BookIssuesTable, BookLocationTable, BookPlotPointsTable, BookSpellsTable,
    BookSpellTagsTable, BookWorldElementsTable, BookWorldTable, CompleteBook,
    LocationElementTable, LocationSubElementTable,
};
use crate::domains::chapter::repo as chapter_repo;
use crate::domains::chapter_content::repo as chapter_content_repo;
use crate::domains::character::repo as character_repo;
use crate::domains::guideline::repo as guideline_repo;
use crate::domains::incident::repo as incident_repo;
use crate::domains::issue::repo as issue_repo;
use crate::domains::location::repo as location_repo;
use crate::domains::plotpoint::repo as plotpoint_repo;
use crate::domains::spell::repo as spell_repo;
use crate::domains::spell_tag::repo as spell_tag_repo;
use crate::domains::world::repo as world_repo;
use crate::error::AppResult;
use crate::shared::types::Lang;

/// Prepares a complete book with all related data for synchronization upload.
/// Fetches all book-related tables from the database, decrypts encrypted fields
/// using the user's encryption key, and returns a complete book object ready for sync.
/// * `conn` - Database connection
/// * `user_id` - The unique identifier of the user who owns the book
/// * `book_id` - The unique identifier of the book to upload
/// * `lang` - The language code for localization
/// Returns a CompleteBook object containing all decrypted book data.
pub fn upload_book_for_sync(conn: &Connection, user_id: &str, book_id: &str, lang: Lang) -> AppResult<CompleteBook> {
    let user_encryption_key: String = get_user_encryption_key(user_id)?;

    let encrypted_books: Vec<book_repo::EritBooksTable> = book_repo::fetch_erit_books_table(conn, user_id, book_id, lang)?;
    let encrypted_act_summaries: Vec<act_repo::BookActSummariesTable> = act_repo::fetch_book_act_summaries(conn, user_id, book_id, lang)?;
    let encrypted_ai_guidelines: Vec<guideline_repo::BookAIGuideLineTable> = guideline_repo::fetch_book_ai_guide_line(conn, user_id, book_id, lang)?;
    let encrypted_chapters: Vec<chapter_repo::BookChaptersTable> = chapter_repo::fetch_book_chapters(conn, user_id, book_id, lang)?;
    let encrypted_characters: Vec<character_repo::BookCharactersTable> = character_repo::fetch_book_characters(conn, user_id, book_id, lang)?;
    let encrypted_guidelines: Vec<guideline_repo::BookGuideLineTable> = guideline_repo::fetch_book_guide_line_table(conn, user_id, book_id, lang)?;
    let encrypted_incidents: Vec<incident_repo::BookIncidentsTable> = incident_repo::fetch_book_incidents(conn, user_id, book_id, lang)?;
    let encrypted_issues: Vec<issue_repo::BookIssuesTable> = issue_repo::fetch_book_issues(conn, user_id, book_id, lang)?;
    let encrypted_locations: Vec<location_repo::BookLocationTable> = location_repo::fetch_book_locations(conn, user_id, book_id, lang)?;
    let encrypted_plot_points: Vec<plotpoint_repo::BookPlotPointsTable> = plotpoint_repo::fetch_book_plot_points(conn, user_id, book_id, lang)?;
    let encrypted_worlds: Vec<world_repo::BookWorldTable> = world_repo::fetch_book_worlds(conn, user_id, book_id, lang)?;
    let book_tools_data: Option<book_repo::BookToolsTable> = book_repo::fetch_book_tools(conn, user_id, book_id, lang)?;
    let encrypted_spells: Vec<spell_repo::BookSpellsTable> = spell_repo::fetch_book_spells_table(conn, user_id, book_id, lang)?;
    let encrypted_spell_tags: Vec<spell_tag_repo::BookSpellTagsTable> = spell_tag_repo::fetch_book_spell_tags_table(conn, user_id, book_id, lang)?;

    let encrypted_chapter_contents: Vec<chapter_content_repo::BookChapterContentTable> = chapter_content_repo::fetch_all_chapter_contents_by_book(conn, user_id, book_id, lang)?;
    let encrypted_chapter_infos: Vec<chapter_repo::BookChapterInfosTable> = chapter_repo::fetch_all_chapter_infos_by_book(conn, user_id, book_id, lang)?;
    let encrypted_character_attributes: Vec<character_repo::BookCharactersAttributesTable> = character_repo::fetch_all_character_attributes_by_book(conn, user_id, book_id, lang)?;
    let encrypted_world_elements: Vec<world_repo::BookWorldElementsTable> = world_repo::fetch_all_world_elements_by_book(conn, user_id, book_id, lang)?;
    let encrypted_location_elements: Vec<location_repo::LocationElementTable> = location_repo::fetch_all_location_elements_by_book(conn, user_id, book_id, lang)?;
    let encrypted_location_sub_elements: Vec<location_repo::LocationSubElementTable> = location_repo::fetch_all_location_sub_elements_by_book(conn, user_id, book_id, lang)?;

    let mut erit_books: Vec<book_repo::EritBooksTable> = Vec::with_capacity(encrypted_books.len());
    for book in encrypted_books {
        let decrypted_title: String = decrypt_data_with_user_key(&book.title, &user_encryption_key)?;
        let decrypted_sub_title: Option<String> = if let Some(ref sub_title) = book.sub_title { Some(decrypt_data_with_user_key(sub_title, &user_encryption_key)?) } else { None };
        let decrypted_summary: Option<String> = if let Some(ref summary) = book.summary { Some(decrypt_data_with_user_key(summary, &user_encryption_key)?) } else { None };
        let decrypted_cover_image: Option<String> = if let Some(ref cover_image) = book.cover_image { Some(decrypt_data_with_user_key(cover_image, &user_encryption_key)?) } else { None };
        erit_books.push(book_repo::EritBooksTable {
            title: decrypted_title, sub_title: decrypted_sub_title,
            summary: decrypted_summary, cover_image: decrypted_cover_image,
            ..book
        });
    }

    let mut act_summaries: Vec<BookActSummariesTable> = Vec::with_capacity(encrypted_act_summaries.len());
    for act_summary in encrypted_act_summaries {
        let decrypted_summary: String = if let Some(ref summary) = act_summary.summary { if summary.is_empty() { String::new() } else { decrypt_data_with_user_key(summary, &user_encryption_key)? } } else { String::new() };
        act_summaries.push(BookActSummariesTable {
            act_sum_id: act_summary.act_sum_id, book_id: act_summary.book_id,
            user_id: act_summary.user_id, act_index: act_summary.act_index,
            summary: if decrypted_summary.is_empty() { None } else { Some(decrypted_summary) },
            last_update: act_summary.last_update,
        });
    }

    let mut ai_guide_line: Vec<BookAIGuideLineTable> = Vec::with_capacity(encrypted_ai_guidelines.len());
    for guide_line in encrypted_ai_guidelines {
        let decrypted_global_resume: Option<String> = if let Some(ref global_resume) = guide_line.global_resume { Some(decrypt_data_with_user_key(global_resume, &user_encryption_key)?) } else { None };
        let decrypted_themes: Option<String> = if let Some(ref themes) = guide_line.themes { Some(decrypt_data_with_user_key(themes, &user_encryption_key)?) } else { None };
        let decrypted_tone: Option<String> = if let Some(ref tone) = guide_line.tone { Some(decrypt_data_with_user_key(tone, &user_encryption_key)?) } else { None };
        let decrypted_atmosphere: Option<String> = if let Some(ref atmosphere) = guide_line.atmosphere { Some(decrypt_data_with_user_key(atmosphere, &user_encryption_key)?) } else { None };
        let decrypted_current_resume: Option<String> = if let Some(ref current_resume) = guide_line.current_resume { Some(decrypt_data_with_user_key(current_resume, &user_encryption_key)?) } else { None };
        ai_guide_line.push(BookAIGuideLineTable {
            user_id: guide_line.user_id, book_id: guide_line.book_id,
            global_resume: decrypted_global_resume, themes: decrypted_themes,
            verbe_tense: guide_line.verbe_tense, narrative_type: guide_line.narrative_type,
            langue: guide_line.langue, dialogue_type: guide_line.dialogue_type,
            tone: decrypted_tone, atmosphere: decrypted_atmosphere,
            current_resume: decrypted_current_resume, last_update: guide_line.last_update,
        });
    }

    let mut chapters: Vec<BookChaptersTable> = Vec::with_capacity(encrypted_chapters.len());
    for chapter in encrypted_chapters {
        let decrypted_title: String = decrypt_data_with_user_key(&chapter.title, &user_encryption_key)?;
        chapters.push(BookChaptersTable {
            chapter_id: chapter.chapter_id, book_id: chapter.book_id,
            author_id: chapter.author_id, title: decrypted_title,
            hashed_title: chapter.hashed_title, words_count: chapter._words_count,
            chapter_order: chapter.chapter_order, last_update: chapter.last_update,
        });
    }

    let mut chapter_contents: Vec<BookChapterContentTable> = Vec::with_capacity(encrypted_chapter_contents.len());
    for chapter_content in encrypted_chapter_contents {
        let decrypted_content: Option<serde_json::Value> = if let Some(ref content) = chapter_content.content {
            let decrypted: String = decrypt_data_with_user_key(content, &user_encryption_key)?;
            serde_json::from_str(&decrypted).ok()
        } else { None };
        chapter_contents.push(BookChapterContentTable {
            content_id: chapter_content.content_id, chapter_id: chapter_content.chapter_id,
            author_id: chapter_content.author_id, version: chapter_content.version,
            content: decrypted_content, words_count: Some(chapter_content._words_count),
            time_on_it: Some(chapter_content._time_on_it), last_update: chapter_content.last_update,
        });
    }

    let mut chapter_infos: Vec<BookChapterInfosTable> = Vec::with_capacity(encrypted_chapter_infos.len());
    for chapter_info in encrypted_chapter_infos {
        let decrypted_summary: Option<String> = if let Some(ref summary) = chapter_info.summary { Some(decrypt_data_with_user_key(summary, &user_encryption_key)?) } else { None };
        let decrypted_goal: Option<String> = if let Some(ref goal) = chapter_info.goal { Some(decrypt_data_with_user_key(goal, &user_encryption_key)?) } else { None };
        chapter_infos.push(BookChapterInfosTable {
            chapter_info_id: chapter_info._chapter_info_id.clone(),
            chapter_id: chapter_info.chapter_id, act_id: chapter_info._act_id,
            incident_id: chapter_info._incident_id.clone(),
            plot_point_id: chapter_info._plot_point_id.clone(),
            book_id: chapter_info._book_id.clone(), author_id: chapter_info.author_id,
            summary: decrypted_summary, goal: decrypted_goal,
            last_update: chapter_info.last_update,
        });
    }

    let mut characters: Vec<BookCharactersTable> = Vec::with_capacity(encrypted_characters.len());
    for character in encrypted_characters {
        let decrypted_first_name: String = decrypt_data_with_user_key(&character.first_name, &user_encryption_key)?;
        let decrypted_last_name: Option<String> = if let Some(ref last_name) = character.last_name { Some(decrypt_data_with_user_key(last_name, &user_encryption_key)?) } else { None };
        let decrypted_nickname: Option<String> = if let Some(ref nickname) = character.nickname { Some(decrypt_data_with_user_key(nickname, &user_encryption_key)?) } else { None };
        let decrypted_age: Option<String> = if let Some(ref age) = character.age { Some(decrypt_data_with_user_key(age, &user_encryption_key)?) } else { None };
        let decrypted_gender: Option<String> = if let Some(ref gender) = character.gender { Some(decrypt_data_with_user_key(gender, &user_encryption_key)?) } else { None };
        let decrypted_species: Option<String> = if let Some(ref species) = character.species { Some(decrypt_data_with_user_key(species, &user_encryption_key)?) } else { None };
        let decrypted_nationality: Option<String> = if let Some(ref nationality) = character.nationality { Some(decrypt_data_with_user_key(nationality, &user_encryption_key)?) } else { None };
        let decrypted_status: Option<String> = if let Some(ref status) = character.status { Some(decrypt_data_with_user_key(status, &user_encryption_key)?) } else { None };
        let decrypted_category: String = decrypt_data_with_user_key(&character.category, &user_encryption_key)?;
        let decrypted_title: Option<String> = if let Some(ref title) = character.title { Some(decrypt_data_with_user_key(title, &user_encryption_key)?) } else { None };
        let decrypted_role: Option<String> = if let Some(ref role) = character.role { Some(decrypt_data_with_user_key(role, &user_encryption_key)?) } else { None };
        let decrypted_biography: Option<String> = if let Some(ref biography) = character.biography { Some(decrypt_data_with_user_key(biography, &user_encryption_key)?) } else { None };
        let decrypted_history: Option<String> = if let Some(ref history) = character.history { Some(decrypt_data_with_user_key(history, &user_encryption_key)?) } else { None };
        let decrypted_speech_pattern: Option<String> = if let Some(ref speech_pattern) = character.speech_pattern { Some(decrypt_data_with_user_key(speech_pattern, &user_encryption_key)?) } else { None };
        let decrypted_catchphrase: Option<String> = if let Some(ref catchphrase) = character.catchphrase { Some(decrypt_data_with_user_key(catchphrase, &user_encryption_key)?) } else { None };
        let decrypted_residence: Option<String> = if let Some(ref residence) = character.residence { Some(decrypt_data_with_user_key(residence, &user_encryption_key)?) } else { None };
        let decrypted_notes: Option<String> = if let Some(ref notes) = character.notes { Some(decrypt_data_with_user_key(notes, &user_encryption_key)?) } else { None };
        let decrypted_color: Option<String> = if let Some(ref color) = character.color { Some(decrypt_data_with_user_key(color, &user_encryption_key)?) } else { None };
        characters.push(BookCharactersTable {
            character_id: character.character_id, book_id: character.book_id,
            user_id: character.user_id, first_name: decrypted_first_name,
            last_name: decrypted_last_name, nickname: decrypted_nickname,
            age: decrypted_age, gender: decrypted_gender, species: decrypted_species,
            nationality: decrypted_nationality, status: decrypted_status,
            title: decrypted_title, category: decrypted_category,
            image: character.image, role: decrypted_role,
            biography: decrypted_biography, history: decrypted_history,
            speech_pattern: decrypted_speech_pattern, catchphrase: decrypted_catchphrase,
            residence: decrypted_residence, notes: decrypted_notes,
            color: decrypted_color, last_update: character.last_update,
        });
    }

    let mut character_attributes: Vec<BookCharactersAttributesTable> = Vec::with_capacity(encrypted_character_attributes.len());
    for attribute in encrypted_character_attributes {
        let decrypted_attribute_name: String = decrypt_data_with_user_key(&attribute.attribute_name, &user_encryption_key)?;
        let decrypted_attribute_value: String = decrypt_data_with_user_key(&attribute.attribute_value, &user_encryption_key)?;
        character_attributes.push(BookCharactersAttributesTable {
            attr_id: attribute.attr_id, character_id: attribute.character_id,
            user_id: attribute.user_id, attribute_name: decrypted_attribute_name,
            attribute_value: decrypted_attribute_value, last_update: attribute.last_update,
        });
    }

    let mut guide_line: Vec<BookGuideLineTable> = Vec::with_capacity(encrypted_guidelines.len());
    for guide in encrypted_guidelines {
        let decrypted_tone: Option<String> = if let Some(ref tone) = guide.tone { Some(decrypt_data_with_user_key(tone, &user_encryption_key)?) } else { None };
        let decrypted_atmosphere: Option<String> = if let Some(ref atmosphere) = guide.atmosphere { Some(decrypt_data_with_user_key(atmosphere, &user_encryption_key)?) } else { None };
        let decrypted_writing_style: Option<String> = if let Some(ref writing_style) = guide.writing_style { Some(decrypt_data_with_user_key(writing_style, &user_encryption_key)?) } else { None };
        let decrypted_themes: Option<String> = if let Some(ref themes) = guide.themes { Some(decrypt_data_with_user_key(themes, &user_encryption_key)?) } else { None };
        let decrypted_symbolism: Option<String> = if let Some(ref symbolism) = guide.symbolism { Some(decrypt_data_with_user_key(symbolism, &user_encryption_key)?) } else { None };
        let decrypted_motifs: Option<String> = if let Some(ref motifs) = guide.motifs { Some(decrypt_data_with_user_key(motifs, &user_encryption_key)?) } else { None };
        let decrypted_narrative_voice: Option<String> = if let Some(ref narrative_voice) = guide.narrative_voice { Some(decrypt_data_with_user_key(narrative_voice, &user_encryption_key)?) } else { None };
        let decrypted_pacing: Option<String> = if let Some(ref pacing) = guide.pacing { Some(decrypt_data_with_user_key(pacing, &user_encryption_key)?) } else { None };
        let decrypted_intended_audience: Option<String> = if let Some(ref intended_audience) = guide.intended_audience { Some(decrypt_data_with_user_key(intended_audience, &user_encryption_key)?) } else { None };
        let decrypted_key_messages: Option<String> = if let Some(ref key_messages) = guide.key_messages { Some(decrypt_data_with_user_key(key_messages, &user_encryption_key)?) } else { None };
        guide_line.push(BookGuideLineTable {
            user_id: guide.user_id, book_id: guide.book_id,
            tone: decrypted_tone, atmosphere: decrypted_atmosphere,
            writing_style: decrypted_writing_style, themes: decrypted_themes,
            symbolism: decrypted_symbolism, motifs: decrypted_motifs,
            narrative_voice: decrypted_narrative_voice, pacing: decrypted_pacing,
            intended_audience: decrypted_intended_audience, key_messages: decrypted_key_messages,
            last_update: guide.last_update,
        });
    }

    let mut incidents: Vec<BookIncidentsTable> = Vec::with_capacity(encrypted_incidents.len());
    for incident in encrypted_incidents {
        let decrypted_title: String = decrypt_data_with_user_key(&incident.title, &user_encryption_key)?;
        let decrypted_summary: Option<String> = if let Some(ref summary) = incident.summary { Some(decrypt_data_with_user_key(summary, &user_encryption_key)?) } else { None };
        incidents.push(BookIncidentsTable {
            incident_id: incident.incident_id, author_id: incident.author_id,
            book_id: incident.book_id, title: decrypted_title,
            hashed_title: incident.hashed_title, summary: decrypted_summary,
            last_update: incident.last_update,
        });
    }

    let mut issues: Vec<BookIssuesTable> = Vec::with_capacity(encrypted_issues.len());
    for issue in encrypted_issues {
        let decrypted_name: String = decrypt_data_with_user_key(&issue.name, &user_encryption_key)?;
        issues.push(BookIssuesTable {
            issue_id: issue.issue_id, author_id: issue.author_id,
            book_id: issue.book_id, name: decrypted_name,
            hashed_issue_name: issue.hashed_issue_name,
            last_update: issue.last_update,
        });
    }

    let mut locations: Vec<BookLocationTable> = Vec::with_capacity(encrypted_locations.len());
    for location in encrypted_locations {
        let decrypted_loc_name: String = decrypt_data_with_user_key(&location.loc_name, &user_encryption_key)?;
        locations.push(BookLocationTable {
            loc_id: location.loc_id, book_id: location.book_id,
            user_id: location.user_id, loc_name: decrypted_loc_name,
            loc_original_name: location.loc_original_name, last_update: location.last_update,
        });
    }

    let mut plot_points: Vec<BookPlotPointsTable> = Vec::with_capacity(encrypted_plot_points.len());
    for plot_point in encrypted_plot_points {
        let decrypted_title: String = decrypt_data_with_user_key(&plot_point.title, &user_encryption_key)?;
        let decrypted_summary: Option<String> = if let Some(ref summary) = plot_point.summary { Some(decrypt_data_with_user_key(summary, &user_encryption_key)?) } else { None };
        plot_points.push(BookPlotPointsTable {
            plot_point_id: plot_point.plot_point_id, title: decrypted_title,
            hashed_title: plot_point.hashed_title, summary: decrypted_summary,
            linked_incident_id: plot_point.linked_incident_id,
            author_id: plot_point.author_id, book_id: plot_point._book_id,
            last_update: plot_point.last_update,
        });
    }

    let mut worlds: Vec<BookWorldTable> = Vec::with_capacity(encrypted_worlds.len());
    for world in encrypted_worlds {
        let decrypted_name: String = decrypt_data_with_user_key(&world.name, &user_encryption_key)?;
        let decrypted_history: Option<String> = if let Some(ref history) = world.history { Some(decrypt_data_with_user_key(history, &user_encryption_key)?) } else { None };
        let decrypted_politics: Option<String> = if let Some(ref politics) = world.politics { Some(decrypt_data_with_user_key(politics, &user_encryption_key)?) } else { None };
        let decrypted_economy: Option<String> = if let Some(ref economy) = world.economy { Some(decrypt_data_with_user_key(economy, &user_encryption_key)?) } else { None };
        let decrypted_religion: Option<String> = if let Some(ref religion) = world.religion { Some(decrypt_data_with_user_key(religion, &user_encryption_key)?) } else { None };
        let decrypted_languages: Option<String> = if let Some(ref languages) = world.languages { Some(decrypt_data_with_user_key(languages, &user_encryption_key)?) } else { None };
        worlds.push(BookWorldTable {
            world_id: world.world_id, name: decrypted_name,
            hashed_name: world.hashed_name, author_id: world.author_id,
            book_id: world.book_id,
            history: decrypted_history,
            politics: decrypted_politics, economy: decrypted_economy,
            religion: decrypted_religion, languages: decrypted_languages,
            last_update: world.last_update,
        });
    }

    let mut world_elements: Vec<BookWorldElementsTable> = Vec::with_capacity(encrypted_world_elements.len());
    for world_element in encrypted_world_elements {
        let decrypted_name: String = decrypt_data_with_user_key(&world_element.name, &user_encryption_key)?;
        let decrypted_description: Option<String> = if let Some(ref description) = world_element.description { Some(decrypt_data_with_user_key(description, &user_encryption_key)?) } else { None };
        world_elements.push(BookWorldElementsTable {
            element_id: world_element.element_id, world_id: world_element.world_id,
            user_id: world_element.user_id, element_type: world_element.element_type,
            name: decrypted_name, original_name: world_element.original_name,
            description: decrypted_description, last_update: world_element.last_update,
        });
    }

    let mut location_elements: Vec<LocationElementTable> = Vec::with_capacity(encrypted_location_elements.len());
    for location_element in encrypted_location_elements {
        let decrypted_element_name: String = decrypt_data_with_user_key(&location_element.element_name, &user_encryption_key)?;
        let decrypted_element_description: Option<String> = if let Some(ref element_description) = location_element.element_description { Some(decrypt_data_with_user_key(element_description, &user_encryption_key)?) } else { None };
        location_elements.push(LocationElementTable {
            element_id: location_element.element_id, location: location_element.location,
            user_id: location_element.user_id, element_name: decrypted_element_name,
            original_name: location_element.original_name,
            element_description: decrypted_element_description,
            last_update: location_element.last_update,
        });
    }

    let mut location_sub_elements: Vec<LocationSubElementTable> = Vec::with_capacity(encrypted_location_sub_elements.len());
    for location_sub_element in encrypted_location_sub_elements {
        let decrypted_sub_elem_name: String = decrypt_data_with_user_key(&location_sub_element.sub_elem_name, &user_encryption_key)?;
        let decrypted_sub_elem_description: Option<String> = if let Some(ref sub_elem_description) = location_sub_element.sub_elem_description { Some(decrypt_data_with_user_key(sub_elem_description, &user_encryption_key)?) } else { None };
        location_sub_elements.push(LocationSubElementTable {
            sub_element_id: location_sub_element.sub_element_id,
            element_id: location_sub_element.element_id,
            user_id: location_sub_element.user_id, sub_elem_name: decrypted_sub_elem_name,
            original_name: location_sub_element.original_name,
            sub_elem_description: decrypted_sub_elem_description,
            last_update: location_sub_element.last_update,
        });
    }

    let book_tools: Vec<book_repo::BookToolsTable> = if let Some(tools_data) = book_tools_data { vec![tools_data] } else { vec![] };

    let mut spells: Vec<BookSpellsTable> = Vec::with_capacity(encrypted_spells.len());
    for spell in encrypted_spells {
        let decrypted_name: String = decrypt_data_with_user_key(&spell.name, &user_encryption_key)?;
        let decrypted_description: Option<String> = if let Some(ref description) = spell.description { if description.is_empty() { None } else { Some(decrypt_data_with_user_key(description, &user_encryption_key)?) } } else { None };
        let decrypted_appearance: Option<String> = if let Some(ref appearance) = spell.appearance { if appearance.is_empty() { None } else { Some(decrypt_data_with_user_key(appearance, &user_encryption_key)?) } } else { None };
        let decrypted_tags: Option<String> = if let Some(ref tags) = spell.tags { if tags.is_empty() { None } else { Some(decrypt_data_with_user_key(tags, &user_encryption_key)?) } } else { None };
        let decrypted_power_level: Option<String> = if let Some(ref power_level) = spell.power_level { if power_level.is_empty() { None } else { Some(decrypt_data_with_user_key(power_level, &user_encryption_key)?) } } else { None };
        let decrypted_components: Option<String> = if let Some(ref components) = spell.components { if components.is_empty() { None } else { Some(decrypt_data_with_user_key(components, &user_encryption_key)?) } } else { None };
        let decrypted_limitations: Option<String> = if let Some(ref limitations) = spell.limitations { if limitations.is_empty() { None } else { Some(decrypt_data_with_user_key(limitations, &user_encryption_key)?) } } else { None };
        let decrypted_notes: Option<String> = if let Some(ref notes) = spell.notes { if notes.is_empty() { None } else { Some(decrypt_data_with_user_key(notes, &user_encryption_key)?) } } else { None };
        spells.push(BookSpellsTable {
            spell_id: spell.spell_id, book_id: spell.book_id,
            user_id: spell.user_id, name: decrypted_name,
            name_hash: spell.name_hash, description: decrypted_description,
            appearance: decrypted_appearance, tags: decrypted_tags,
            power_level: decrypted_power_level, components: decrypted_components,
            limitations: decrypted_limitations, notes: decrypted_notes,
            last_update: spell.last_update,
        });
    }

    let mut spell_tags: Vec<BookSpellTagsTable> = Vec::with_capacity(encrypted_spell_tags.len());
    for spell_tag in encrypted_spell_tags {
        let decrypted_name: String = decrypt_data_with_user_key(&spell_tag.name, &user_encryption_key)?;
        spell_tags.push(BookSpellTagsTable {
            tag_id: spell_tag.tag_id, book_id: spell_tag.book_id,
            user_id: spell_tag.user_id, name: decrypted_name,
            name_hash: spell_tag.name_hash, color: spell_tag.color,
            last_update: spell_tag.last_update,
        });
    }

    Ok(CompleteBook {
        erit_books, act_summaries, ai_guide_line, chapters, chapter_contents,
        chapter_infos, characters, character_attributes, guide_line, incidents,
        issues, locations, plot_points, worlds, world_elements, location_elements,
        location_sub_elements, book_tools, spells, spell_tags,
    })
}
