use rusqlite::{params, Connection};

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

pub struct ChapterQueryResult {
    pub chapter_id: String,
    pub title: String,
    pub chapter_order: i64,
}

pub struct ActChapterQuery {
    pub chapter_info_id: i64,
    pub chapter_id: String,
    pub title: String,
    pub chapter_order: i64,
    pub act_id: i64,
    pub incident_id: Option<String>,
    pub plot_point_id: Option<String>,
    pub summary: String,
    pub goal: String,
}

pub struct ChapterStoryQueryResult {
    pub _chapter_info_id: i64,
    pub act_id: i64,
    pub summary: String,
    pub chapter_summary: String,
    pub chapter_goal: String,
    pub incident_id: Option<i64>,
    pub incident_title: Option<String>,
    pub incident_summary: Option<String>,
    pub plot_point_id: Option<i64>,
    pub plot_title: Option<String>,
    pub plot_summary: Option<String>,
}

pub struct LastChapterResult {
    pub chapter_id: String,
    pub version: i64,
}

pub struct BookChaptersTable {
    pub chapter_id: String,
    pub book_id: String,
    pub author_id: String,
    pub title: String,
    pub hashed_title: String,
    pub _words_count: Option<i64>,
    pub chapter_order: i64,
    pub last_update: i64,
}

pub struct BookChapterInfosTable {
    pub _chapter_info_id: String,
    pub chapter_id: String,
    pub _act_id: Option<i64>,
    pub _incident_id: Option<String>,
    pub _plot_point_id: Option<String>,
    pub _book_id: String,
    pub author_id: String,
    pub summary: Option<String>,
    pub goal: Option<String>,
    pub last_update: i64,
}

pub struct SyncedChapterResult {
    pub chapter_id: String,
    pub book_id: String,
    pub title: String,
    pub last_update: i64,
}

pub struct SyncedChapterInfoResult {
    pub chapter_info_id: String,
    pub chapter_id: Option<String>,
    pub _book_id: String,
    pub last_update: i64,
}

pub struct ChapterBookResult {
    pub title: String,
    pub chapter_order: i64,
    pub content: Option<String>,
}

pub struct ChapterExportInfoResult {
    pub chapter_id: String,
    pub title: String,
    pub chapter_order: i64,
    pub available_versions: String,
}

pub struct SelectedChapterContentResult {
    pub chapter_id: String,
    pub title: String,
    pub chapter_order: i64,
    pub content: String,
    pub _version: i64,
}

#[derive(serde::Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ChapterSelectionParam {
    pub chapter_id: String,
    pub version: i64,
}

/// Checks if a chapter name already exists for a book.
pub fn check_name_duplication(conn: &Connection, user_id: &str, book_id: &str, hashed_title: &str, lang: Lang) -> AppResult<bool> {
    let mut statement = conn
        .prepare("SELECT chapter_id FROM book_chapters WHERE author_id=?1 AND book_id=?2 AND hashed_title=?3")
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de vérifier la duplication du nom.".to_string() } else { "Unable to verify name duplication.".to_string() }))?;

    let exists = statement
        .exists(params![user_id, book_id, hashed_title])
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de vérifier la duplication du nom.".to_string() } else { "Unable to verify name duplication.".to_string() }))?;

    Ok(exists)
}

/// Inserts a new chapter into the database.
pub fn insert_chapter(conn: &Connection, chapter_id: &str, user_id: &str, book_id: &str, title: &str, hashed_title: &str, words_count: i64, chapter_order: i64, lang: Lang) -> AppResult<String> {
    let insert_result = conn
        .execute("INSERT INTO book_chapters (chapter_id, author_id, book_id, title, hashed_title, words_count, chapter_order, last_update) VALUES (?1,?2,?3,?4,?5,?6,?7,?8)", params![chapter_id, user_id, book_id, title, hashed_title, words_count, chapter_order, timestamp_in_seconds()])
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible d'ajouter le chapitre.".to_string() } else { "Unable to add chapter.".to_string() }))?;

    if insert_result > 0 {
        Ok(chapter_id.to_string())
    } else {
        Err(AppError::Internal(if lang == Lang::Fr { "Une erreur s'est passé lors de l'ajout du chapitre.".to_string() } else { "Error adding chapter.".to_string() }))
    }
}

