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

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

pub struct BookQuery {
    pub book_id: String,
    pub book_type: String,
    pub author_id: String,
    pub title: String,
    pub sub_title: Option<String>,
    pub summary: Option<String>,
    pub serie_id: Option<i64>,
    pub desired_release_date: Option<String>,
    pub desired_word_count: Option<i64>,
    pub words_count: Option<i64>,
    pub cover_image: Option<String>,
}

#[derive(Serialize, Deserialize)]
pub struct EritBooksTable {
    pub book_id: String,
    #[serde(rename = "type")]
    pub book_type: String,
    pub author_id: String,
    pub title: String,
    pub hashed_title: String,
    pub sub_title: Option<String>,
    pub hashed_sub_title: Option<String>,
    pub summary: Option<String>,
    pub serie_id: Option<i64>,
    pub desired_release_date: Option<String>,
    pub desired_word_count: Option<i64>,
    pub words_count: Option<i64>,
    pub last_update: i64,
    pub cover_image: Option<String>,
}

pub struct SyncedBookResult {
    pub book_id: String,
    pub book_type: String,
    pub title: String,
    pub sub_title: Option<String>,
    pub last_update: i64,
}


#[derive(Serialize, Deserialize)]
pub struct BookToolsTable {
    pub book_id: String,
    pub user_id: String,
    pub characters_enabled: i64,
    pub worlds_enabled: i64,
    pub locations_enabled: i64,
    pub spells_enabled: i64,
    pub last_update: i64,
}

pub struct SyncedBookToolsResult {
    pub last_update: i64,
    pub characters_enabled: i64,
    pub worlds_enabled: i64,
    pub locations_enabled: i64,
    pub spells_enabled: i64,
}

/// Retrieves all books for a user.
/// * `conn` - Database connection
/// * `user_id` - The user identifier
/// * `lang` - The language for error messages
/// Returns list of user's books.
pub fn fetch_books(conn: &Connection, user_id: &str, lang: Lang) -> AppResult<Vec<BookQuery>> {
    let mut statement = conn
        .prepare("SELECT book_id, type, author_id, title, sub_title, summary, serie_id, desired_release_date, desired_word_count, words_count, cover_image FROM erit_books WHERE author_id = ?1 ORDER BY book_id DESC")
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer la liste des livres.".to_string() } else { "Unable to retrieve book list.".to_string() }))?;

    let books = statement
        .query_map(params![user_id], |query_row| {
            Ok(BookQuery {
                book_id: query_row.get(0)?, book_type: query_row.get(1)?,
                author_id: query_row.get(2)?, title: query_row.get(3)?,
                sub_title: query_row.get(4)?, summary: query_row.get(5)?,
                serie_id: query_row.get(6)?, desired_release_date: query_row.get(7)?,
                desired_word_count: query_row.get(8)?, words_count: query_row.get(9)?,
                cover_image: query_row.get(10)?,
            })
        })
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer la liste des livres.".to_string() } else { "Unable to retrieve book list.".to_string() }))?
        .collect::<Result<Vec<_>, _>>()
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer la liste des livres.".to_string() } else { "Unable to retrieve book list.".to_string() }))?;

    Ok(books)
}

/// Updates a book's cover image.
/// * `conn` - Database connection
/// * `book_id` - The book identifier
/// * `cover_image_name` - The cover image file name
/// * `user_id` - The user identifier
/// * `last_update` - The update timestamp
/// * `lang` - The language for error messages
/// Returns true if the update was successful.

