use rusqlite::{params, Connection};

use crate::error::{AppError, AppResult};
use crate::shared::types::Lang;

pub struct BookWorldTable {
    pub world_id: String,
    pub name: String,
    pub hashed_name: String,
    pub author_id: String,
    pub book_id: String,
    pub history: Option<String>,
    pub politics: Option<String>,
    pub economy: Option<String>,
    pub religion: Option<String>,
    pub languages: Option<String>,
    pub last_update: i64,
}

pub struct BookWorldElementsTable {
    pub element_id: String,
    pub world_id: String,
    pub user_id: String,
    pub element_type: i64,
    pub name: String,
    pub original_name: String,
    pub description: Option<String>,
    pub last_update: i64,
}

pub struct SyncedWorldResult {
    pub world_id: String,
    pub book_id: String,
    pub name: String,
    pub last_update: i64,
}

pub struct SyncedWorldElementResult {
    pub element_id: String,
    pub world_id: String,
    pub name: String,
    pub last_update: i64,
}

pub struct WorldQuery {
    pub world_id: String,
    pub world_name: String,
    pub history: Option<String>,
    pub politics: Option<String>,
    pub economy: Option<String>,
    pub religion: Option<String>,
    pub languages: Option<String>,
    pub element_id: Option<String>,
    pub element_name: Option<String>,
    pub element_description: Option<String>,
    pub element_type: Option<i64>,
    pub series_world_id: Option<String>,
}

pub struct WorldElementValue {
    pub id: String,
    pub name: String,
    pub description: String,
    pub element_type: i64,
}

/// Checks if a world with the given name exists for a specific user and book.
/// * `conn` - Database connection
/// * `user_id` - The unique identifier of the user
/// * `book_id` - The unique identifier of the book
/// * `world_name` - The hashed name of the world to check
/// * `lang` - The language for error messages ("fr" or "en")
/// Returns true if the world exists, false otherwise.
pub fn check_world_exist(conn: &Connection, user_id: &str, book_id: &str, world_name: &str, lang: Lang) -> AppResult<bool> {
    let mut statement = conn
        .prepare("SELECT world_id FROM book_world WHERE author_id=?1 AND book_id=?2 AND hashed_name=?3")
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de v\u{00e9}rifier l'existence du monde.".to_string() } else { "Unable to verify world existence.".to_string() }))?;

    let exists = statement
        .exists(params![user_id, book_id, world_name])
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de v\u{00e9}rifier l'existence du monde.".to_string() } else { "Unable to verify world existence.".to_string() }))?;

    Ok(exists)
}

/// Inserts a new world into the database.
/// * `conn` - Database connection
/// * `world_id` - The unique identifier for the new world
/// * `user_id` - The unique identifier of the author
/// * `book_id` - The unique identifier of the book
/// * `encrypted_name` - The encrypted name of the world
/// * `hashed_name` - The hashed name of the world for uniqueness checks
/// * `last_update` - The creation timestamp
/// * `lang` - The language for error messages ("fr" or "en")
/// * `series_world_id` - The optional series world identifier
/// Returns the world ID if insertion was successful.
pub fn insert_new_world(
    conn: &Connection, world_id: &str, user_id: &str, book_id: &str, encrypted_name: &str,
    hashed_name: &str, last_update: i64, lang: Lang, series_world_id: Option<&str>,
) -> AppResult<String> {
    let insert_result = if let Some(series_id) = series_world_id {
        conn.execute("INSERT INTO book_world (world_id, author_id, book_id, name, hashed_name, series_world_id, last_update) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)", params![world_id, user_id, book_id, encrypted_name, hashed_name, series_id, last_update])
            .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible d'ajouter le monde.".to_string() } else { "Unable to add world.".to_string() }))?
    } else {
        conn.execute("INSERT INTO book_world (world_id, author_id, book_id, name, hashed_name, last_update) VALUES (?1, ?2, ?3, ?4, ?5, ?6)", params![world_id, user_id, book_id, encrypted_name, hashed_name, last_update])
            .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible d'ajouter le monde.".to_string() } else { "Unable to add world.".to_string() }))?
    };

    if insert_result > 0 {
        Ok(world_id.to_string())
    } else {
        Err(AppError::Internal(if lang == Lang::Fr { "Erreur lors de l'ajout du monde.".to_string() } else { "Error adding world.".to_string() }))
    }
}

