use rusqlite::Connection;
use serde::{Deserialize, Serialize};

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

#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SeriesCharacterPropsPost {
    pub id: Option<String>,
    pub name: String,
    pub last_name: String,
    pub nickname: String,
    pub age: Option<i64>,
    pub gender: String,
    pub species: String,
    pub nationality: String,
    pub status: String,
    pub category: String,
    pub title: String,
    pub image: String,
    pub physical: Vec<NameItem>,
    pub psychological: Vec<NameItem>,
    pub relations: Vec<NameItem>,
    pub skills: Vec<NameItem>,
    pub weaknesses: Vec<NameItem>,
    pub strengths: Vec<NameItem>,
    pub goals: Vec<NameItem>,
    pub motivations: Vec<NameItem>,
    pub arc: Vec<NameItem>,
    pub secrets: Vec<NameItem>,
    pub fears: Vec<NameItem>,
    pub flaws: Vec<NameItem>,
    pub beliefs: Vec<NameItem>,
    pub conflicts: Vec<NameItem>,
    pub quotes: Vec<NameItem>,
    pub distinguishing_marks: Vec<NameItem>,
    pub items: Vec<NameItem>,
    pub affiliations: Vec<NameItem>,
    pub role: String,
    pub biography: Option<String>,
    pub history: Option<String>,
    pub speech_pattern: Option<String>,
    pub catchphrase: Option<String>,
    pub residence: Option<String>,
    pub notes: Option<String>,
    pub color: Option<String>,
}

#[derive(Deserialize)]
pub struct NameItem {
    pub name: String,
}

#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct SeriesCharacterListProps {
    pub id: String,
    pub name: String,
    pub last_name: String,
    pub nickname: String,
    pub age: Option<i64>,
    pub gender: String,
    pub species: String,
    pub nationality: String,
    pub status: String,
    pub title: String,
    pub category: String,
    pub image: String,
    pub role: String,
    pub biography: String,
    pub history: String,
    pub speech_pattern: String,
    pub catchphrase: String,
    pub residence: String,
    pub notes: String,
    pub color: String,
}

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

#[derive(Serialize)]
pub struct CharacterAttributesResponse {
    pub attributes: Vec<SeriesAttribute>,
}

/// Retrieves a list of characters for a specific series owned by a user.
/// * `conn` - Database connection
/// * `user_id` - The unique identifier of the user
/// * `series_id` - The unique identifier of the series
/// * `lang` - The language for error messages
/// Returns a list of decrypted series character properties.
pub fn get_character_list(conn: &Connection, user_id: &str, series_id: &str, lang: Lang) -> AppResult<Vec<SeriesCharacterListProps>> {
    let characters: Vec<repo::SeriesCharacterResult> = repo::fetch_characters(conn, user_id, series_id, lang)?;

    if characters.is_empty() {
        return Ok(vec![]);
    }

    let user_key: String = get_user_encryption_key(user_id)?;

    let mut character_list: Vec<SeriesCharacterListProps> = Vec::with_capacity(characters.len());
    for character in characters {
        let decrypted_name: String = if !character.first_name.is_empty() { decrypt_data_with_user_key(&character.first_name, &user_key)? } else { String::new() };
        let decrypted_last_name: String = if !character.last_name.is_empty() { decrypt_data_with_user_key(&character.last_name, &user_key)? } else { String::new() };
        let decrypted_nickname: String = if let Some(ref nickname) = character.nickname { if nickname.is_empty() { String::new() } else { decrypt_data_with_user_key(nickname, &user_key)? } } else { String::new() };
        let decrypted_age: Option<i64> = if let Some(ref age) = character.age { if age.is_empty() { None } else { Some(decrypt_data_with_user_key(age, &user_key)?.parse::<i64>().unwrap_or(0)) } } else { None };
        let decrypted_gender: String = if let Some(ref gender) = character.gender { if gender.is_empty() { String::new() } else { decrypt_data_with_user_key(gender, &user_key)? } } else { String::new() };
        let decrypted_species: String = if let Some(ref species) = character.species { if species.is_empty() { String::new() } else { decrypt_data_with_user_key(species, &user_key)? } } else { String::new() };
        let decrypted_nationality: String = if let Some(ref nationality) = character.nationality { if nationality.is_empty() { String::new() } else { decrypt_data_with_user_key(nationality, &user_key)? } } else { String::new() };
        let decrypted_status: String = if let Some(ref status) = character.status { if status.is_empty() { "alive".to_string() } else { decrypt_data_with_user_key(status, &user_key)? } } else { "alive".to_string() };
        let decrypted_title: String = if !character.title.is_empty() { decrypt_data_with_user_key(&character.title, &user_key)? } else { String::new() };
        let decrypted_category: String = if !character.category.is_empty() { decrypt_data_with_user_key(&character.category, &user_key)? } else { String::new() };
        let decrypted_image: String = if !character.image.is_empty() { decrypt_data_with_user_key(&character.image, &user_key)? } else { String::new() };
        let decrypted_role: String = if !character.role.is_empty() { decrypt_data_with_user_key(&character.role, &user_key)? } else { String::new() };
        let decrypted_biography: String = if !character.biography.is_empty() { decrypt_data_with_user_key(&character.biography, &user_key)? } else { String::new() };
        let decrypted_history: String = if !character.history.is_empty() { decrypt_data_with_user_key(&character.history, &user_key)? } else { String::new() };
        let decrypted_speech_pattern: String = if let Some(ref speech_pattern) = character.speech_pattern { if speech_pattern.is_empty() { String::new() } else { decrypt_data_with_user_key(speech_pattern, &user_key)? } } else { String::new() };
        let decrypted_catchphrase: String = if let Some(ref catchphrase) = character.catchphrase { if catchphrase.is_empty() { String::new() } else { decrypt_data_with_user_key(catchphrase, &user_key)? } } else { String::new() };
        let decrypted_residence: String = if let Some(ref residence) = character.residence { if residence.is_empty() { String::new() } else { decrypt_data_with_user_key(residence, &user_key)? } } else { String::new() };
        let decrypted_notes: String = if let Some(ref notes) = character.notes { if notes.is_empty() { String::new() } else { decrypt_data_with_user_key(notes, &user_key)? } } else { String::new() };
        let decrypted_color: String = if let Some(ref color) = character.color { if color.is_empty() { String::new() } else { decrypt_data_with_user_key(color, &user_key)? } } else { String::new() };

        character_list.push(SeriesCharacterListProps {
            id: character.character_id,
            name: decrypted_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: decrypted_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,
        });
    }

    Ok(character_list)
}