/// Retrieves a book by its identifier.
/// * `conn` - Database connection
/// * `book_id` - The book identifier
/// * `user_id` - The user identifier
/// * `lang` - The language for error messages
/// Returns the book information.
pub fn fetch_book(conn: &Connection, book_id: &str, user_id: &str, lang: Lang) -> AppResult<BookQuery> {
    let mut statement = conn
        .prepare("SELECT book_id, author_id, title, summary, sub_title, cover_image, desired_release_date, desired_word_count, words_count, serie_id, type FROM erit_books WHERE book_id=?1 AND author_id=?2")
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les informations du livre.".to_string() } else { "Unable to retrieve book information.".to_string() }))?;

    let book = statement
        .query_row(params![book_id, user_id], |query_row| {
            Ok(BookQuery {
                book_id: query_row.get(0)?, author_id: query_row.get(1)?,
                title: query_row.get(2)?, summary: query_row.get(3)?,
                sub_title: query_row.get(4)?, cover_image: query_row.get(5)?,
                desired_release_date: query_row.get(6)?, desired_word_count: query_row.get(7)?,
                words_count: query_row.get(8)?, serie_id: query_row.get(9)?,
                book_type: query_row.get(10)?,
            })
        })
        .map_err(|error| match error {
            rusqlite::Error::QueryReturnedNoRows => AppError::NotFound(if lang == Lang::Fr { "Livre non trouvé.".to_string() } else { "Book not found.".to_string() }),
            _ => AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les informations du livre.".to_string() } else { "Unable to retrieve book information.".to_string() }),
        })?;

    Ok(book)
}

/// Verifies if a book already exists for a user.
/// * `conn` - Database connection
/// * `hashed_title` - The hashed book title
/// * `hashed_sub_title` - The hashed book subtitle
/// * `user_id` - The user identifier
/// * `lang` - The language for error messages
/// Returns true if the book exists.
pub fn verify_book_exist(conn: &Connection, hashed_title: &str, hashed_sub_title: &str, user_id: &str, lang: Lang) -> AppResult<bool> {
    let mut statement = conn
        .prepare("SELECT book_id FROM erit_books WHERE hashed_title=?1 AND author_id=?2 AND hashed_sub_title=?3")
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de vérifier l'existence du livre.".to_string() } else { "Unable to verify book existence.".to_string() }))?;

    let exists = statement
        .exists(params![hashed_title, user_id, hashed_sub_title])
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de vérifier l'existence du livre.".to_string() } else { "Unable to verify book existence.".to_string() }))?;

    Ok(exists)
}