/// Fetches all worlds and their elements for a specific user and book.
/// * `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 an array of world query results with joined element data.
pub fn fetch_worlds(conn: &Connection, user_id: &str, book_id: &str, lang: Lang) -> AppResult<Vec<WorldQuery>> {
    let mut statement = conn
        .prepare("SELECT world.world_id AS world_id, world.name AS world_name, world.history, world.politics, world.economy, world.religion, world.languages, element.element_id AS element_id, element.name AS element_name, element.description AS element_description, element.element_type, world.series_world_id FROM book_world AS world LEFT JOIN book_world_elements AS element ON world.world_id=element.world_id WHERE world.author_id=?1 AND world.book_id=?2")
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de r\u{00e9}cup\u{00e9}rer les mondes.".to_string() } else { "Unable to retrieve worlds.".to_string() }))?;

    let worlds = statement
        .query_map(params![user_id, book_id], |query_row| {
            Ok(WorldQuery {
                world_id: query_row.get(0)?, world_name: query_row.get(1)?,
                history: query_row.get(2)?, politics: query_row.get(3)?,
                economy: query_row.get(4)?, religion: query_row.get(5)?,
                languages: query_row.get(6)?, element_id: query_row.get(7)?,
                element_name: query_row.get(8)?, element_description: query_row.get(9)?,
                element_type: query_row.get(10)?, series_world_id: query_row.get(11)?,
            })
        })
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de r\u{00e9}cup\u{00e9}rer les mondes.".to_string() } else { "Unable to retrieve worlds.".to_string() }))?
        .collect::<Result<Vec<_>, _>>()
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de r\u{00e9}cup\u{00e9}rer les mondes.".to_string() } else { "Unable to retrieve worlds.".to_string() }))?;

    Ok(worlds)
}

/// Updates a world's data in the database.
/// * `conn` - Database connection
/// * `user_id` - The unique identifier of the author
/// * `world_id` - The unique identifier of the world to update
/// * `encrypt_name` - The new encrypted name
/// * `hashed_name` - The new hashed name
/// * `encrypt_history` - The new encrypted history
/// * `encrypt_politics` - The new encrypted politics
/// * `encrypt_economy` - The new encrypted economy
/// * `encrypt_religion` - The new encrypted religion
/// * `encrypt_languages` - The new encrypted languages
/// * `last_update` - The timestamp of the last update
/// * `lang` - The language for error messages ("fr" or "en")
/// * `series_world_id` - The optional series world identifier
/// Returns true if the update was successful, false otherwise.
pub fn update_world(
    conn: &Connection, user_id: &str, world_id: &str, encrypt_name: &str, hashed_name: &str,
    encrypt_history: &str, encrypt_politics: &str, encrypt_economy: &str, encrypt_religion: &str,
    encrypt_languages: &str, last_update: i64, lang: Lang, series_world_id: Option<&str>,
) -> AppResult<bool> {
    let update_result = if let Some(series_id) = series_world_id {
        conn.execute("UPDATE book_world SET name=?1, hashed_name=?2, history=?3, politics=?4, economy=?5, religion=?6, languages=?7, last_update=?8, series_world_id=?9 WHERE author_id=?10 AND world_id=?11", params![encrypt_name, hashed_name, encrypt_history, encrypt_politics, encrypt_economy, encrypt_religion, encrypt_languages, last_update, series_id, user_id, world_id])
            .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de mettre \u{00e0} jour le monde.".to_string() } else { "Unable to update world.".to_string() }))?
    } else {
        conn.execute("UPDATE book_world SET name=?1, hashed_name=?2, history=?3, politics=?4, economy=?5, religion=?6, languages=?7, last_update=?8 WHERE author_id=?9 AND world_id=?10", params![encrypt_name, hashed_name, encrypt_history, encrypt_politics, encrypt_economy, encrypt_religion, encrypt_languages, last_update, user_id, world_id])
            .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de mettre \u{00e0} jour le monde.".to_string() } else { "Unable to update world.".to_string() }))?
    };

    Ok(update_result > 0)
}