/// Retrieves all chapters with their act information for a book.
pub fn fetch_all_chapter_for_acts(conn: &Connection, user_id: &str, book_id: &str, lang: Lang) -> AppResult<Vec<ActChapterQuery>> {
    let mut statement = conn
        .prepare("SELECT ci.chapter_info_id AS chapter_info_id, ci.chapter_id AS chapter_id, chapter.title, chapter.chapter_order, ci.act_id, ci.incident_id AS incident_id, ci.plot_point_id AS plot_point_id, ci.summary, ci.goal FROM book_chapter_infos AS ci INNER JOIN book_chapters AS chapter ON chapter.chapter_id = ci.chapter_id WHERE ci.book_id = ?1 AND ci.author_id = ?2")
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les chapitres pour les actes.".to_string() } else { "Unable to retrieve chapters for acts.".to_string() }))?;

    let rows = statement
        .query_map(params![book_id, user_id], |query_row| {
            Ok(ActChapterQuery {
                chapter_info_id: query_row.get(0)?, chapter_id: query_row.get(1)?,
                title: query_row.get(2)?, chapter_order: query_row.get(3)?,
                act_id: query_row.get(4)?, incident_id: query_row.get(5)?,
                plot_point_id: query_row.get(6)?, summary: query_row.get(7)?,
                goal: query_row.get(8)?,
            })
        })
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les chapitres pour les actes.".to_string() } else { "Unable to retrieve chapters for acts.".to_string() }))?
        .collect::<Result<Vec<_>, _>>()
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les chapitres pour les actes.".to_string() } else { "Unable to retrieve chapters for acts.".to_string() }))?;

    Ok(rows)
}

/// Retrieves all chapters from a book ordered by chapter order.
pub fn fetch_all_chapter_from_a_book(conn: &Connection, user_id: &str, book_id: &str, lang: Lang) -> AppResult<Vec<ChapterQueryResult>> {
    let mut statement = conn
        .prepare("SELECT chapter_id, title, chapter_order FROM book_chapters WHERE book_id=?1 AND author_id=?2 ORDER BY chapter_order")
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les chapitres.".to_string() } else { "Unable to retrieve chapters.".to_string() }))?;

    let rows = statement
        .query_map(params![book_id, user_id], |query_row| {
            Ok(ChapterQueryResult {
                chapter_id: query_row.get(0)?, title: query_row.get(1)?,
                chapter_order: query_row.get(2)?,
            })
        })
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les chapitres.".to_string() } else { "Unable to retrieve chapters.".to_string() }))?
        .collect::<Result<Vec<_>, _>>()
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les chapitres.".to_string() } else { "Unable to retrieve chapters.".to_string() }))?;

    Ok(rows)
}

/// Deletes a chapter from the database.
pub fn delete_chapter(conn: &Connection, user_id: &str, chapter_id: &str, lang: Lang) -> AppResult<bool> {
    let delete_result = conn
        .execute("DELETE FROM book_chapters WHERE author_id=?1 AND chapter_id=?2", params![user_id, chapter_id])
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de supprimer le chapitre.".to_string() } else { "Unable to delete chapter.".to_string() }))?;

    Ok(delete_result > 0)
}

/// Inserts chapter information linking a chapter to an act.
pub fn insert_chapter_information(
    conn: &Connection, chapter_info_id: &str, user_id: &str, chapter_id: &str,
    act_id: i64, book_id: &str, plot_id: Option<&str>, incident_id: Option<&str>, lang: Lang,
) -> AppResult<String> {
    let mut statement = conn
        .prepare("SELECT chapter_info_id FROM book_chapter_infos WHERE chapter_id=?1 AND act_id=?2 AND book_id=?3 AND plot_point_id=?4 AND incident_id=?5 AND author_id=?6")
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de vérifier l'existence de l'information du chapitre.".to_string() } else { "Unable to verify chapter information existence.".to_string() }))?;

    let existing = statement
        .exists(params![chapter_id, act_id, book_id, plot_id, incident_id, user_id])
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de vérifier l'existence de l'information du chapitre.".to_string() } else { "Unable to verify chapter information existence.".to_string() }))?;

    if existing {
        return Err(AppError::Internal(if lang == Lang::Fr { "Le chapitre est déjà lié.".to_string() } else { "Chapter is already linked.".to_string() }));
    }

    let insert_result = conn
        .execute("INSERT INTO book_chapter_infos (chapter_info_id, chapter_id, act_id, book_id, author_id, incident_id, plot_point_id, summary, goal, last_update) VALUES (?1,?2,?3,?4,?5,?6,?7,?8,?9,?10)", params![chapter_info_id, chapter_id, act_id, book_id, user_id, incident_id, plot_id, "", "", timestamp_in_seconds()])
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible d'ajouter l'information du chapitre.".to_string() } else { "Unable to add chapter information.".to_string() }))?;

    if insert_result > 0 {
        Ok(chapter_info_id.to_string())
    } else {
        Err(AppError::Internal(if lang == Lang::Fr { "Une erreur s'est produite pendant la liaison du chapitre.".to_string() } else { "Error linking chapter.".to_string() }))
    }
}