/// Adds a new character to a series with all its attributes.
/// * `conn` - Database connection
/// * `user_id` - The unique identifier of the user
/// * `character` - The character data to create
/// * `series_id` - The unique identifier of the series
/// * `lang` - The language for error messages
/// Returns the newly created character's ID.
pub fn add_new_character(conn: &Connection, user_id: &str, character: &SeriesCharacterPropsPost, series_id: &str, lang: Lang) -> AppResult<String> {
    let user_key: String = get_user_encryption_key(user_id)?;
    let character_id: String = create_unique_id(None);
    let last_update: i64 = timestamp_in_seconds();
    let encrypted_name: String = encrypt_data_with_user_key(&character.name, &user_key)?;
    let encrypted_last_name: Option<String> = if !character.last_name.is_empty() { Some(encrypt_data_with_user_key(&character.last_name, &user_key)?) } else { None };
    let encrypted_nickname: Option<String> = if !character.nickname.is_empty() { Some(encrypt_data_with_user_key(&character.nickname, &user_key)?) } else { None };
    let encrypted_age: Option<String> = if let Some(age) = character.age { Some(encrypt_data_with_user_key(&age.to_string(), &user_key)?) } else { None };
    let encrypted_gender: Option<String> = if !character.gender.is_empty() { Some(encrypt_data_with_user_key(&character.gender, &user_key)?) } else { None };
    let encrypted_species: Option<String> = if !character.species.is_empty() { Some(encrypt_data_with_user_key(&character.species, &user_key)?) } else { None };
    let encrypted_nationality: Option<String> = if !character.nationality.is_empty() { Some(encrypt_data_with_user_key(&character.nationality, &user_key)?) } else { None };
    let encrypted_status: Option<String> = if !character.status.is_empty() { Some(encrypt_data_with_user_key(&character.status, &user_key)?) } else { None };
    let encrypted_title: Option<String> = if !character.title.is_empty() { Some(encrypt_data_with_user_key(&character.title, &user_key)?) } else { None };
    let encrypted_category: Option<String> = if !character.category.is_empty() { Some(encrypt_data_with_user_key(&character.category, &user_key)?) } else { None };
    let encrypted_image: Option<String> = if !character.image.is_empty() { Some(encrypt_data_with_user_key(&character.image, &user_key)?) } else { None };
    let encrypted_role: Option<String> = if !character.role.is_empty() { Some(encrypt_data_with_user_key(&character.role, &user_key)?) } else { None };
    let encrypted_biography: Option<String> = if let Some(ref biography) = character.biography { if !biography.is_empty() { Some(encrypt_data_with_user_key(biography, &user_key)?) } else { None } } else { None };
    let encrypted_history: Option<String> = if let Some(ref history) = character.history { if !history.is_empty() { Some(encrypt_data_with_user_key(history, &user_key)?) } else { None } } else { None };
    let encrypted_speech_pattern: Option<String> = if let Some(ref speech_pattern) = character.speech_pattern { if !speech_pattern.is_empty() { Some(encrypt_data_with_user_key(speech_pattern, &user_key)?) } else { None } } else { None };
    let encrypted_catchphrase: Option<String> = if let Some(ref catchphrase) = character.catchphrase { if !catchphrase.is_empty() { Some(encrypt_data_with_user_key(catchphrase, &user_key)?) } else { None } } else { None };
    let encrypted_residence: Option<String> = if let Some(ref residence) = character.residence { if !residence.is_empty() { Some(encrypt_data_with_user_key(residence, &user_key)?) } else { None } } else { None };
    let encrypted_notes: Option<String> = if let Some(ref notes) = character.notes { if !notes.is_empty() { Some(encrypt_data_with_user_key(notes, &user_key)?) } else { None } } else { None };
    let encrypted_color: Option<String> = if let Some(ref color) = character.color { if !color.is_empty() { Some(encrypt_data_with_user_key(color, &user_key)?) } else { None } } else { None };

    repo::add_new_character(
        conn, user_id, &character_id, &encrypted_name,
        encrypted_last_name.as_deref(), encrypted_nickname.as_deref(), encrypted_age.as_deref(),
        encrypted_gender.as_deref(), encrypted_species.as_deref(), encrypted_nationality.as_deref(),
        encrypted_status.as_deref(), encrypted_title.as_deref(), encrypted_category.as_deref(),
        encrypted_image.as_deref(), encrypted_role.as_deref(), encrypted_biography.as_deref(),
        encrypted_history.as_deref(), encrypted_speech_pattern.as_deref(), encrypted_catchphrase.as_deref(),
        encrypted_residence.as_deref(), encrypted_notes.as_deref(), encrypted_color.as_deref(),
        series_id, last_update, lang,
    )?;

    // Insert array attributes
    for attribute_item in &character.physical { add_new_attribute(conn, &character_id, user_id, "physical", &attribute_item.name, lang)?; }
    for attribute_item in &character.psychological { add_new_attribute(conn, &character_id, user_id, "psychological", &attribute_item.name, lang)?; }
    for attribute_item in &character.relations { add_new_attribute(conn, &character_id, user_id, "relations", &attribute_item.name, lang)?; }
    for attribute_item in &character.skills { add_new_attribute(conn, &character_id, user_id, "skills", &attribute_item.name, lang)?; }
    for attribute_item in &character.weaknesses { add_new_attribute(conn, &character_id, user_id, "weaknesses", &attribute_item.name, lang)?; }
    for attribute_item in &character.strengths { add_new_attribute(conn, &character_id, user_id, "strengths", &attribute_item.name, lang)?; }
    for attribute_item in &character.goals { add_new_attribute(conn, &character_id, user_id, "goals", &attribute_item.name, lang)?; }
    for attribute_item in &character.motivations { add_new_attribute(conn, &character_id, user_id, "motivations", &attribute_item.name, lang)?; }
    for attribute_item in &character.arc { add_new_attribute(conn, &character_id, user_id, "arc", &attribute_item.name, lang)?; }
    for attribute_item in &character.secrets { add_new_attribute(conn, &character_id, user_id, "secrets", &attribute_item.name, lang)?; }
    for attribute_item in &character.fears { add_new_attribute(conn, &character_id, user_id, "fears", &attribute_item.name, lang)?; }
    for attribute_item in &character.flaws { add_new_attribute(conn, &character_id, user_id, "flaws", &attribute_item.name, lang)?; }
    for attribute_item in &character.beliefs { add_new_attribute(conn, &character_id, user_id, "beliefs", &attribute_item.name, lang)?; }
    for attribute_item in &character.conflicts { add_new_attribute(conn, &character_id, user_id, "conflicts", &attribute_item.name, lang)?; }
    for attribute_item in &character.quotes { add_new_attribute(conn, &character_id, user_id, "quotes", &attribute_item.name, lang)?; }
    for attribute_item in &character.distinguishing_marks { add_new_attribute(conn, &character_id, user_id, "distinguishingMarks", &attribute_item.name, lang)?; }
    for attribute_item in &character.items { add_new_attribute(conn, &character_id, user_id, "items", &attribute_item.name, lang)?; }
    for attribute_item in &character.affiliations { add_new_attribute(conn, &character_id, user_id, "affiliations", &attribute_item.name, lang)?; }

    Ok(character_id)
}