/// Updates multiple world elements in the database.
/// * `conn` - Database connection
/// * `user_id` - The unique identifier of the user
/// * `elements` - An array of world element values to update
/// * `last_update` - The timestamp of the last update
/// * `lang` - The language for error messages ("fr" or "en")
/// Returns true if all updates were successful, false otherwise.
pub fn update_world_elements(conn: &Connection, user_id: &str, elements: &[WorldElementValue], last_update: i64, lang: Lang) -> AppResult<bool> {
    for element in elements {
        let update_result = conn
            .execute("UPDATE book_world_elements SET name=?1, description=?2, element_type=?3, last_update=?4 WHERE user_id=?5 AND element_id=?6", params![element.name, element.description, element.element_type, last_update, user_id, element.id])
            .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de mettre \u{00e0} jour les \u{00e9}l\u{00e9}ments du monde.".to_string() } else { "Unable to update world elements.".to_string() }))?;

        if update_result == 0 {
            return Ok(false);
        }
    }

    Ok(true)
}

/// Checks if a world element with the given hashed name exists.
/// * `conn` - Database connection
/// * `world_num_id` - The unique identifier of the world
/// * `hashed_name` - The hashed name of the element to check
/// * `lang` - The language for error messages ("fr" or "en")
/// Returns true if the element exists, false otherwise.
pub fn check_element_exist(conn: &Connection, world_num_id: &str, hashed_name: &str, lang: Lang) -> AppResult<bool> {
    let mut statement = conn
        .prepare("SELECT element_id FROM book_world_elements WHERE world_id=?1 AND original_name=?2")
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de v\u{00e9}rifier l'existence de l'\u{00e9}l\u{00e9}ment.".to_string() } else { "Unable to verify element existence.".to_string() }))?;

    let exists = statement
        .exists(params![world_num_id, hashed_name])
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de v\u{00e9}rifier l'existence de l'\u{00e9}l\u{00e9}ment.".to_string() } else { "Unable to verify element existence.".to_string() }))?;

    Ok(exists)
}

/// Inserts a new world element into the database.
/// * `conn` - Database connection
/// * `user_id` - The unique identifier of the user
/// * `element_id` - The unique identifier for the new element
/// * `element_type` - The type of the element
/// * `world_id` - The unique identifier of the parent world
/// * `encrypted_name` - The encrypted name of the element
/// * `hashed_name` - The hashed name of the element for uniqueness checks
/// * `last_update` - The creation timestamp
/// * `lang` - The language for error messages ("fr" or "en")
/// Returns the element ID if insertion was successful.
pub fn insert_new_element(
    conn: &Connection, user_id: &str, element_id: &str, element_type: i64, world_id: &str,
    encrypted_name: &str, hashed_name: &str, last_update: i64, lang: Lang,
) -> AppResult<String> {
    let insert_result = conn
        .execute("INSERT INTO book_world_elements (element_id, world_id, user_id, name, original_name, element_type, last_update) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)", params![element_id, world_id, user_id, encrypted_name, hashed_name, element_type, last_update])
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible d'ajouter l'\u{00e9}l\u{00e9}ment.".to_string() } else { "Unable to add element.".to_string() }))?;

    if insert_result > 0 {
        Ok(element_id.to_string())
    } else {
        Err(AppError::Internal(if lang == Lang::Fr { "Erreur lors de l'ajout de l'\u{00e9}l\u{00e9}ment.".to_string() } else { "Error adding element.".to_string() }))
    }
}