/// Updates a chapter's basic information.
pub fn update_chapter(conn: &Connection, user_id: &str, chapter_id: &str, encrypted_title: &str, hash_title: &str, chapter_order: i64, last_update: i64, lang: Lang) -> AppResult<bool> {
    let update_result = conn
        .execute("UPDATE book_chapters SET title=?1, hashed_title=?2, chapter_order=?3, last_update=?4 WHERE author_id=?5 AND chapter_id=?6", params![encrypted_title, hash_title, chapter_order, last_update, user_id, chapter_id])
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de mettre à jour le chapitre.".to_string() } else { "Unable to update chapter.".to_string() }))?;

    Ok(update_result > 0)
}

/// Updates chapter information (summary and goal).
pub fn update_chapter_infos(
    conn: &Connection, user_id: &str, chapter_id: &str, act_id: i64, book_id: &str,
    incident_id: Option<&str>, plot_id: Option<&str>, summary: &str, goal: Option<&str>,
    last_update: i64, lang: Lang,
) -> AppResult<bool> {
    let mut query = "UPDATE book_chapter_infos SET summary=?1,goal=?2,last_update=?3 WHERE chapter_id = ?4 AND act_id = ?5 AND book_id = ?6".to_string();
    let mut param_values: Vec<Box<dyn rusqlite::types::ToSql>> = vec![
        Box::new(summary.to_string()), Box::new(goal.map(|g| g.to_string())),
        Box::new(last_update), Box::new(chapter_id.to_string()),
        Box::new(act_id), Box::new(book_id.to_string()),
    ];

    if let Some(incident) = incident_id {
        let idx = param_values.len() + 1;
        query.push_str(&format!(" AND incident_id=?{}", idx));
        param_values.push(Box::new(incident.to_string()));
    } else {
        query.push_str(" AND incident_id IS NULL");
    }

    if let Some(plot) = plot_id {
        let idx = param_values.len() + 1;
        query.push_str(&format!(" AND plot_point_id=?{}", idx));
        param_values.push(Box::new(plot.to_string()));
    } else {
        query.push_str(" AND plot_point_id IS NULL");
    }

    let idx = param_values.len() + 1;
    query.push_str(&format!(" AND author_id=?{}", idx));
    param_values.push(Box::new(user_id.to_string()));

    let params_ref: Vec<&dyn rusqlite::types::ToSql> = param_values.iter().map(|p| p.as_ref()).collect();
    let update_result = conn
        .execute(&query, params_ref.as_slice())
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de mettre à jour les informations du chapitre.".to_string() } else { "Unable to update chapter information.".to_string() }))?;

    Ok(update_result > 0)
}

/// Retrieves the last opened chapter for a book.
pub fn fetch_last_chapter(conn: &Connection, user_id: &str, book_id: &str, lang: Lang) -> AppResult<Option<LastChapterResult>> {
    let mut statement = conn
        .prepare("SELECT chapter_id as chapter_id,version FROM user_last_chapter WHERE user_id=?1 AND book_id=?2")
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer le dernier chapitre ouvert.".to_string() } else { "Unable to retrieve last opened chapter.".to_string() }))?;

    let result = statement
        .query_row(params![user_id, book_id], |query_row| {
            Ok(LastChapterResult { chapter_id: query_row.get(0)?, version: query_row.get(1)? })
        });

    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 le dernier chapitre ouvert.".to_string() } else { "Unable to retrieve last opened chapter.".to_string() })),
    }
}

