use rusqlite::{params, Connection, OptionalExtension};

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

pub struct BookActSummariesTable {
    pub act_sum_id: String,
    pub book_id: String,
    pub user_id: String,
    pub act_index: i64,
    pub last_update: i64,
    pub summary: Option<String>,
}

pub struct SyncedActSummaryResult {
    pub act_sum_id: String,
    pub book_id: String,
    pub last_update: i64,
}

pub struct ActQuery {
    pub act_index: i64,
    pub summary: String,
}

/// Fetches all acts for a specific book and user.
/// * `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 ActQuery objects containing act index and summary.
/// Errors if the database operation fails.
pub fn fetch_all_acts(conn: &Connection, user_id: &str, book_id: &str, lang: Lang) -> AppResult<Vec<ActQuery>> {
    let mut statement = conn
        .prepare("SELECT act_index, summary FROM book_act_summaries WHERE book_id=?1 AND user_id=?2")
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les actes.".to_string() } else { "Unable to retrieve acts.".to_string() }))?;

    let acts = statement
        .query_map(params![book_id, user_id], |query_row| {
            Ok(ActQuery { act_index: query_row.get(0)?, summary: query_row.get(1)? })
        })
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les actes.".to_string() } else { "Unable to retrieve acts.".to_string() }))?
        .collect::<Result<Vec<_>, _>>()
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les actes.".to_string() } else { "Unable to retrieve acts.".to_string() }))?;

    Ok(acts)
}

/// Updates the summary of an existing act.
/// * `conn` - Database connection
/// * `user_id` - The unique identifier of the user
/// * `book_id` - The unique identifier of the book
/// * `act_id` - The unique identifier of the act summary
/// * `summary` - The new summary text
/// * `last_update` - The timestamp of the last update in seconds
/// * `lang` - The language for error messages ("fr" or "en")
/// Returns true if the update was successful, false otherwise.
/// Errors if the database operation fails.
pub fn update_act_summary(
    conn: &Connection, user_id: &str, book_id: &str, act_id: i64, summary: &str, last_update: i64, lang: Lang,
) -> AppResult<bool> {
    let update_result = conn
        .execute(
            "UPDATE book_act_summaries SET summary=?1, last_update=?2 WHERE user_id=?3 AND book_id=?4 AND act_index=?5",
            params![summary, last_update, user_id, book_id, act_id],
        )
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de mettre à jour le résumé de l'acte.".to_string() } else { "Unable to update act summary.".to_string() }))?;

    Ok(update_result > 0)
}

/// Inserts a new act summary into the database.
/// * `conn` - Database connection
/// * `act_summary_id` - The unique identifier for the new act summary
/// * `user_id` - The unique identifier of the user
/// * `book_id` - The unique identifier of the book
/// * `act_id` - The act index number
/// * `act_summary` - The summary text for the act
/// * `lang` - The language for error messages ("fr" or "en")
/// Returns the act summary ID if insertion was successful.
/// Errors if the database operation fails.
pub fn insert_act_summary(
    conn: &Connection, act_summary_id: &str, user_id: &str, book_id: &str, act_id: i64,
    act_summary: &str, last_update: i64, lang: Lang,
) -> AppResult<String> {
    let insert_result = conn
        .execute(
            "INSERT INTO book_act_summaries (act_sum_id, book_id, user_id, act_index, summary, last_update) VALUES (?1,?2,?3,?4,?5,?6)",
            params![act_summary_id, book_id, user_id, act_id, act_summary, last_update],
        )
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible d'ajouter le résumé de l'acte.".to_string() } else { "Unable to add act summary.".to_string() }))?;

    if insert_result > 0 {
        Ok(act_summary_id.to_string())
    } else {
        Err(AppError::Internal(if lang == Lang::Fr { "Erreur lors de l'ajout du résumé de l'acte.".to_string() } else { "Error adding act summary.".to_string() }))
    }
}

/// Fetches all act summaries for a specific 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 BookActSummariesTable objects.
/// Errors if the database operation fails.
pub fn fetch_book_act_summaries(conn: &Connection, user_id: &str, book_id: &str, lang: Lang) -> AppResult<Vec<BookActSummariesTable>> {
    let mut statement = conn
        .prepare("SELECT act_sum_id, book_id, user_id, act_index, summary, last_update FROM book_act_summaries WHERE user_id=?1 AND book_id=?2")
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les résumés des actes.".to_string() } else { "Unable to retrieve act summaries.".to_string() }))?;

    let summaries = statement
        .query_map(params![user_id, book_id], |query_row| {
            Ok(BookActSummariesTable {
                act_sum_id: query_row.get(0)?, book_id: query_row.get(1)?,
                user_id: query_row.get(2)?, act_index: query_row.get(3)?,
                summary: query_row.get(4)?, last_update: query_row.get(5)?,
            })
        })
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les résumés des actes.".to_string() } else { "Unable to retrieve act summaries.".to_string() }))?
        .collect::<Result<Vec<_>, _>>()
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les résumés des actes.".to_string() } else { "Unable to retrieve act summaries.".to_string() }))?;

    Ok(summaries)
}