/// Deletes a world element from the database.
/// * `conn` - Database connection
/// * `user_id` - The unique identifier of the user
/// * `element_id` - The unique identifier of the element to delete
/// * `lang` - The language for error messages ("fr" or "en")
/// Returns true if the deletion was successful, false otherwise.
pub fn delete_element(conn: &Connection, user_id: &str, element_id: &str, lang: Lang) -> AppResult<bool> {
    let delete_result = conn
        .execute("DELETE FROM book_world_elements WHERE user_id=?1 AND element_id=?2", params![user_id, element_id])
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de supprimer l'\u{00e9}l\u{00e9}ment.".to_string() } else { "Unable to delete element.".to_string() }))?;

    Ok(delete_result > 0)
}

/// Fetches all worlds for a specific user and book.
/// * `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 an array of book world table records.
pub fn fetch_book_worlds(conn: &Connection, user_id: &str, book_id: &str, lang: Lang) -> AppResult<Vec<BookWorldTable>> {
    let mut statement = conn
        .prepare("SELECT world_id, name, hashed_name, author_id, book_id, history, politics, economy, religion, languages, last_update FROM book_world WHERE author_id=?1 AND book_id=?2")
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de r\u{00e9}cup\u{00e9}rer les mondes.".to_string() } else { "Unable to retrieve worlds.".to_string() }))?;

    let worlds = statement
        .query_map(params![user_id, book_id], |query_row| {
            Ok(BookWorldTable {
                world_id: query_row.get(0)?, name: query_row.get(1)?,
                hashed_name: query_row.get(2)?, author_id: query_row.get(3)?,
                book_id: query_row.get(4)?, history: query_row.get(5)?,
                politics: query_row.get(6)?, economy: query_row.get(7)?,
                religion: query_row.get(8)?, languages: query_row.get(9)?,
                last_update: query_row.get(10)?,
            })
        })
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de r\u{00e9}cup\u{00e9}rer les mondes.".to_string() } else { "Unable to retrieve worlds.".to_string() }))?
        .collect::<Result<Vec<_>, _>>()
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de r\u{00e9}cup\u{00e9}rer les mondes.".to_string() } else { "Unable to retrieve worlds.".to_string() }))?;

    Ok(worlds)
}

pub fn fetch_all_world_elements_by_book(conn: &Connection, user_id: &str, book_id: &str, lang: Lang) -> AppResult<Vec<BookWorldElementsTable>> {
    let mut statement = conn
        .prepare("SELECT e.element_id, e.world_id, e.user_id, e.element_type, e.name, e.original_name, e.description, e.last_update FROM book_world_elements e INNER JOIN book_world w ON e.world_id = w.world_id AND e.user_id = w.author_id WHERE e.user_id=?1 AND w.book_id=?2")
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les éléments du monde.".to_string() } else { "Unable to retrieve world elements.".to_string() }))?;

    let elements = statement
        .query_map(params![user_id, book_id], |query_row| {
            Ok(BookWorldElementsTable {
                element_id: query_row.get(0)?, world_id: query_row.get(1)?,
                user_id: query_row.get(2)?, element_type: query_row.get(3)?,
                name: query_row.get(4)?, original_name: query_row.get(5)?,
                description: query_row.get(6)?, last_update: query_row.get(7)?,
            })
        })
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les éléments du monde.".to_string() } else { "Unable to retrieve world elements.".to_string() }))?
        .collect::<Result<Vec<_>, _>>()
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les éléments du monde.".to_string() } else { "Unable to retrieve world elements.".to_string() }))?;

    Ok(elements)
}