/// Updates an existing character's information and attributes.
/// * `conn` - Database connection
/// * `user_id` - The unique identifier of the user
/// * `character` - The updated character data
/// * `lang` - The language for error messages
/// Returns true if the update was successful.
pub fn update_character(conn: &Connection, user_id: &str, character: &SeriesCharacterPropsPost, lang: Lang) -> AppResult<bool> {
    let character_id: &str = character.id.as_deref().ok_or_else(|| {
        AppError::Internal(if lang == Lang::Fr { "ID du personnage requis.".to_string() } else { "Character ID required.".to_string() })
    })?;

    let exists: bool = repo::is_character_exist(conn, user_id, character_id, lang)?;
    if !exists {
        return Err(AppError::Internal(if lang == Lang::Fr { "Personnage non trouvé.".to_string() } else { "Character not found.".to_string() }));
    }

    let user_key: String = get_user_encryption_key(user_id)?;
    let last_update: i64 = timestamp_in_seconds();
    let encrypted_name: String = encrypt_data_with_user_key(&character.name, &user_key)?;
    let encrypted_last_name: Option<String> = if !character.last_name.is_empty() { Some(encrypt_data_with_user_key(&character.last_name, &user_key)?) } else { None };
    let encrypted_nickname: Option<String> = if !character.nickname.is_empty() { Some(encrypt_data_with_user_key(&character.nickname, &user_key)?) } else { None };
    let encrypted_age: Option<String> = if let Some(age) = character.age { Some(encrypt_data_with_user_key(&age.to_string(), &user_key)?) } else { None };
    let encrypted_gender: Option<String> = if !character.gender.is_empty() { Some(encrypt_data_with_user_key(&character.gender, &user_key)?) } else { None };
    let encrypted_species: Option<String> = if !character.species.is_empty() { Some(encrypt_data_with_user_key(&character.species, &user_key)?) } else { None };
    let encrypted_nationality: Option<String> = if !character.nationality.is_empty() { Some(encrypt_data_with_user_key(&character.nationality, &user_key)?) } else { None };
    let encrypted_status: Option<String> = if !character.status.is_empty() { Some(encrypt_data_with_user_key(&character.status, &user_key)?) } else { None };
    let encrypted_title: Option<String> = if !character.title.is_empty() { Some(encrypt_data_with_user_key(&character.title, &user_key)?) } else { None };
    let encrypted_category: Option<String> = if !character.category.is_empty() { Some(encrypt_data_with_user_key(&character.category, &user_key)?) } else { None };
    let encrypted_image: Option<String> = if !character.image.is_empty() { Some(encrypt_data_with_user_key(&character.image, &user_key)?) } else { None };
    let encrypted_role: Option<String> = if !character.role.is_empty() { Some(encrypt_data_with_user_key(&character.role, &user_key)?) } else { None };
    let encrypted_biography: Option<String> = if let Some(ref biography) = character.biography { if !biography.is_empty() { Some(encrypt_data_with_user_key(biography, &user_key)?) } else { None } } else { None };
    let encrypted_history: Option<String> = if let Some(ref history) = character.history { if !history.is_empty() { Some(encrypt_data_with_user_key(history, &user_key)?) } else { None } } else { None };
    let encrypted_speech_pattern: Option<String> = if let Some(ref speech_pattern) = character.speech_pattern { if !speech_pattern.is_empty() { Some(encrypt_data_with_user_key(speech_pattern, &user_key)?) } else { None } } else { None };
    let encrypted_catchphrase: Option<String> = if let Some(ref catchphrase) = character.catchphrase { if !catchphrase.is_empty() { Some(encrypt_data_with_user_key(catchphrase, &user_key)?) } else { None } } else { None };
    let encrypted_residence: Option<String> = if let Some(ref residence) = character.residence { if !residence.is_empty() { Some(encrypt_data_with_user_key(residence, &user_key)?) } else { None } } else { None };
    let encrypted_notes: Option<String> = if let Some(ref notes) = character.notes { if !notes.is_empty() { Some(encrypt_data_with_user_key(notes, &user_key)?) } else { None } } else { None };
    let encrypted_color: Option<String> = if let Some(ref color) = character.color { if !color.is_empty() { Some(encrypt_data_with_user_key(color, &user_key)?) } else { None } } else { None };

    repo::update_character(
        conn, user_id, character_id, &encrypted_name,
        encrypted_last_name.as_deref(), encrypted_nickname.as_deref(), encrypted_age.as_deref(),
        encrypted_gender.as_deref(), encrypted_species.as_deref(), encrypted_nationality.as_deref(),
        encrypted_status.as_deref(), encrypted_title.as_deref(), encrypted_category.as_deref(),
        encrypted_image.as_deref(), encrypted_role.as_deref(), encrypted_biography.as_deref(),
        encrypted_history.as_deref(), encrypted_speech_pattern.as_deref(), encrypted_catchphrase.as_deref(),
        encrypted_residence.as_deref(), encrypted_notes.as_deref(), encrypted_color.as_deref(),
        last_update, lang,
    )
}

