use rusqlite::Connection;

use crate::crypto::encryption::encrypt_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::CompleteBook;
use crate::domains::chapter::repo as chapter_repo;
use crate::domains::character::repo as character_repo;
use crate::domains::character::repo::SyncCharacterData;
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::chapter_content::repo as chapter_content_repo;
use crate::domains::world::repo as world_repo;
use crate::error::{AppError, AppResult};
use crate::shared::types::Lang;

/// Saves a complete book with all its associated data to the local database.
/// This method encrypts all sensitive data using the user's encryption key before storing.
/// It processes and inserts all book components including chapters, incidents, plot points,
/// chapter contents, chapter infos, characters, character attributes, locations, location elements,
/// location sub-elements, worlds, world elements, act summaries, AI guidelines, guidelines, and issues.
/// * `conn` - Database connection
/// * `user_id` - The unique identifier of the user who owns the book
/// * `data` - The complete book data structure containing all book components to save
/// * `lang` - The language code for localization
/// Returns true if all data was saved successfully, false otherwise.
pub fn save_complete_book(conn: &Connection, user_id: &str, data: &CompleteBook, lang: Lang) -> AppResult<bool> {
    let user_encryption_key: String = get_user_encryption_key(user_id)?;

    let book_data = data.erit_books.first()
        .ok_or_else(|| AppError::Validation("No book data to download.".to_string()))?;
    let encrypted_book_title: String = encrypt_data_with_user_key(&book_data.title, &user_encryption_key)?;
    let encrypted_book_sub_title: Option<String> = if let Some(ref sub_title) = book_data.sub_title { Some(encrypt_data_with_user_key(sub_title, &user_encryption_key)?) } else { None };
    let encrypted_book_summary: Option<String> = if let Some(ref summary) = book_data.summary { Some(encrypt_data_with_user_key(summary, &user_encryption_key)?) } else { None };
    let encrypted_book_cover_image: Option<String> = if let Some(ref cover_image) = book_data.cover_image { Some(encrypt_data_with_user_key(cover_image, &user_encryption_key)?) } else { None };

    let book_inserted: bool = book_repo::insert_sync_book(conn, &book_data.book_id, user_id, &book_data.book_type, &encrypted_book_title, &book_data.hashed_title, encrypted_book_sub_title.as_deref(), book_data.hashed_sub_title.as_deref(), encrypted_book_summary.as_deref(), book_data.serie_id, book_data.desired_release_date.as_deref(), book_data.desired_word_count, book_data.words_count, encrypted_book_cover_image.as_deref(), book_data.last_update, lang)?;
    if !book_inserted { return Ok(false); }

    for chapter in &data.chapters {
        let encrypted_chapter_title: String = encrypt_data_with_user_key(&chapter.title, &user_encryption_key)?;
        let chapter_inserted: bool = chapter_repo::insert_sync_chapter(conn, &chapter.chapter_id, &chapter.book_id, user_id, &encrypted_chapter_title, Some(&chapter.hashed_title), None, Some(chapter.chapter_order), chapter.last_update, lang)?;
        if !chapter_inserted { return Ok(false); }
    }

    for incident in &data.incidents {
        let encrypted_incident_title: String = encrypt_data_with_user_key(&incident.title, &user_encryption_key)?;
        let encrypted_incident_summary: Option<String> = if let Some(ref summary) = incident.summary { Some(encrypt_data_with_user_key(summary, &user_encryption_key)?) } else { None };
        let incident_inserted: bool = incident_repo::insert_sync_incident(conn, &incident.incident_id, user_id, &incident.book_id, &encrypted_incident_title, &incident.hashed_title, encrypted_incident_summary.as_deref(), incident.last_update, lang)?;
        if !incident_inserted { return Ok(false); }
    }

    for plot_point in &data.plot_points {
        let encrypted_plot_point_title: String = encrypt_data_with_user_key(&plot_point.title, &user_encryption_key)?;
        let encrypted_plot_point_summary: Option<String> = if let Some(ref summary) = plot_point.summary { Some(encrypt_data_with_user_key(summary, &user_encryption_key)?) } else { None };
        let plot_point_inserted: bool = plotpoint_repo::insert_sync_plot_point(conn, &plot_point.plot_point_id, &encrypted_plot_point_title, &plot_point.hashed_title, encrypted_plot_point_summary.as_deref(), plot_point.linked_incident_id.as_deref(), user_id, &plot_point.book_id, plot_point.last_update, lang)?;
        if !plot_point_inserted { return Ok(false); }
    }

    for chapter_content in &data.chapter_contents {
        let content_str: Option<String> = chapter_content.content.as_ref().map(|v| serde_json::to_string(v).unwrap_or_default());
        let encrypted_chapter_content: Option<String> = if let Some(ref content) = content_str { Some(encrypt_data_with_user_key(content, &user_encryption_key)?) } else { None };
        let words_count: i64 = chapter_content.words_count.unwrap_or(0);
        let time_on_it: i64 = chapter_content.time_on_it.unwrap_or(0);
        let chapter_content_inserted: bool = chapter_content_repo::insert_sync_chapter_content(conn, &chapter_content.content_id, &chapter_content.chapter_id, user_id, chapter_content.version, encrypted_chapter_content.as_deref(), words_count, time_on_it, chapter_content.last_update, lang)?;
        if !chapter_content_inserted { return Ok(false); }
    }

    for chapter_info in &data.chapter_infos {
        let encrypted_chapter_summary: Option<String> = if let Some(ref summary) = chapter_info.summary { Some(encrypt_data_with_user_key(summary, &user_encryption_key)?) } else { None };
        let encrypted_chapter_goal: Option<String> = if let Some(ref goal) = chapter_info.goal { Some(encrypt_data_with_user_key(goal, &user_encryption_key)?) } else { None };
        let chapter_info_inserted: bool = chapter_repo::insert_sync_chapter_info(conn, &chapter_info.chapter_info_id, &chapter_info.chapter_id, chapter_info.act_id, chapter_info.incident_id.as_deref(), chapter_info.plot_point_id.as_deref(), &chapter_info.book_id, user_id, encrypted_chapter_summary.as_deref(), encrypted_chapter_goal.as_deref(), chapter_info.last_update, lang)?;
        if !chapter_info_inserted { return Ok(false); }
    }

    for character in &data.characters {
        let character_data = SyncCharacterData {
            first_name: encrypt_data_with_user_key(&character.first_name, &user_encryption_key)?,
            last_name: if let Some(ref last_name) = character.last_name { Some(encrypt_data_with_user_key(last_name, &user_encryption_key)?) } else { None },
            nickname: if let Some(ref nickname) = character.nickname { Some(encrypt_data_with_user_key(nickname, &user_encryption_key)?) } else { None },
            age: if let Some(ref age) = character.age { Some(encrypt_data_with_user_key(age, &user_encryption_key)?) } else { None },
            gender: if let Some(ref gender) = character.gender { Some(encrypt_data_with_user_key(gender, &user_encryption_key)?) } else { None },
            species: if let Some(ref species) = character.species { Some(encrypt_data_with_user_key(species, &user_encryption_key)?) } else { None },
            nationality: if let Some(ref nationality) = character.nationality { Some(encrypt_data_with_user_key(nationality, &user_encryption_key)?) } else { None },
            status: if let Some(ref status) = character.status { Some(encrypt_data_with_user_key(status, &user_encryption_key)?) } else { None },
            category: encrypt_data_with_user_key(&character.category, &user_encryption_key)?,
            title: if let Some(ref title) = character.title { Some(encrypt_data_with_user_key(title, &user_encryption_key)?) } else { None },
            image: if let Some(ref image) = character.image { Some(encrypt_data_with_user_key(image, &user_encryption_key)?) } else { None },
            role: if let Some(ref role) = character.role { Some(encrypt_data_with_user_key(role, &user_encryption_key)?) } else { None },
            biography: if let Some(ref biography) = character.biography { Some(encrypt_data_with_user_key(biography, &user_encryption_key)?) } else { None },
            history: if let Some(ref history) = character.history { Some(encrypt_data_with_user_key(history, &user_encryption_key)?) } else { None },
            speech_pattern: if let Some(ref speech_pattern) = character.speech_pattern { Some(encrypt_data_with_user_key(speech_pattern, &user_encryption_key)?) } else { None },
            catchphrase: if let Some(ref catchphrase) = character.catchphrase { Some(encrypt_data_with_user_key(catchphrase, &user_encryption_key)?) } else { None },
            residence: if let Some(ref residence) = character.residence { Some(encrypt_data_with_user_key(residence, &user_encryption_key)?) } else { None },
            notes: if let Some(ref notes) = character.notes { Some(encrypt_data_with_user_key(notes, &user_encryption_key)?) } else { None },
            color: if let Some(ref color) = character.color { Some(encrypt_data_with_user_key(color, &user_encryption_key)?) } else { None },
        };
        let character_inserted: bool = character_repo::insert_sync_character(conn, &character.character_id, &character.book_id, user_id, &character_data, character.last_update, lang)?;
        if !character_inserted { return Ok(false); }
    }

    for character_attribute in &data.character_attributes {
        let encrypted_attribute_name: String = encrypt_data_with_user_key(&character_attribute.attribute_name, &user_encryption_key)?;
        let encrypted_attribute_value: String = encrypt_data_with_user_key(&character_attribute.attribute_value, &user_encryption_key)?;
        let character_attribute_inserted: bool = character_repo::insert_sync_character_attribute(conn, &character_attribute.attr_id, &character_attribute.character_id, user_id, &encrypted_attribute_name, &encrypted_attribute_value, character_attribute.last_update, lang)?;
        if !character_attribute_inserted { return Ok(false); }
    }

    for location in &data.locations {
        let encrypted_location_name: String = encrypt_data_with_user_key(&location.loc_name, &user_encryption_key)?;
        let location_inserted: bool = location_repo::insert_sync_location(conn, &location.loc_id, &location.book_id, user_id, &encrypted_location_name, &location.loc_original_name, location.last_update, lang)?;
        if !location_inserted { return Ok(false); }
    }

    for location_element in &data.location_elements {
        let encrypted_location_element_name: String = encrypt_data_with_user_key(&location_element.element_name, &user_encryption_key)?;
        let encrypted_location_element_description: Option<String> = if let Some(ref element_description) = location_element.element_description { Some(encrypt_data_with_user_key(element_description, &user_encryption_key)?) } else { None };
        let location_element_inserted: bool = location_repo::insert_sync_location_element(conn, &location_element.element_id, &location_element.location, user_id, &encrypted_location_element_name, &location_element.original_name, encrypted_location_element_description.as_deref(), location_element.last_update, lang)?;
        if !location_element_inserted { return Ok(false); }
    }

    for location_sub_element in &data.location_sub_elements {
        let encrypted_sub_element_name: String = encrypt_data_with_user_key(&location_sub_element.sub_elem_name, &user_encryption_key)?;
        let encrypted_sub_element_description: Option<String> = if let Some(ref sub_elem_description) = location_sub_element.sub_elem_description { Some(encrypt_data_with_user_key(sub_elem_description, &user_encryption_key)?) } else { None };
        let location_sub_element_inserted: bool = location_repo::insert_sync_location_sub_element(conn, &location_sub_element.sub_element_id, &location_sub_element.element_id, user_id, &encrypted_sub_element_name, &location_sub_element.original_name, encrypted_sub_element_description.as_deref(), location_sub_element.last_update, lang)?;
        if !location_sub_element_inserted { return Ok(false); }
    }

    for world in &data.worlds {
        let encrypted_world_name: String = encrypt_data_with_user_key(&world.name, &user_encryption_key)?;
        let encrypted_world_history: Option<String> = if let Some(ref history) = world.history { Some(encrypt_data_with_user_key(history, &user_encryption_key)?) } else { None };
        let encrypted_world_politics: Option<String> = if let Some(ref politics) = world.politics { Some(encrypt_data_with_user_key(politics, &user_encryption_key)?) } else { None };
        let encrypted_world_economy: Option<String> = if let Some(ref economy) = world.economy { Some(encrypt_data_with_user_key(economy, &user_encryption_key)?) } else { None };
        let encrypted_world_religion: Option<String> = if let Some(ref religion) = world.religion { Some(encrypt_data_with_user_key(religion, &user_encryption_key)?) } else { None };
        let encrypted_world_languages: Option<String> = if let Some(ref languages) = world.languages { Some(encrypt_data_with_user_key(languages, &user_encryption_key)?) } else { None };
        let world_inserted: bool = world_repo::insert_sync_world(conn, &world.world_id, &encrypted_world_name, &world.hashed_name, user_id, &world.book_id, encrypted_world_history.as_deref(), encrypted_world_politics.as_deref(), encrypted_world_economy.as_deref(), encrypted_world_religion.as_deref(), encrypted_world_languages.as_deref(), world.last_update, lang)?;
        if !world_inserted { return Ok(false); }
    }

    for world_element in &data.world_elements {
        let encrypted_world_element_name: String = encrypt_data_with_user_key(&world_element.name, &user_encryption_key)?;
        let encrypted_world_element_description: Option<String> = if let Some(ref description) = world_element.description { Some(encrypt_data_with_user_key(description, &user_encryption_key)?) } else { None };
        let world_element_inserted: bool = world_repo::insert_sync_world_element(conn, &world_element.element_id, &world_element.world_id, user_id, world_element.element_type, &encrypted_world_element_name, &world_element.original_name, encrypted_world_element_description.as_deref(), world_element.last_update, lang)?;
        if !world_element_inserted { return Ok(false); }
    }

    for act_summary in &data.act_summaries {
        let encrypted_act_summary: Option<String> = if let Some(ref summary) = act_summary.summary { Some(encrypt_data_with_user_key(summary, &user_encryption_key)?) } else { None };
        let act_summary_inserted: bool = act_repo::insert_sync_act_summary(conn, &act_summary.act_sum_id, &act_summary.book_id, user_id, act_summary.act_index, encrypted_act_summary.as_deref(), act_summary.last_update, lang)?;
        if !act_summary_inserted { return Ok(false); }
    }

    for ai_guideline in &data.ai_guide_line {
        let encrypted_global_resume: Option<String> = if let Some(ref global_resume) = ai_guideline.global_resume { Some(encrypt_data_with_user_key(global_resume, &user_encryption_key)?) } else { None };
        let encrypted_themes: Option<String> = if let Some(ref themes) = ai_guideline.themes { Some(encrypt_data_with_user_key(themes, &user_encryption_key)?) } else { None };
        let encrypted_tone: Option<String> = if let Some(ref tone) = ai_guideline.tone { Some(encrypt_data_with_user_key(tone, &user_encryption_key)?) } else { None };
        let encrypted_atmosphere: Option<String> = if let Some(ref atmosphere) = ai_guideline.atmosphere { Some(encrypt_data_with_user_key(atmosphere, &user_encryption_key)?) } else { None };
        let encrypted_current_resume: Option<String> = if let Some(ref current_resume) = ai_guideline.current_resume { Some(encrypt_data_with_user_key(current_resume, &user_encryption_key)?) } else { None };
        let ai_guideline_inserted: bool = guideline_repo::insert_sync_ai_guide_line(conn, user_id, &ai_guideline.book_id, encrypted_global_resume.as_deref(), encrypted_themes.as_deref(), ai_guideline.verbe_tense, ai_guideline.narrative_type, ai_guideline.langue, ai_guideline.dialogue_type, encrypted_tone.as_deref(), encrypted_atmosphere.as_deref(), encrypted_current_resume.as_deref(), ai_guideline.last_update, lang)?;
        if !ai_guideline_inserted { return Ok(false); }
    }

    for guideline in &data.guide_line {
        let encrypted_tone: Option<String> = if let Some(ref tone) = guideline.tone { Some(encrypt_data_with_user_key(tone, &user_encryption_key)?) } else { None };
        let encrypted_atmosphere: Option<String> = if let Some(ref atmosphere) = guideline.atmosphere { Some(encrypt_data_with_user_key(atmosphere, &user_encryption_key)?) } else { None };
        let encrypted_writing_style: Option<String> = if let Some(ref writing_style) = guideline.writing_style { Some(encrypt_data_with_user_key(writing_style, &user_encryption_key)?) } else { None };
        let encrypted_themes: Option<String> = if let Some(ref themes) = guideline.themes { Some(encrypt_data_with_user_key(themes, &user_encryption_key)?) } else { None };
        let encrypted_symbolism: Option<String> = if let Some(ref symbolism) = guideline.symbolism { Some(encrypt_data_with_user_key(symbolism, &user_encryption_key)?) } else { None };
        let encrypted_motifs: Option<String> = if let Some(ref motifs) = guideline.motifs { Some(encrypt_data_with_user_key(motifs, &user_encryption_key)?) } else { None };
        let encrypted_narrative_voice: Option<String> = if let Some(ref narrative_voice) = guideline.narrative_voice { Some(encrypt_data_with_user_key(narrative_voice, &user_encryption_key)?) } else { None };
        let encrypted_pacing: Option<String> = if let Some(ref pacing) = guideline.pacing { Some(encrypt_data_with_user_key(pacing, &user_encryption_key)?) } else { None };
        let encrypted_intended_audience: Option<String> = if let Some(ref intended_audience) = guideline.intended_audience { Some(encrypt_data_with_user_key(intended_audience, &user_encryption_key)?) } else { None };
        let encrypted_key_messages: Option<String> = if let Some(ref key_messages) = guideline.key_messages { Some(encrypt_data_with_user_key(key_messages, &user_encryption_key)?) } else { None };
        let guideline_inserted: bool = guideline_repo::insert_sync_guide_line(conn, user_id, &guideline.book_id, encrypted_tone.as_deref(), encrypted_atmosphere.as_deref(), encrypted_writing_style.as_deref(), encrypted_themes.as_deref(), encrypted_symbolism.as_deref(), encrypted_motifs.as_deref(), encrypted_narrative_voice.as_deref(), encrypted_pacing.as_deref(), encrypted_intended_audience.as_deref(), encrypted_key_messages.as_deref(), guideline.last_update, lang)?;
        if !guideline_inserted { return Ok(false); }
    }

    for issue in &data.issues {
        let encrypted_issue_name: String = encrypt_data_with_user_key(&issue.name, &user_encryption_key)?;
        let issue_inserted: bool = issue_repo::insert_sync_issue(conn, &issue.issue_id, user_id, &issue.book_id, &encrypted_issue_name, &issue.hashed_issue_name, issue.last_update, lang)?;
        if !issue_inserted { return Ok(false); }
    }

    for book_tool in &data.book_tools {
        let book_tool_inserted: bool = book_repo::insert_sync_book_tools(conn, &book_tool.book_id, user_id, book_tool.characters_enabled, book_tool.worlds_enabled, book_tool.locations_enabled, book_tool.spells_enabled, book_tool.last_update, lang);
        if !book_tool_inserted { return Ok(false); }
    }

    for spell_tag in &data.spell_tags {
        let encrypted_tag_name: String = encrypt_data_with_user_key(&spell_tag.name, &user_encryption_key)?;
        let spell_tag_inserted: bool = spell_tag_repo::insert_sync_spell_tag(conn, &spell_tag.tag_id, &spell_tag.book_id, user_id, &encrypted_tag_name, &spell_tag.name_hash, spell_tag.color.as_deref(), spell_tag.last_update, lang)?;
        if !spell_tag_inserted { return Ok(false); }
    }

    for spell in &data.spells {
        let encrypted_name: String = encrypt_data_with_user_key(&spell.name, &user_encryption_key)?;
        let encrypted_description: Option<String> = if let Some(ref description) = spell.description { Some(encrypt_data_with_user_key(description, &user_encryption_key)?) } else { None };
        let encrypted_appearance: Option<String> = if let Some(ref appearance) = spell.appearance { Some(encrypt_data_with_user_key(appearance, &user_encryption_key)?) } else { None };
        let encrypted_tags: Option<String> = if let Some(ref tags) = spell.tags { Some(encrypt_data_with_user_key(tags, &user_encryption_key)?) } else { None };
        let encrypted_power_level: Option<String> = if let Some(ref power_level) = spell.power_level { Some(encrypt_data_with_user_key(power_level, &user_encryption_key)?) } else { None };
        let encrypted_components: Option<String> = if let Some(ref components) = spell.components { Some(encrypt_data_with_user_key(components, &user_encryption_key)?) } else { None };
        let encrypted_limitations: Option<String> = if let Some(ref limitations) = spell.limitations { Some(encrypt_data_with_user_key(limitations, &user_encryption_key)?) } else { None };
        let encrypted_notes: Option<String> = if let Some(ref notes) = spell.notes { Some(encrypt_data_with_user_key(notes, &user_encryption_key)?) } else { None };
        let spell_inserted: bool = spell_repo::insert_sync_spell(conn, &spell.spell_id, &spell.book_id, user_id, &encrypted_name, &spell.name_hash, encrypted_description.as_deref(), encrypted_appearance.as_deref(), encrypted_tags.as_deref(), encrypted_power_level.as_deref(), encrypted_components.as_deref(), encrypted_limitations.as_deref(), encrypted_notes.as_deref(), spell.last_update, lang)?;
        if !spell_inserted { return Ok(false); }
    }

    Ok(true)
}