/// Fetches all synced worlds for a specific user.
/// * `conn` - Database connection
/// * `user_id` - The unique identifier of the user
/// * `lang` - The language for error messages ("fr" or "en")
/// Returns an array of synced world results.
pub fn fetch_synced_worlds(conn: &Connection, user_id: &str, lang: Lang) -> AppResult<Vec<SyncedWorldResult>> {
    let mut statement = conn
        .prepare("SELECT world_id, book_id, name, last_update FROM book_world WHERE author_id = ?1")
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de r\u{00e9}cup\u{00e9}rer les mondes synchronis\u{00e9}s.".to_string() } else { "Unable to retrieve synced worlds.".to_string() }))?;

    let synced_worlds = statement
        .query_map(params![user_id], |query_row| {
            Ok(SyncedWorldResult { world_id: query_row.get(0)?, book_id: query_row.get(1)?, name: query_row.get(2)?, last_update: query_row.get(3)? })
        })
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de r\u{00e9}cup\u{00e9}rer les mondes synchronis\u{00e9}s.".to_string() } else { "Unable to retrieve synced worlds.".to_string() }))?
        .collect::<Result<Vec<_>, _>>()
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de r\u{00e9}cup\u{00e9}rer les mondes synchronis\u{00e9}s.".to_string() } else { "Unable to retrieve synced worlds.".to_string() }))?;

    Ok(synced_worlds)
}

/// Fetches all synced world elements for a specific user.
/// * `conn` - Database connection
/// * `user_id` - The unique identifier of the user
/// * `lang` - The language for error messages ("fr" or "en")
/// Returns an array of synced world element results.
pub fn fetch_synced_world_elements(conn: &Connection, user_id: &str, lang: Lang) -> AppResult<Vec<SyncedWorldElementResult>> {
    let mut statement = conn
        .prepare("SELECT element_id, world_id, name, last_update FROM book_world_elements WHERE user_id = ?1")
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de r\u{00e9}cup\u{00e9}rer les \u{00e9}l\u{00e9}ments de monde synchronis\u{00e9}s.".to_string() } else { "Unable to retrieve synced world elements.".to_string() }))?;

    let synced_elements = statement
        .query_map(params![user_id], |query_row| {
            Ok(SyncedWorldElementResult { element_id: query_row.get(0)?, world_id: query_row.get(1)?, name: query_row.get(2)?, last_update: query_row.get(3)? })
        })
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de r\u{00e9}cup\u{00e9}rer les \u{00e9}l\u{00e9}ments de monde synchronis\u{00e9}s.".to_string() } else { "Unable to retrieve synced world elements.".to_string() }))?
        .collect::<Result<Vec<_>, _>>()
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de r\u{00e9}cup\u{00e9}rer les \u{00e9}l\u{00e9}ments de monde synchronis\u{00e9}s.".to_string() } else { "Unable to retrieve synced world elements.".to_string() }))?;

    Ok(synced_elements)
}

/// Inserts a synced world into the database.
/// * `conn` - Database connection
/// * `world_id` - The unique identifier for the world
/// * `name` - The encrypted name of the world
/// * `hashed_name` - The hashed name of the world
/// * `author_id` - The unique identifier of the author
/// * `book_id` - The unique identifier of the book
/// * `history` - The encrypted history (optional)
/// * `politics` - The encrypted politics (optional)
/// * `economy` - The encrypted economy (optional)
/// * `religion` - The encrypted religion (optional)
/// * `languages` - The encrypted languages (optional)
/// * `last_update` - The timestamp of the last update
/// * `lang` - The language for error messages ("fr" or "en")
/// Returns true if the insertion was successful, false otherwise.
pub fn insert_sync_world(
    conn: &Connection, world_id: &str, name: &str, hashed_name: &str, author_id: &str,
    book_id: &str, history: Option<&str>, politics: Option<&str>, economy: Option<&str>,
    religion: Option<&str>, languages: Option<&str>, last_update: i64, lang: Lang,
) -> AppResult<bool> {
    let insert_result = conn
        .execute("INSERT INTO book_world (world_id, name, hashed_name, author_id, book_id, history, politics, economy, religion, languages, last_update) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11)", params![world_id, name, hashed_name, author_id, book_id, history, politics, economy, religion, languages, last_update])
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible d'ins\u{00e9}rer le monde.".to_string() } else { "Unable to insert world.".to_string() }))?;

    Ok(insert_result > 0)
}