/// Updates or inserts the last chapter record for a user.
pub fn update_last_chapter_record(conn: &Connection, user_id: &str, book_id: &str, chapter_id: &str, version: i64, lang: Lang) -> AppResult<bool> {
    let update_result = conn
        .execute("UPDATE user_last_chapter SET chapter_id=?1, version=?2 WHERE user_id=?3 AND book_id=?4", params![chapter_id, version, user_id, book_id])
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible d'enregistrer le dernier chapitre.".to_string() } else { "Unable to save last chapter.".to_string() }))?;

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

    let insert_result = conn
        .execute("INSERT INTO user_last_chapter (user_id, book_id, chapter_id, version) VALUES (?1,?2,?3,?4)", params![user_id, book_id, chapter_id, version])
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible d'enregistrer le dernier chapitre.".to_string() } else { "Unable to save last chapter.".to_string() }))?;

    Ok(insert_result > 0)
}

/// Retrieves chapter story information including act, incident, and plot point data.
pub fn fetch_chapter_story(conn: &Connection, user_id: &str, chapter_id: &str, lang: Lang) -> AppResult<Vec<ChapterStoryQueryResult>> {
    let mut statement = conn
        .prepare("SELECT chapter_info_id, chapter.act_id, act_sum.summary, chapter.summary AS chapter_summary, chapter.goal AS chapter_goal, chapter.incident_id, incident.title AS incident_title, incident.summary AS incident_summary, chapter.plot_point_id, plot.title AS plot_title, plot.summary AS plot_summary FROM book_chapter_infos AS chapter LEFT JOIN book_incidents AS incident ON chapter.incident_id=incident.incident_id LEFT JOIN book_plot_points AS plot ON chapter.plot_point_id=plot.plot_point_id LEFT JOIN book_act_summaries AS act_sum ON chapter.act_id=act_sum.act_sum_id AND chapter.book_id=act_sum.book_id WHERE chapter.chapter_id=?1 AND chapter.author_id=?2")
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer l'histoire du chapitre.".to_string() } else { "Unable to retrieve chapter story.".to_string() }))?;

    let rows = statement
        .query_map(params![chapter_id, user_id], |query_row| {
            Ok(ChapterStoryQueryResult {
                _chapter_info_id: query_row.get(0)?, act_id: query_row.get(1)?,
                summary: query_row.get::<_, Option<String>>(2)?.unwrap_or_default(),
                chapter_summary: query_row.get::<_, Option<String>>(3)?.unwrap_or_default(),
                chapter_goal: query_row.get::<_, Option<String>>(4)?.unwrap_or_default(),
                incident_id: query_row.get(5)?, incident_title: query_row.get(6)?,
                incident_summary: query_row.get(7)?, plot_point_id: query_row.get(8)?,
                plot_title: query_row.get(9)?, plot_summary: query_row.get(10)?,
            })
        })
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer l'histoire du chapitre.".to_string() } else { "Unable to retrieve chapter story.".to_string() }))?
        .collect::<Result<Vec<_>, _>>()
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer l'histoire du chapitre.".to_string() } else { "Unable to retrieve chapter story.".to_string() }))?;

    Ok(rows)
}

/// Deletes chapter information by its identifier.
pub fn delete_chapter_information(conn: &Connection, user_id: &str, chapter_info_id: &str, lang: Lang) -> AppResult<bool> {
    let delete_result = conn
        .execute("DELETE FROM book_chapter_infos WHERE chapter_info_id=?1 AND author_id=?2", params![chapter_info_id, user_id])
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de supprimer les informations du chapitre.".to_string() } else { "Unable to delete chapter information.".to_string() }))?;

    Ok(delete_result > 0)
}