/// Fetches all synced act summaries for a 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 SyncedActSummaryResult objects containing sync metadata.
/// Errors if the database operation fails.
pub fn fetch_synced_act_summaries(conn: &Connection, user_id: &str, lang: Lang) -> AppResult<Vec<SyncedActSummaryResult>> {
    let mut statement = conn
        .prepare("SELECT act_sum_id, book_id, last_update FROM book_act_summaries WHERE user_id = ?1")
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les résumés d'actes synchronisés.".to_string() } else { "Unable to retrieve synced act summaries.".to_string() }))?;

    let synced_act_summaries = statement
        .query_map(params![user_id], |query_row| {
            Ok(SyncedActSummaryResult { act_sum_id: query_row.get(0)?, book_id: query_row.get(1)?, last_update: query_row.get(2)? })
        })
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les résumés d'actes synchronisés.".to_string() } else { "Unable to retrieve synced act summaries.".to_string() }))?
        .collect::<Result<Vec<_>, _>>()
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les résumés d'actes synchronisés.".to_string() } else { "Unable to retrieve synced act summaries.".to_string() }))?;

    Ok(synced_act_summaries)
}

/// Inserts a synced act summary from remote data.
/// * `conn` - Database connection
/// * `act_sum_id` - The unique identifier of the act summary
/// * `book_id` - The unique identifier of the book
/// * `user_id` - The unique identifier of the user
/// * `act_index` - The act index number
/// * `summary` - The summary text (can be null)
/// * `last_update` - The timestamp of the last update in seconds
/// * `lang` - The language for error messages ("fr" or "en")
/// Returns true if the insertion was successful, false otherwise.
/// Errors if the database operation fails.
pub fn insert_sync_act_summary(
    conn: &Connection, act_sum_id: &str, book_id: &str, user_id: &str, act_index: i64,
    summary: Option<&str>, last_update: i64, lang: Lang,
) -> AppResult<bool> {
    let insert_result = conn
        .execute(
            "INSERT INTO book_act_summaries (act_sum_id, book_id, user_id, act_index, summary, last_update) VALUES (?1, ?2, ?3, ?4, ?5, ?6)",
            params![act_sum_id, book_id, user_id, act_index, summary, last_update],
        )
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible d'insérer le résumé d'acte.".to_string() } else { "Unable to insert act summary.".to_string() }))?;

    Ok(insert_result > 0)
}

/// Fetches a complete act summary by its unique identifier.
/// * `conn` - Database connection
/// * `id` - The unique identifier of the act summary
/// * `lang` - The language for error messages ("fr" or "en")
/// Returns an array of BookActSummariesTable objects.
/// Errors if the database operation fails.
pub fn fetch_complete_act_summary_by_id(conn: &Connection, id: &str, lang: Lang) -> AppResult<Vec<BookActSummariesTable>> {
    let mut statement = conn
        .prepare("SELECT act_sum_id, book_id, user_id, act_index, summary, last_update FROM book_act_summaries WHERE act_sum_id = ?1")
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer le résumé d'acte complet.".to_string() } else { "Unable to retrieve complete act summary.".to_string() }))?;

    let act_summary = statement
        .query_map(params![id], |query_row| {
            Ok(BookActSummariesTable {
                act_sum_id: query_row.get(0)?, book_id: query_row.get(1)?,
                user_id: query_row.get(2)?, act_index: query_row.get(3)?,
                summary: query_row.get(4)?, last_update: query_row.get(5)?,
            })
        })
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer le résumé d'acte complet.".to_string() } else { "Unable to retrieve complete act summary.".to_string() }))?
        .collect::<Result<Vec<_>, _>>()
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer le résumé d'acte complet.".to_string() } else { "Unable to retrieve complete act summary.".to_string() }))?;

    Ok(act_summary)
}

/// Checks if an act summary exists for a given user, book, and act index.
/// * `conn` - Database connection
/// * `user_id` - The unique identifier of the user
/// * `book_id` - The unique identifier of the book
/// * `act_index` - The act index number to check
/// * `lang` - The language for error messages ("fr" or "en")
/// Returns true if the act summary exists, false otherwise.
/// Errors if the database operation fails.
pub fn act_summarize_exist(conn: &Connection, user_id: &str, book_id: &str, act_index: i64, lang: Lang) -> AppResult<bool> {
    let mut statement = conn
        .prepare("SELECT 1 FROM book_act_summaries WHERE user_id =?1 AND book_id =?2 AND act_index = ?3")
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de vérifier l'existence du résumé de l'acte.".to_string() } else { "Unable to check act summary existence.".to_string() }))?;

    let existence_check = statement
        .query_row(params![user_id, book_id, act_index], |_query_row| Ok(true))
        .optional()
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de vérifier l'existence du résumé de l'acte.".to_string() } else { "Unable to check act summary existence.".to_string() }))?;

    Ok(existence_check.is_some())
}