/// Inserts a synced world element into the database.
/// * `conn` - Database connection
/// * `element_id` - The unique identifier for the element
/// * `world_id` - The unique identifier of the parent world
/// * `user_id` - The unique identifier of the user
/// * `element_type` - The type of the element
/// * `name` - The encrypted name of the element
/// * `original_name` - The original hashed name
/// * `description` - The encrypted description (optional)
/// * `last_update` - The timestamp of the last update
/// * `lang` - The language for error messages ("fr" or "en")
/// Returns true if the insertion was successful, false otherwise.
pub fn insert_sync_world_element(
    conn: &Connection, element_id: &str, world_id: &str, user_id: &str, element_type: i64,
    name: &str, original_name: &str, description: Option<&str>, last_update: i64, lang: Lang,
) -> AppResult<bool> {
    let insert_result = conn
        .execute("INSERT INTO book_world_elements (element_id, world_id, user_id, element_type, name, original_name, description, last_update) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8)", params![element_id, world_id, user_id, element_type, name, original_name, description, last_update])
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible d'ins\u{00e9}rer l'\u{00e9}l\u{00e9}ment du monde.".to_string() } else { "Unable to insert world element.".to_string() }))?;

    Ok(insert_result > 0)
}

/// Fetches a complete world by its ID.
/// * `conn` - Database connection
/// * `id` - The unique identifier of the world
/// * `lang` - The language for error messages ("fr" or "en")
/// Returns an array of book world table records.
pub fn fetch_complete_world_by_id(conn: &Connection, id: &str, lang: Lang) -> AppResult<Vec<BookWorldTable>> {
    let mut statement = conn
        .prepare("SELECT world_id, name, hashed_name, author_id, book_id, history, politics, economy, religion, languages, last_update FROM book_world WHERE world_id = ?1")
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de r\u{00e9}cup\u{00e9}rer le monde complet.".to_string() } else { "Unable to retrieve complete world.".to_string() }))?;

    let worlds = statement
        .query_map(params![id], |query_row| {
            Ok(BookWorldTable {
                world_id: query_row.get(0)?, name: query_row.get(1)?,
                hashed_name: query_row.get(2)?, author_id: query_row.get(3)?,
                book_id: query_row.get(4)?, history: query_row.get(5)?,
                politics: query_row.get(6)?, economy: query_row.get(7)?,
                religion: query_row.get(8)?, languages: query_row.get(9)?,
                last_update: query_row.get(10)?,
            })
        })
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de r\u{00e9}cup\u{00e9}rer le monde complet.".to_string() } else { "Unable to retrieve complete world.".to_string() }))?
        .collect::<Result<Vec<_>, _>>()
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de r\u{00e9}cup\u{00e9}rer le monde complet.".to_string() } else { "Unable to retrieve complete world.".to_string() }))?;

    Ok(worlds)
}