/// Inserts a new book into the database.
/// * `conn` - Database connection
/// * `book_id` - The book identifier
/// * `user_id` - The user identifier
/// * `encrypted_title` - The encrypted title
/// * `hashed_title` - The hashed title
/// * `encrypted_sub_title` - The encrypted subtitle
/// * `hashed_sub_title` - The hashed subtitle
/// * `encrypted_summary` - The encrypted summary
/// * `book_type` - The book type
/// * `serie` - The series identifier
/// * `publication_date` - The desired publication date
/// * `desired_word_count` - The desired word count
/// * `last_update` - The creation timestamp
/// * `lang` - The language for error messages
/// Returns the created book identifier.
pub fn insert_book(
    conn: &Connection, book_id: &str, user_id: &str, encrypted_title: &str, hashed_title: &str,
    encrypted_sub_title: &str, hashed_sub_title: &str, encrypted_summary: &str, book_type: &str,
    serie: i64, publication_date: Option<&str>, desired_word_count: i64, last_update: i64, lang: Lang,
) -> AppResult<String> {
    let insert_result = conn
        .execute("INSERT INTO erit_books (book_id, type, author_id, title, hashed_title, sub_title, hashed_sub_title, summary, serie_id, desired_release_date, desired_word_count, last_update) VALUES (?1,?2,?3,?4,?5,?6,?7,?8,?9,?10,?11,?12)", params![book_id, book_type, user_id, encrypted_title, hashed_title, encrypted_sub_title, hashed_sub_title, encrypted_summary, serie, publication_date, desired_word_count, last_update])
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible d'ajouter le livre.".to_string() } else { "Unable to add book.".to_string() }))?;

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

/// Retrieves a book's cover image.
/// * `conn` - Database connection
/// * `user_id` - The user identifier
/// * `book_id` - The book identifier
/// * `lang` - The language for error messages
/// Returns the cover information.

/// Updates a book's basic information.
/// * `conn` - Database connection
/// * `user_id` - The user identifier
/// * `title` - The new title
/// * `hashed_title` - The hashed title
/// * `sub_title` - The new subtitle
/// * `hashed_sub_title` - The hashed subtitle
/// * `summary` - The new summary
/// * `publication_date` - The new publication date
/// * `word_count` - The new desired word count
/// * `book_id` - The book identifier
/// * `last_update` - The update timestamp
/// * `lang` - The language for error messages
/// Returns true if the update was successful.
pub fn update_book_basic_information(
    conn: &Connection, user_id: &str, title: &str, hashed_title: &str, sub_title: &str,
    hashed_sub_title: &str, summary: &str, publication_date: Option<&str>, word_count: i64,
    book_id: &str, last_update: i64, lang: Lang,
) -> AppResult<bool> {
    let update_result = conn
        .execute("UPDATE erit_books SET title=?1, hashed_title=?2, sub_title=?3, hashed_sub_title=?4, summary=?5, serie_id=?6, desired_release_date=?7, desired_word_count=?8, last_update=?9 WHERE author_id=?10 AND book_id=?11", params![title, hashed_title, sub_title, hashed_sub_title, summary, 0, publication_date, word_count, last_update, user_id, book_id])
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de mettre à jour les informations du livre.".to_string() } else { "Unable to update book information.".to_string() }))?;

    Ok(update_result > 0)
}

/// Deletes a book from the database.
/// * `conn` - Database connection
/// * `user_id` - The user identifier
/// * `book_id` - The book identifier to delete
/// * `lang` - The language for error messages
/// Returns true if the deletion was successful.
pub fn delete_book(conn: &Connection, user_id: &str, book_id: &str, lang: Lang) -> AppResult<bool> {
    let delete_result = conn
        .execute("DELETE FROM erit_books WHERE author_id=?1 AND book_id=?2", params![user_id, book_id])
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de supprimer le livre.".to_string() } else { "Unable to delete book.".to_string() }))?;

    Ok(delete_result > 0)
}

/// Retrieves all columns from erit_books table for a book.
/// * `conn` - Database connection
/// * `user_id` - The user identifier
/// * `book_id` - The book identifier
/// * `lang` - The language for error messages
/// Returns the complete book data.
pub fn fetch_erit_books_table(conn: &Connection, user_id: &str, book_id: &str, lang: Lang) -> AppResult<Vec<EritBooksTable>> {
    let mut statement = conn
        .prepare("SELECT book_id, type, author_id, title, hashed_title, sub_title, hashed_sub_title, summary, serie_id, desired_release_date, desired_word_count, words_count, cover_image, last_update FROM erit_books WHERE book_id=?1 AND author_id=?2")
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les informations du livre.".to_string() } else { "Unable to retrieve book information.".to_string() }))?;

    let rows = statement
        .query_map(params![book_id, user_id], |query_row| {
            Ok(EritBooksTable {
                book_id: query_row.get(0)?, book_type: query_row.get(1)?,
                author_id: query_row.get(2)?, title: query_row.get(3)?,
                hashed_title: query_row.get(4)?, sub_title: query_row.get(5)?,
                hashed_sub_title: query_row.get(6)?, summary: query_row.get(7)?,
                serie_id: query_row.get(8)?, desired_release_date: query_row.get(9)?,
                desired_word_count: query_row.get(10)?, words_count: query_row.get(11)?,
                cover_image: query_row.get(12)?, last_update: query_row.get(13)?,
            })
        })
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les informations du livre.".to_string() } else { "Unable to retrieve book information.".to_string() }))?
        .collect::<Result<Vec<_>, _>>()
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les informations du livre.".to_string() } else { "Unable to retrieve book information.".to_string() }))?;

    Ok(rows)
}

/// Retrieves synced books for a user.
/// * `conn` - Database connection
/// * `user_id` - The user identifier
/// * `lang` - The language for error messages
/// Returns list of books with sync information.
pub fn fetch_synced_books(conn: &Connection, user_id: &str, lang: Lang) -> AppResult<Vec<SyncedBookResult>> {
    let mut statement = conn
        .prepare("SELECT book_id, type, title, sub_title, last_update FROM erit_books WHERE author_id = ?1")
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les livres synchronisés.".to_string() } else { "Unable to retrieve synced books.".to_string() }))?;

    let rows = statement
        .query_map(params![user_id], |query_row| {
            Ok(SyncedBookResult {
                book_id: query_row.get(0)?, book_type: query_row.get(1)?,
                title: query_row.get(2)?, sub_title: query_row.get(3)?,
                last_update: query_row.get(4)?,
            })
        })
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les livres synchronisés.".to_string() } else { "Unable to retrieve synced books.".to_string() }))?
        .collect::<Result<Vec<_>, _>>()
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les livres synchronisés.".to_string() } else { "Unable to retrieve synced books.".to_string() }))?;

    Ok(rows)
}

/// Inserts a synced book from the server.
/// * `conn` - Database connection
/// * `book_id` - The book identifier
/// * `user_id` - The user identifier
/// * `book_type` - The book type
/// * `title` - The encrypted title
/// * `hashed_title` - The hashed title
/// * `sub_title` - The encrypted subtitle
/// * `hashed_sub_title` - The hashed subtitle
/// * `summary` - The encrypted summary
/// * `serie_id` - The series identifier
/// * `desired_release_date` - The desired release date
/// * `desired_word_count` - The desired word count
/// * `words_count` - The current word count
/// * `cover_image` - The cover image file name
/// * `last_update` - The last update timestamp
/// * `lang` - The language for error messages
/// Returns true if the insertion was successful.
pub fn insert_sync_book(
    conn: &Connection, book_id: &str, user_id: &str, book_type: &str, title: &str,
    hashed_title: &str, sub_title: Option<&str>, hashed_sub_title: Option<&str>,
    summary: Option<&str>, serie_id: Option<i64>, desired_release_date: Option<&str>,
    desired_word_count: Option<i64>, words_count: Option<i64>, cover_image: Option<&str>,
    last_update: i64, lang: Lang,
) -> AppResult<bool> {
    let insert_result = conn
        .execute("INSERT INTO erit_books (book_id, author_id, type, title, hashed_title, sub_title, hashed_sub_title, summary, serie_id, desired_release_date, desired_word_count, words_count, cover_image, last_update) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14)", params![book_id, user_id, book_type, title, hashed_title, sub_title, hashed_sub_title, summary, serie_id, desired_release_date, desired_word_count, words_count, cover_image, last_update])
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible d'insérer le livre synchronisé.".to_string() } else { "Unable to insert synced book.".to_string() }))?;

    Ok(insert_result > 0)
}

/// Retrieves a complete book by its identifier (without author verification).
/// * `conn` - Database connection
/// * `book_id` - The book identifier
/// * `lang` - The language for error messages
/// Returns the complete book data.
pub fn fetch_complete_book_by_id(conn: &Connection, book_id: &str, lang: Lang) -> AppResult<Vec<EritBooksTable>> {
    let mut statement = conn
        .prepare("SELECT * FROM erit_books WHERE book_id = ?1")
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer le livre complet.".to_string() } else { "Unable to retrieve complete book.".to_string() }))?;

    let rows = statement
        .query_map(params![book_id], |query_row| {
            Ok(EritBooksTable {
                book_id: query_row.get(0)?, book_type: query_row.get(1)?,
                author_id: query_row.get(2)?, title: query_row.get(3)?,
                hashed_title: query_row.get(4)?, sub_title: query_row.get(5)?,
                hashed_sub_title: query_row.get(6)?, summary: query_row.get(7)?,
                serie_id: query_row.get(8)?, desired_release_date: query_row.get(9)?,
                desired_word_count: query_row.get(10)?, words_count: query_row.get(11)?,
                cover_image: query_row.get(12)?, last_update: query_row.get(13)?,
            })
        })
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer le livre complet.".to_string() } else { "Unable to retrieve complete book.".to_string() }))?
        .collect::<Result<Vec<_>, _>>()
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer le livre complet.".to_string() } else { "Unable to retrieve complete book.".to_string() }))?;

    Ok(rows)
}

/// Retrieves the book tools settings for a user and book.
/// * `conn` - Database connection
/// * `user_id` - The user identifier
/// * `book_id` - The book identifier
/// * `lang` - The language for error messages
/// Returns the book tools settings or None if not found.
pub fn fetch_book_tools(conn: &Connection, user_id: &str, book_id: &str, lang: Lang) -> AppResult<Option<BookToolsTable>> {
    let mut statement = conn
        .prepare("SELECT book_id, user_id, characters_enabled, worlds_enabled, locations_enabled, spells_enabled, last_update FROM book_tools WHERE user_id=?1 AND book_id=?2")
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les paramètres des outils.".to_string() } else { "Unable to fetch tools settings.".to_string() }))?;

    let result = statement
        .query_row(params![user_id, book_id], |query_row| {
            Ok(BookToolsTable {
                book_id: query_row.get(0)?, user_id: query_row.get(1)?,
                characters_enabled: query_row.get(2)?, worlds_enabled: query_row.get(3)?,
                locations_enabled: query_row.get(4)?, spells_enabled: query_row.get(5)?,
                last_update: query_row.get(6)?,
            })
        });

    match result {
        Ok(row) => Ok(Some(row)),
        Err(rusqlite::Error::QueryReturnedNoRows) => Ok(None),
        Err(_) => Err(AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les paramètres des outils.".to_string() } else { "Unable to fetch tools settings.".to_string() })),
    }
}

/// Updates a book tool setting. If no row exists, inserts a new one.
/// * `conn` - Database connection
/// * `user_id` - The user identifier
/// * `book_id` - The book identifier
/// * `tool_name` - The tool column name (characters_enabled, worlds_enabled, locations_enabled, spells_enabled)
/// * `enabled` - Whether the tool is enabled
/// * `last_update` - The update timestamp
/// * `lang` - The language for error messages
/// Returns true if the update or insert was successful.
pub fn update_book_tool_setting(conn: &Connection, user_id: &str, book_id: &str, tool_name: &str, enabled: bool, last_update: i64, lang: Lang) -> AppResult<bool> {
    let enabled_value: i64 = if enabled { 1 } else { 0 };

    let update_query = format!("UPDATE book_tools SET {}=?1, last_update=?2 WHERE user_id=?3 AND book_id=?4", tool_name);
    let update_result = conn
        .execute(&update_query, params![enabled_value, last_update, user_id, book_id])
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de mettre à jour les paramètres des outils.".to_string() } else { "Unable to update tools settings.".to_string() }))?;

    if update_result > 0 {
        return Ok(true);
    }

    let characters_value: i64 = if tool_name == "characters_enabled" { enabled_value } else { 0 };
    let worlds_value: i64 = if tool_name == "worlds_enabled" { enabled_value } else { 0 };
    let locations_value: i64 = if tool_name == "locations_enabled" { enabled_value } else { 0 };
    let spells_value: i64 = if tool_name == "spells_enabled" { enabled_value } else { 0 };

    let insert_result = conn
        .execute("INSERT INTO book_tools (book_id, user_id, characters_enabled, worlds_enabled, locations_enabled, spells_enabled, last_update) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)", params![book_id, user_id, characters_value, worlds_value, locations_value, spells_value, last_update])
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de mettre à jour les paramètres des outils.".to_string() } else { "Unable to update tools settings.".to_string() }))?;

    Ok(insert_result > 0)
}

/// Upserts book tools settings during sync.
/// Inserts if not exists, updates if exists.
/// * `conn` - Database connection
/// * `book_id` - The book identifier
/// * `user_id` - The user identifier
/// * `characters_enabled` - Whether characters tool is enabled
/// * `worlds_enabled` - Whether worlds tool is enabled
/// * `locations_enabled` - Whether locations tool is enabled
/// * `spells_enabled` - Whether spells tool is enabled
/// * `last_update` - The last update timestamp
/// * `lang` - The language for error messages
/// Returns true if the upsert was successful, false on error.
pub fn insert_sync_book_tools(conn: &Connection, book_id: &str, user_id: &str, characters_enabled: i64, worlds_enabled: i64, locations_enabled: i64, spells_enabled: i64, last_update: i64, _lang: Lang) -> bool {
    let result = conn.execute("INSERT INTO book_tools (book_id, user_id, characters_enabled, worlds_enabled, locations_enabled, spells_enabled, last_update) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7) ON CONFLICT (book_id, user_id) DO UPDATE SET characters_enabled = excluded.characters_enabled, worlds_enabled = excluded.worlds_enabled, locations_enabled = excluded.locations_enabled, spells_enabled = excluded.spells_enabled, last_update = excluded.last_update", params![book_id, user_id, characters_enabled, worlds_enabled, locations_enabled, spells_enabled, last_update]);

    match result {
        Ok(_) => true,
        Err(error) => {
            eprintln!("[BookRepository] DB Error: {}", error);
            false
        }
    }
}

/// Retrieves synced book tools for a user and book.
/// * `conn` - Database connection
/// * `user_id` - The user identifier
/// * `book_id` - The book identifier
/// * `lang` - The language for error messages
/// Returns the synced book tools settings or None if not found.
pub fn fetch_synced_book_tools(conn: &Connection, user_id: &str, book_id: &str, lang: Lang) -> AppResult<Option<SyncedBookToolsResult>> {
    let mut statement = conn
        .prepare("SELECT last_update, characters_enabled, worlds_enabled, locations_enabled, spells_enabled FROM book_tools WHERE user_id = ?1 AND book_id = ?2")
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les paramètres des outils.".to_string() } else { "Unable to fetch tools settings.".to_string() }))?;

    let result = statement
        .query_row(params![user_id, book_id], |query_row| {
            Ok(SyncedBookToolsResult {
                last_update: query_row.get(0)?, characters_enabled: query_row.get(1)?,
                worlds_enabled: query_row.get(2)?, locations_enabled: query_row.get(3)?,
                spells_enabled: query_row.get(4)?,
            })
        });

    match result {
        Ok(row) => Ok(Some(row)),
        Err(rusqlite::Error::QueryReturnedNoRows) => Ok(None),
        Err(_) => Err(AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les paramètres des outils.".to_string() } else { "Unable to fetch tools settings.".to_string() })),
    }
}

/// Checks if a book exists for a user.
/// * `conn` - Database connection
/// * `user_id` - The user identifier
/// * `book_id` - The book identifier
/// * `lang` - The language for error messages
/// Returns true if the book exists, false otherwise.
pub fn is_book_exist(conn: &Connection, user_id: &str, book_id: &str, _lang: Lang) -> bool {
    let result = conn.prepare("SELECT 1 FROM erit_books WHERE author_id = ?1 AND book_id = ?2 LIMIT 1");

    match result {
        Ok(mut statement) => {
            statement.exists(params![user_id, book_id]).unwrap_or(false)
        }
        Err(error) => {
            eprintln!("DB Error: {}", error);
            false
        }
    }
}

/// Retrieves the series_id for a book from series_books table.
/// * `conn` - Database connection
/// * `book_id` - The book identifier
/// * `lang` - The language for error messages
/// Returns the series_id or None if book is not in a series.
pub fn fetch_book_series_id(conn: &Connection, book_id: &str, _lang: Lang) -> Option<String> {
    let result = conn.prepare("SELECT series_id FROM series_books WHERE book_id = ?1 LIMIT 1");

    match result {
        Ok(mut statement) => {
            let query_result = statement.query_row(params![book_id], |query_row| {
                query_row.get::<_, String>(0)
            });
            match query_result {
                Ok(series_id) => if series_id.is_empty() { None } else { Some(series_id) },
                Err(_) => None,
            }
        }
        Err(error) => {
            eprintln!("DB Error: {}", error);
            None
        }
    }
}