/// Deletes a character from a series.
/// * `conn` - Database connection
/// * `user_id` - The unique identifier of the user
/// * `character_id` - The unique identifier of the character
/// * `deleted_at` - The timestamp of deletion
/// * `lang` - The language for error messages
/// Returns true if the deletion was successful.
pub fn delete_character(conn: &Connection, user_id: &str, character_id: &str, deleted_at: i64, lang: Lang) -> AppResult<bool> {
    let exists: bool = repo::is_character_exist(conn, user_id, character_id, lang)?;
    if !exists {
        return Err(AppError::Internal(if lang == Lang::Fr { "Personnage non trouvé.".to_string() } else { "Character not found.".to_string() }));
    }
    let deleted: bool = repo::delete_character(conn, user_id, character_id, lang)?;
    if deleted {
        tombstone_repo::insert(conn, character_id, "series_characters", character_id, None, user_id, deleted_at, lang)?;
    }
    Ok(deleted)
}

/// Adds a new attribute to a character.
/// * `conn` - Database connection
/// * `character_id` - The unique identifier of the character
/// * `user_id` - The unique identifier of the user
/// * `attribute_type` - The attribute type
/// * `name` - The attribute value
/// * `lang` - The language for error messages
/// Returns the attribute ID.
pub fn add_new_attribute(conn: &Connection, character_id: &str, user_id: &str, attribute_type: &str, name: &str, lang: Lang) -> AppResult<String> {
    let user_key: String = get_user_encryption_key(user_id)?;
    let attribute_id: String = create_unique_id(None);
    let last_update: i64 = timestamp_in_seconds();
    let encrypted_type: String = encrypt_data_with_user_key(attribute_type, &user_key)?;
    let encrypted_name: String = encrypt_data_with_user_key(name, &user_key)?;

    repo::insert_attribute(conn, &attribute_id, character_id, user_id, &encrypted_type, &encrypted_name, last_update, lang)?;

    Ok(attribute_id)
}