/// Fetches a complete world element by its ID.
/// * `conn` - Database connection
/// * `id` - The unique identifier of the element
/// * `lang` - The language for error messages ("fr" or "en")
/// Returns an array of book world elements table records.
pub fn fetch_complete_world_element_by_id(conn: &Connection, id: &str, lang: Lang) -> AppResult<Vec<BookWorldElementsTable>> {
    let mut statement = conn
        .prepare("SELECT element_id, world_id, user_id, element_type, name, original_name, description, last_update FROM book_world_elements WHERE element_id = ?1")
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de r\u{00e9}cup\u{00e9}rer l'\u{00e9}l\u{00e9}ment de monde complet.".to_string() } else { "Unable to retrieve complete world element.".to_string() }))?;

    let elements = statement
        .query_map(params![id], |query_row| {
            Ok(BookWorldElementsTable {
                element_id: query_row.get(0)?, world_id: query_row.get(1)?,
                user_id: query_row.get(2)?, element_type: query_row.get(3)?,
                name: query_row.get(4)?, original_name: query_row.get(5)?,
                description: query_row.get(6)?, last_update: query_row.get(7)?,
            })
        })
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de r\u{00e9}cup\u{00e9}rer l'\u{00e9}l\u{00e9}ment de monde complet.".to_string() } else { "Unable to retrieve complete world element.".to_string() }))?
        .collect::<Result<Vec<_>, _>>()
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de r\u{00e9}cup\u{00e9}rer l'\u{00e9}l\u{00e9}ment de monde complet.".to_string() } else { "Unable to retrieve complete world element.".to_string() }))?;

    Ok(elements)
}

/// Updates a single world element's name and description.
/// * `conn` - Database connection
/// * `user_id` - The unique identifier of the user
/// * `element_id` - The unique identifier of the element to update
/// * `name` - The new encrypted name
/// * `description` - The new encrypted description
/// * `last_update` - The timestamp of the last update
/// * `lang` - The language for error messages ("fr" or "en")
/// Returns true if the update was successful, false otherwise.
pub fn update_world_element(
    conn: &Connection, user_id: &str, element_id: &str, name: &str, description: &str,
    last_update: i64, lang: Lang,
) -> AppResult<bool> {
    let update_result = conn
        .execute("UPDATE book_world_elements SET name = ?1, description = ?2, last_update = ?3 WHERE element_id = ?4 AND user_id = ?5", params![name, description, last_update, element_id, user_id])
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de mettre \u{00e0} jour l'\u{00e9}l\u{00e9}ment du monde.".to_string() } else { "Unable to update world element.".to_string() }))?;

    Ok(update_result > 0)
}

/// Checks if a world exists for a specific user and book.
/// * `conn` - Database connection
/// * `user_id` - The unique identifier of the user
/// * `book_id` - The unique identifier of the book
/// * `world_id` - The unique identifier of the world
/// * `lang` - The language for error messages ("fr" or "en")
/// Returns true if the world exists, false otherwise.
pub fn world_exist(conn: &Connection, user_id: &str, book_id: &str, world_id: &str, lang: Lang) -> AppResult<bool> {
    let mut statement = conn
        .prepare("SELECT 1 FROM book_world WHERE world_id=?1 AND author_id=?2 AND book_id=?3")
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de v\u{00e9}rifier l'existence du monde.".to_string() } else { "Unable to check world existence.".to_string() }))?;

    let exists = statement
        .exists(params![world_id, user_id, book_id])
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de v\u{00e9}rifier l'existence du monde.".to_string() } else { "Unable to check world existence.".to_string() }))?;

    Ok(exists)
}

/// Checks if a world element exists for a specific user and world.
/// * `conn` - Database connection
/// * `user_id` - The unique identifier of the user
/// * `world_id` - The unique identifier of the world
/// * `element_id` - The unique identifier of the element
/// * `lang` - The language for error messages ("fr" or "en")
/// Returns true if the element exists, false otherwise.
pub fn world_element_exist(conn: &Connection, user_id: &str, world_id: &str, element_id: &str, lang: Lang) -> AppResult<bool> {
    let mut statement = conn
        .prepare("SELECT 1 FROM book_world_elements WHERE element_id=?1 AND world_id=?2 AND user_id=?3")
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de v\u{00e9}rifier l'existence de l'\u{00e9}l\u{00e9}ment du monde.".to_string() } else { "Unable to check world element existence.".to_string() }))?;

    let exists = statement
        .exists(params![element_id, world_id, user_id])
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de v\u{00e9}rifier l'existence de l'\u{00e9}l\u{00e9}ment du monde.".to_string() } else { "Unable to check world element existence.".to_string() }))?;

    Ok(exists)
}