/// Checks if a chapter exists.
pub fn is_chapter_exist(conn: &Connection, user_id: &str, chapter_id: &str, _lang: Lang) -> bool {
    let result = conn.prepare("SELECT 1 FROM book_chapters WHERE chapter_id=?1 AND author_id=?2");

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

/// Checks if chapter info exists.
pub fn is_chapter_info_exist(conn: &Connection, user_id: &str, chapter_id: &str, _lang: Lang) -> bool {
    let result = conn.prepare("SELECT 1 FROM book_chapter_infos WHERE chapter_id=?1 AND author_id=?2");

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

/// Retrieves complete book chapters with their content.
pub fn fetch_complete_book_chapters(conn: &Connection, book_id: &str, lang: Lang) -> AppResult<Vec<ChapterBookResult>> {
    let mut statement = conn
        .prepare("SELECT title, chapter_order, content.content FROM book_chapters AS chapter LEFT JOIN book_chapter_content AS content ON chapter.chapter_id = content.chapter_id AND content.version = (SELECT MAX(version) FROM book_chapter_content WHERE chapter_id = chapter.chapter_id AND version > 1) WHERE chapter.book_id = ?1 ORDER BY chapter.chapter_order")
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les chapitres.".to_string() } else { "Unable to retrieve chapters.".to_string() }))?;

    let chapters = statement
        .query_map(params![book_id], |query_row| {
            Ok(ChapterBookResult {
                title: query_row.get(0)?, chapter_order: query_row.get(1)?,
                content: query_row.get(2)?,
            })
        })
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les chapitres.".to_string() } else { "Unable to retrieve chapters.".to_string() }))?
        .collect::<Result<Vec<_>, _>>()
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les chapitres.".to_string() } else { "Unable to retrieve chapters.".to_string() }))?;

    if chapters.is_empty() {
        return Err(AppError::NotFound(if lang == Lang::Fr { "Aucun chapitre trouvé.".to_string() } else { "No chapters found.".to_string() }));
    }

    Ok(chapters)
}

/// Retrieves all chapters for a book.
pub fn fetch_book_chapters(conn: &Connection, user_id: &str, book_id: &str, lang: Lang) -> AppResult<Vec<BookChaptersTable>> {
    let mut statement = conn
        .prepare("SELECT chapter_id, book_id, author_id, title, hashed_title, words_count, chapter_order, last_update FROM book_chapters WHERE author_id=?1 AND book_id=?2")
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les chapitres.".to_string() } else { "Unable to retrieve chapters.".to_string() }))?;

    let rows = statement
        .query_map(params![user_id, book_id], |query_row| {
            Ok(BookChaptersTable {
                chapter_id: query_row.get(0)?, book_id: query_row.get(1)?,
                author_id: query_row.get(2)?, title: query_row.get(3)?,
                hashed_title: query_row.get(4)?, _words_count: query_row.get(5)?,
                chapter_order: query_row.get(6)?, last_update: query_row.get(7)?,
            })
        })
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les chapitres.".to_string() } else { "Unable to retrieve chapters.".to_string() }))?
        .collect::<Result<Vec<_>, _>>()
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les chapitres.".to_string() } else { "Unable to retrieve chapters.".to_string() }))?;

    Ok(rows)
}

pub fn fetch_all_chapter_infos_by_book(conn: &Connection, user_id: &str, book_id: &str, lang: Lang) -> AppResult<Vec<BookChapterInfosTable>> {
    let mut statement = conn
        .prepare("SELECT chapter_info_id, chapter_id, act_id, incident_id, plot_point_id, book_id, author_id, summary, goal, last_update FROM book_chapter_infos WHERE author_id=?1 AND book_id=?2")
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les infos des chapitres.".to_string() } else { "Unable to retrieve chapter infos.".to_string() }))?;
    let rows = statement
        .query_map(params![user_id, book_id], |query_row| {
            Ok(BookChapterInfosTable {
                _chapter_info_id: query_row.get(0)?, chapter_id: query_row.get(1)?,
                _act_id: query_row.get(2)?, _incident_id: query_row.get(3)?,
                _plot_point_id: query_row.get(4)?, _book_id: query_row.get(5)?,
                author_id: query_row.get(6)?, summary: query_row.get(7)?,
                goal: query_row.get(8)?, last_update: query_row.get(9)?,
            })
        })
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les infos des chapitres.".to_string() } else { "Unable to retrieve chapter infos.".to_string() }))?
        .collect::<Result<Vec<_>, _>>()
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les infos des chapitres.".to_string() } else { "Unable to retrieve chapter infos.".to_string() }))?;
    Ok(rows)
}

/// Retrieves synced chapters for a user.
pub fn fetch_synced_chapters(conn: &Connection, user_id: &str, lang: Lang) -> AppResult<Vec<SyncedChapterResult>> {
    let mut statement = conn
        .prepare("SELECT chapter_id, book_id, title, last_update FROM book_chapters WHERE author_id = ?1")
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les chapitres synchronisés.".to_string() } else { "Unable to retrieve synced chapters.".to_string() }))?;

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

    Ok(rows)
}

/// Retrieves synced chapter infos for a user.
pub fn fetch_synced_chapter_infos(conn: &Connection, user_id: &str, lang: Lang) -> AppResult<Vec<SyncedChapterInfoResult>> {
    let mut statement = conn
        .prepare("SELECT chapter_info_id, chapter_id, book_id, last_update FROM book_chapter_infos WHERE author_id = ?1")
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les infos des chapitres synchronisés.".to_string() } else { "Unable to retrieve synced chapter infos.".to_string() }))?;

    let rows = statement
        .query_map(params![user_id], |query_row| {
            Ok(SyncedChapterInfoResult {
                chapter_info_id: query_row.get(0)?, chapter_id: query_row.get(1)?,
                _book_id: query_row.get(2)?, last_update: query_row.get(3)?,
            })
        })
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les infos des chapitres synchronisés.".to_string() } else { "Unable to retrieve synced chapter infos.".to_string() }))?
        .collect::<Result<Vec<_>, _>>()
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les infos des chapitres synchronisés.".to_string() } else { "Unable to retrieve synced chapter infos.".to_string() }))?;

    Ok(rows)
}

/// Inserts a synced chapter from the server.
pub fn insert_sync_chapter(conn: &Connection, chapter_id: &str, book_id: &str, author_id: &str, title: &str, hashed_title: Option<&str>, words_count: Option<i64>, chapter_order: Option<i64>, last_update: i64, lang: Lang) -> AppResult<bool> {
    let insert_result = conn
        .execute("INSERT INTO book_chapters (chapter_id, book_id, author_id, title, hashed_title, words_count, chapter_order, last_update) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8)", params![chapter_id, book_id, author_id, title, hashed_title, words_count, chapter_order, last_update])
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible d'insérer le chapitre.".to_string() } else { "Unable to insert chapter.".to_string() }))?;

    Ok(insert_result > 0)
}

/// Inserts synced chapter info from the server.
pub fn insert_sync_chapter_info(
    conn: &Connection, chapter_info_id: &str, chapter_id: &str, act_id: Option<i64>,
    incident_id: Option<&str>, plot_point_id: Option<&str>, book_id: &str, author_id: &str,
    summary: Option<&str>, goal: Option<&str>, last_update: i64, lang: Lang,
) -> AppResult<bool> {
    let insert_result = conn
        .execute("INSERT INTO book_chapter_infos (chapter_info_id, chapter_id, act_id, incident_id, plot_point_id, book_id, author_id, summary, goal, last_update) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10)", params![chapter_info_id, chapter_id, act_id, incident_id, plot_point_id, book_id, author_id, summary, goal, last_update])
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible d'insérer les infos du chapitre.".to_string() } else { "Unable to insert chapter info.".to_string() }))?;

    Ok(insert_result > 0)
}

/// Retrieves a complete chapter by its identifier.
pub fn fetch_complete_chapter_by_id(conn: &Connection, chapter_id: &str, lang: Lang) -> AppResult<Vec<BookChaptersTable>> {
    let mut statement = conn
        .prepare("SELECT chapter_id, book_id, author_id, title, hashed_title, words_count, chapter_order, last_update FROM book_chapters WHERE chapter_id = ?1")
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer le chapitre complet.".to_string() } else { "Unable to retrieve complete chapter.".to_string() }))?;

    let rows = statement
        .query_map(params![chapter_id], |query_row| {
            Ok(BookChaptersTable {
                chapter_id: query_row.get(0)?, book_id: query_row.get(1)?,
                author_id: query_row.get(2)?, title: query_row.get(3)?,
                hashed_title: query_row.get(4)?, _words_count: query_row.get(5)?,
                chapter_order: query_row.get(6)?, last_update: query_row.get(7)?,
            })
        })
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer le chapitre complet.".to_string() } else { "Unable to retrieve complete chapter.".to_string() }))?
        .collect::<Result<Vec<_>, _>>()
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer le chapitre complet.".to_string() } else { "Unable to retrieve complete chapter.".to_string() }))?;

    Ok(rows)
}

/// Retrieves complete chapter info by its identifier.
pub fn fetch_complete_chapter_info_by_id(conn: &Connection, chapter_info_id: &str, lang: Lang) -> AppResult<Vec<BookChapterInfosTable>> {
    let mut statement = conn
        .prepare("SELECT chapter_info_id, chapter_id, act_id, incident_id, plot_point_id, book_id, author_id, summary, goal, last_update FROM book_chapter_infos WHERE chapter_info_id = ?1")
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les informations de chapitre complètes.".to_string() } else { "Unable to retrieve complete chapter info.".to_string() }))?;

    let rows = statement
        .query_map(params![chapter_info_id], |query_row| {
            Ok(BookChapterInfosTable {
                _chapter_info_id: query_row.get(0)?, chapter_id: query_row.get(1)?,
                _act_id: query_row.get(2)?, _incident_id: query_row.get(3)?,
                _plot_point_id: query_row.get(4)?, _book_id: query_row.get(5)?,
                author_id: query_row.get(6)?, summary: query_row.get(7)?,
                goal: query_row.get(8)?, last_update: query_row.get(9)?,
            })
        })
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les informations de chapitre complètes.".to_string() } else { "Unable to retrieve complete chapter info.".to_string() }))?
        .collect::<Result<Vec<_>, _>>()
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les informations de chapitre complètes.".to_string() } else { "Unable to retrieve complete chapter info.".to_string() }))?;

    Ok(rows)
}

/// Retrieves chapter export information for a book.
pub fn fetch_chapters_export_info(conn: &Connection, user_id: &str, book_id: &str, lang: Lang) -> AppResult<Vec<ChapterExportInfoResult>> {
    let mut statement = conn
        .prepare("SELECT bc.chapter_id, bc.title, bc.chapter_order, GROUP_CONCAT(DISTINCT bcc.version) AS available_versions FROM book_chapters bc LEFT JOIN book_chapter_content bcc ON bc.chapter_id = bcc.chapter_id WHERE bc.author_id = ?1 AND bc.book_id = ?2 GROUP BY bc.chapter_id, bc.title, bc.chapter_order ORDER BY bc.chapter_order")
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les informations d'export des chapitres.".to_string() } else { "Unable to retrieve chapters export info.".to_string() }))?;

    let rows = statement
        .query_map(params![user_id, book_id], |query_row| {
            Ok(ChapterExportInfoResult {
                chapter_id: query_row.get(0)?, title: query_row.get(1)?,
                chapter_order: query_row.get(2)?,
                available_versions: query_row.get::<_, Option<String>>(3)?.unwrap_or_default(),
            })
        })
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les informations d'export des chapitres.".to_string() } else { "Unable to retrieve chapters export info.".to_string() }))?
        .collect::<Result<Vec<_>, _>>()
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les informations d'export des chapitres.".to_string() } else { "Unable to retrieve chapters export info.".to_string() }))?;

    Ok(rows)
}

/// Retrieves content for selected chapters with specific versions.
pub fn fetch_selected_chapters_content(conn: &Connection, book_id: &str, selections: &[ChapterSelectionParam], lang: Lang) -> AppResult<Vec<SelectedChapterContentResult>> {
    let conditions: Vec<String> = selections.iter().enumerate().map(|(index, _)| {
        let base = 2 + index * 2;
        format!("(chapter.chapter_id = ?{} AND content.version = ?{})", base, base + 1)
    }).collect();

    let query = format!("SELECT chapter.chapter_id, chapter.title, chapter.chapter_order, content.content, content.version FROM book_chapters AS chapter INNER JOIN book_chapter_content AS content ON chapter.chapter_id = content.chapter_id WHERE chapter.book_id = ?1 AND ({}) ORDER BY chapter.chapter_order", conditions.join(" OR "));

    let mut param_values: Vec<Box<dyn rusqlite::types::ToSql>> = vec![Box::new(book_id.to_string())];
    for selection in selections {
        param_values.push(Box::new(selection.chapter_id.clone()));
        param_values.push(Box::new(selection.version));
    }

    let params_ref: Vec<&dyn rusqlite::types::ToSql> = param_values.iter().map(|p| p.as_ref()).collect();

    let mut statement = conn
        .prepare(&query)
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer le contenu des chapitres sélectionnés.".to_string() } else { "Unable to retrieve selected chapters content.".to_string() }))?;

    let rows = statement
        .query_map(params_ref.as_slice(), |query_row| {
            Ok(SelectedChapterContentResult {
                chapter_id: query_row.get(0)?, title: query_row.get(1)?,
                chapter_order: query_row.get(2)?, content: query_row.get(3)?,
                _version: query_row.get(4)?,
            })
        })
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer le contenu des chapitres sélectionnés.".to_string() } else { "Unable to retrieve selected chapters content.".to_string() }))?
        .collect::<Result<Vec<_>, _>>()
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer le contenu des chapitres sélectionnés.".to_string() } else { "Unable to retrieve selected chapters content.".to_string() }))?;

    Ok(rows)
}