/// Deletes an attribute from a character.
/// * `conn` - Database connection
/// * `user_id` - The unique identifier of the user
/// * `attribute_id` - The unique identifier of the attribute
/// * `deleted_at` - The timestamp of deletion
/// * `lang` - The language for error messages
/// Returns true if the deletion was successful.
pub fn delete_attribute(conn: &Connection, user_id: &str, attribute_id: &str, deleted_at: i64, lang: Lang) -> AppResult<bool> {
    let deleted: bool = repo::delete_attribute(conn, user_id, attribute_id, lang)?;
    if deleted {
        tombstone_repo::insert(conn, attribute_id, "series_characters_attributes", attribute_id, None, user_id, deleted_at, lang)?;
    }
    Ok(deleted)
}

/// Gets all attributes for a character.
/// * `conn` - Database connection
/// * `user_id` - The unique identifier of the user
/// * `character_id` - The unique identifier of the character
/// * `lang` - The language for error messages
/// Returns the character's attributes.
pub fn get_character_attributes(conn: &Connection, user_id: &str, character_id: &str, lang: Lang) -> AppResult<CharacterAttributesResponse> {
    let user_key: String = get_user_encryption_key(user_id)?;
    let attributes_result: Vec<repo::SeriesCharacterAttributeResult> = repo::fetch_attributes(conn, character_id, user_id, lang)?;

    let mut attributes: Vec<SeriesAttribute> = Vec::with_capacity(attributes_result.len());
    for attr in attributes_result {
        let decrypted_name: String = decrypt_data_with_user_key(&attr.attribute_value, &user_key)?;
        attributes.push(SeriesAttribute {
            id: attr.attr_id,
            name: decrypted_name,
        });
    }

    Ok(CharacterAttributesResponse { attributes })
}
