use rusqlite::{params, Connection};

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

pub struct SeriesLocationResult {
    pub loc_id: String,
    pub loc_name: String,
}

pub struct SeriesLocationElementResult {
    pub element_id: String,
    pub _location_id: String,
    pub element_name: String,
    pub element_description: String,
}

pub struct SeriesLocationSubElementResult {
    pub sub_element_id: String,
    pub _element_id: String,
    pub sub_elem_name: String,
    pub sub_elem_description: String,
}

pub struct SeriesLocationsTableResult {
    pub loc_id: String,
    pub series_id: String,
    pub user_id: String,
    pub loc_name: String,
    pub loc_original_name: String,
    pub last_update: i64,
}

pub struct SeriesLocationElementsTableResult {
    pub element_id: String,
    pub location_id: String,
    pub user_id: String,
    pub element_name: String,
    pub original_name: String,
    pub element_description: Option<String>,
    pub last_update: i64,
}

pub struct SeriesLocationSubElementsTableResult {
    pub sub_element_id: String,
    pub element_id: String,
    pub user_id: String,
    pub sub_elem_name: String,
    pub original_name: String,
    pub sub_elem_description: Option<String>,
    pub last_update: i64,
}

pub struct SyncedSeriesLocationResult {
    pub loc_id: String,
    pub series_id: String,
    pub loc_name: String,
    pub last_update: i64,
}

pub struct SyncedSeriesLocationElementResult {
    pub element_id: String,
    pub location_id: String,
    pub element_name: String,
    pub last_update: i64,
}

pub struct SyncedSeriesLocationSubElementResult {
    pub sub_element_id: String,
    pub element_id: String,
    pub sub_elem_name: String,
    pub last_update: i64,
}

/// Fetches all locations for a series.
pub fn fetch_locations(conn: &Connection, user_id: &str, series_id: &str, lang: Lang) -> AppResult<Vec<SeriesLocationResult>> {
    let mut statement = conn
        .prepare("SELECT loc_id, loc_name FROM series_locations WHERE user_id = ?1 AND series_id = ?2")
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les lieux.".to_string() } else { "Unable to retrieve locations.".to_string() }))?;

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

    Ok(locations)
}

/// Fetches all elements for a location.
pub fn fetch_elements(conn: &Connection, user_id: &str, location_id: &str, lang: Lang) -> AppResult<Vec<SeriesLocationElementResult>> {
    let mut statement = conn
        .prepare("SELECT element_id, location_id, element_name, element_description FROM series_location_elements WHERE user_id = ?1 AND location_id = ?2")
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les éléments.".to_string() } else { "Unable to retrieve elements.".to_string() }))?;

    let elements = statement
        .query_map(params![user_id, location_id], |query_row| {
            Ok(SeriesLocationElementResult { element_id: query_row.get(0)?, _location_id: query_row.get(1)?, element_name: query_row.get(2)?, element_description: query_row.get(3)? })
        })
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les éléments.".to_string() } else { "Unable to retrieve elements.".to_string() }))?
        .collect::<Result<Vec<_>, _>>()
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les éléments.".to_string() } else { "Unable to retrieve elements.".to_string() }))?;

    Ok(elements)
}

/// Fetches all sub-elements for an element.
pub fn fetch_sub_elements(conn: &Connection, user_id: &str, element_id: &str, lang: Lang) -> AppResult<Vec<SeriesLocationSubElementResult>> {
    let mut statement = conn
        .prepare("SELECT sub_element_id, element_id, sub_elem_name, sub_elem_description FROM series_location_sub_elements WHERE user_id = ?1 AND element_id = ?2")
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les sous-éléments.".to_string() } else { "Unable to retrieve sub-elements.".to_string() }))?;

    let sub_elements = statement
        .query_map(params![user_id, element_id], |query_row| {
            Ok(SeriesLocationSubElementResult { sub_element_id: query_row.get(0)?, _element_id: query_row.get(1)?, sub_elem_name: query_row.get(2)?, sub_elem_description: query_row.get(3)? })
        })
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les sous-éléments.".to_string() } else { "Unable to retrieve sub-elements.".to_string() }))?
        .collect::<Result<Vec<_>, _>>()
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les sous-éléments.".to_string() } else { "Unable to retrieve sub-elements.".to_string() }))?;

    Ok(sub_elements)
}

/// Inserts a new location section.
pub fn insert_location(
    conn: &Connection, location_id: &str, series_id: &str, user_id: &str,
    encrypted_name: &str, original_name: &str, last_update: i64, lang: Lang,
) -> AppResult<String> {
    let insert_result = conn
        .execute(
            "INSERT INTO series_locations (loc_id, series_id, user_id, loc_name, loc_original_name, last_update) VALUES (?1, ?2, ?3, ?4, ?5, ?6)",
            params![location_id, series_id, user_id, encrypted_name, original_name, last_update],
        )
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible d'ajouter le lieu.".to_string() } else { "Unable to add location.".to_string() }))?;

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

/// Inserts a new element.
pub fn insert_element(
    conn: &Connection, element_id: &str, location_id: &str, user_id: &str,
    encrypted_name: &str, original_name: &str, description: Option<&str>, last_update: i64, lang: Lang,
) -> AppResult<String> {
    let insert_result = conn
        .execute(
            "INSERT INTO series_location_elements (element_id, location_id, user_id, element_name, original_name, element_description, last_update) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)",
            params![element_id, location_id, user_id, encrypted_name, original_name, description, last_update],
        )
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible d'ajouter l'élé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'élément.".to_string() } else { "Error adding element.".to_string() }))
    }
}

/// Inserts a new sub-element.
pub fn insert_sub_element(
    conn: &Connection, sub_element_id: &str, element_id: &str, user_id: &str,
    encrypted_name: &str, original_name: &str, description: Option<&str>, last_update: i64, lang: Lang,
) -> AppResult<String> {
    let insert_result = conn
        .execute(
            "INSERT INTO series_location_sub_elements (sub_element_id, element_id, user_id, sub_elem_name, original_name, sub_elem_description, last_update) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)",
            params![sub_element_id, element_id, user_id, encrypted_name, original_name, description, last_update],
        )
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible d'ajouter le sous-élément.".to_string() } else { "Unable to add sub-element.".to_string() }))?;

    if insert_result > 0 {
        Ok(sub_element_id.to_string())
    } else {
        Err(AppError::Internal(if lang == Lang::Fr { "Erreur lors de l'ajout du sous-élément.".to_string() } else { "Error adding sub-element.".to_string() }))
    }
}

/// Deletes a location section.
pub fn delete_location(conn: &Connection, user_id: &str, location_id: &str, lang: Lang) -> AppResult<bool> {
    let delete_result = conn
        .execute("DELETE FROM series_locations WHERE loc_id = ?1 AND user_id = ?2", params![location_id, user_id])
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de supprimer le lieu.".to_string() } else { "Unable to delete location.".to_string() }))?;

    Ok(delete_result > 0)
}

/// Deletes an element.
pub fn delete_element(conn: &Connection, user_id: &str, element_id: &str, lang: Lang) -> AppResult<bool> {
    let delete_result = conn
        .execute("DELETE FROM series_location_elements WHERE element_id = ?1 AND user_id = ?2", params![element_id, user_id])
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de supprimer l'élément.".to_string() } else { "Unable to delete element.".to_string() }))?;

    Ok(delete_result > 0)
}

/// Deletes a sub-element.
pub fn delete_sub_element(conn: &Connection, user_id: &str, sub_element_id: &str, lang: Lang) -> AppResult<bool> {
    let delete_result = conn
        .execute("DELETE FROM series_location_sub_elements WHERE sub_element_id = ?1 AND user_id = ?2", params![sub_element_id, user_id])
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de supprimer le sous-élément.".to_string() } else { "Unable to delete sub-element.".to_string() }))?;

    Ok(delete_result > 0)
}

/// Fetches all locations for a series for sync.
pub fn fetch_series_locations_table(conn: &Connection, user_id: &str, series_id: &str, lang: Lang) -> AppResult<Vec<SeriesLocationsTableResult>> {
    let mut statement = conn
        .prepare("SELECT loc_id, series_id, user_id, loc_name, loc_original_name, last_update FROM series_locations WHERE series_id = ?1 AND user_id = ?2")
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les lieux pour sync.".to_string() } else { "Unable to retrieve locations for sync.".to_string() }))?;

    let locations = statement
        .query_map(params![series_id, user_id], |query_row| {
            Ok(SeriesLocationsTableResult {
                loc_id: query_row.get(0)?, series_id: query_row.get(1)?, user_id: query_row.get(2)?,
                loc_name: query_row.get(3)?, loc_original_name: query_row.get(4)?, last_update: query_row.get(5)?,
            })
        })
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les lieux pour sync.".to_string() } else { "Unable to retrieve locations for sync.".to_string() }))?
        .collect::<Result<Vec<_>, _>>()
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les lieux pour sync.".to_string() } else { "Unable to retrieve locations for sync.".to_string() }))?;

    Ok(locations)
}

/// Fetches all series locations for a user for sync comparison.
pub fn fetch_synced_series_locations(conn: &Connection, user_id: &str, lang: Lang) -> AppResult<Vec<SyncedSeriesLocationResult>> {
    let mut statement = conn
        .prepare("SELECT loc_id, series_id, loc_name, last_update FROM series_locations WHERE user_id = ?1")
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les lieux de série pour sync.".to_string() } else { "Unable to retrieve series locations for sync.".to_string() }))?;

    let locations = statement
        .query_map(params![user_id], |query_row| {
            Ok(SyncedSeriesLocationResult { loc_id: query_row.get(0)?, series_id: query_row.get(1)?, loc_name: query_row.get(2)?, last_update: query_row.get(3)? })
        })
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les lieux de série pour sync.".to_string() } else { "Unable to retrieve series locations for sync.".to_string() }))?
        .collect::<Result<Vec<_>, _>>()
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les lieux de série pour sync.".to_string() } else { "Unable to retrieve series locations for sync.".to_string() }))?;

    Ok(locations)
}

/// Fetches all series location elements for a user for sync comparison.
pub fn fetch_synced_series_location_elements(conn: &Connection, user_id: &str, lang: Lang) -> AppResult<Vec<SyncedSeriesLocationElementResult>> {
    let mut statement = conn
        .prepare("SELECT element_id, location_id, element_name, last_update FROM series_location_elements WHERE user_id = ?1")
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les éléments de lieu pour sync.".to_string() } else { "Unable to retrieve location elements for sync.".to_string() }))?;

    let elements = statement
        .query_map(params![user_id], |query_row| {
            Ok(SyncedSeriesLocationElementResult { element_id: query_row.get(0)?, location_id: query_row.get(1)?, element_name: query_row.get(2)?, last_update: query_row.get(3)? })
        })
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les éléments de lieu pour sync.".to_string() } else { "Unable to retrieve location elements for sync.".to_string() }))?
        .collect::<Result<Vec<_>, _>>()
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les éléments de lieu pour sync.".to_string() } else { "Unable to retrieve location elements for sync.".to_string() }))?;

    Ok(elements)
}

/// Fetches all series location sub-elements for a user for sync comparison.
pub fn fetch_synced_series_location_sub_elements(conn: &Connection, user_id: &str, lang: Lang) -> AppResult<Vec<SyncedSeriesLocationSubElementResult>> {
    let mut statement = conn
        .prepare("SELECT sub_element_id, element_id, sub_elem_name, last_update FROM series_location_sub_elements WHERE user_id = ?1")
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les sous-éléments de lieu pour sync.".to_string() } else { "Unable to retrieve location sub-elements for sync.".to_string() }))?;

    let sub_elements = statement
        .query_map(params![user_id], |query_row| {
            Ok(SyncedSeriesLocationSubElementResult { sub_element_id: query_row.get(0)?, element_id: query_row.get(1)?, sub_elem_name: query_row.get(2)?, last_update: query_row.get(3)? })
        })
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les sous-éléments de lieu pour sync.".to_string() } else { "Unable to retrieve location sub-elements for sync.".to_string() }))?
        .collect::<Result<Vec<_>, _>>()
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les sous-éléments de lieu pour sync.".to_string() } else { "Unable to retrieve location sub-elements for sync.".to_string() }))?;

    Ok(sub_elements)
}

/// Checks if a location exists.
pub fn is_location_exist(conn: &Connection, user_id: &str, location_id: &str, lang: Lang) -> AppResult<bool> {
    let exists: bool = conn
        .prepare("SELECT 1 FROM series_locations WHERE loc_id = ?1 AND user_id = ?2")
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de vérifier l'existence du lieu.".to_string() } else { "Unable to check location existence.".to_string() }))?
        .exists(params![location_id, user_id])
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de vérifier l'existence du lieu.".to_string() } else { "Unable to check location existence.".to_string() }))?;

    Ok(exists)
}

/// Checks if a location element exists.
pub fn is_location_element_exist(conn: &Connection, user_id: &str, element_id: &str, lang: Lang) -> AppResult<bool> {
    let exists: bool = conn
        .prepare("SELECT 1 FROM series_location_elements WHERE element_id = ?1 AND user_id = ?2")
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de vérifier l'existence de l'élément.".to_string() } else { "Unable to check element existence.".to_string() }))?
        .exists(params![element_id, user_id])
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de vérifier l'existence de l'élément.".to_string() } else { "Unable to check element existence.".to_string() }))?;

    Ok(exists)
}

/// Checks if a location sub-element exists.
pub fn is_location_sub_element_exist(conn: &Connection, user_id: &str, sub_element_id: &str, lang: Lang) -> AppResult<bool> {
    let exists: bool = conn
        .prepare("SELECT 1 FROM series_location_sub_elements WHERE sub_element_id = ?1 AND user_id = ?2")
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de vérifier l'existence du sous-élément.".to_string() } else { "Unable to check sub-element existence.".to_string() }))?
        .exists(params![sub_element_id, user_id])
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de vérifier l'existence du sous-élément.".to_string() } else { "Unable to check sub-element existence.".to_string() }))?;

    Ok(exists)
}

/// Inserts a series location for sync.
pub fn insert_sync_location(
    conn: &Connection, location_id: &str, series_id: &str, user_id: &str,
    loc_name: &str, loc_original_name: &str, last_update: i64, lang: Lang,
) -> AppResult<bool> {
    let insert_result = conn
        .execute(
            "INSERT INTO series_locations (loc_id, series_id, user_id, loc_name, loc_original_name, last_update) VALUES (?1, ?2, ?3, ?4, ?5, ?6) ON CONFLICT(loc_id) DO UPDATE SET loc_name = excluded.loc_name, loc_original_name = excluded.loc_original_name, last_update = excluded.last_update",
            params![location_id, series_id, user_id, loc_name, loc_original_name, last_update],
        )
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible d'insérer le lieu pour sync.".to_string() } else { "Unable to insert location for sync.".to_string() }))?;

    Ok(insert_result > 0)
}

/// Inserts a series location element for sync.
pub fn insert_sync_location_element(
    conn: &Connection, element_id: &str, location_id: &str, user_id: &str,
    element_name: &str, original_name: &str, element_description: Option<&str>, last_update: i64, lang: Lang,
) -> AppResult<bool> {
    let insert_result = conn
        .execute(
            "INSERT INTO series_location_elements (element_id, location_id, user_id, element_name, original_name, element_description, last_update) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7) ON CONFLICT(element_id) DO UPDATE SET element_name = excluded.element_name, original_name = excluded.original_name, element_description = excluded.element_description, last_update = excluded.last_update",
            params![element_id, location_id, user_id, element_name, original_name, element_description, last_update],
        )
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible d'insérer l'élément de lieu pour sync.".to_string() } else { "Unable to insert location element for sync.".to_string() }))?;

    Ok(insert_result > 0)
}

/// Inserts a series location sub-element for sync.
pub fn insert_sync_location_sub_element(
    conn: &Connection, sub_element_id: &str, element_id: &str, user_id: &str,
    sub_elem_name: &str, original_name: &str, sub_elem_description: Option<&str>, last_update: i64, lang: Lang,
) -> AppResult<bool> {
    let insert_result = conn
        .execute(
            "INSERT INTO series_location_sub_elements (sub_element_id, element_id, user_id, sub_elem_name, original_name, sub_elem_description, last_update) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7) ON CONFLICT(sub_element_id) DO UPDATE SET sub_elem_name = excluded.sub_elem_name, original_name = excluded.original_name, sub_elem_description = excluded.sub_elem_description, last_update = excluded.last_update",
            params![sub_element_id, element_id, user_id, sub_elem_name, original_name, sub_elem_description, last_update],
        )
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible d'insérer le sous-élément pour sync.".to_string() } else { "Unable to insert sub-element for sync.".to_string() }))?;

    Ok(insert_result > 0)
}

/// Fetches all location elements for a series by series ID.
pub fn fetch_series_location_elements_by_series_id(conn: &Connection, user_id: &str, series_id: &str, lang: Lang) -> AppResult<Vec<SeriesLocationElementsTableResult>> {
    let mut statement = conn
        .prepare("SELECT sle.element_id, sle.location_id, sle.user_id, sle.element_name, sle.original_name, sle.element_description, sle.last_update FROM series_location_elements sle INNER JOIN series_locations sl ON sle.location_id = sl.loc_id WHERE sl.series_id = ?1 AND sl.user_id = ?2")
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les éléments de lieu par série.".to_string() } else { "Unable to retrieve location elements by series.".to_string() }))?;

    let elements = statement
        .query_map(params![series_id, user_id], |query_row| {
            Ok(SeriesLocationElementsTableResult {
                element_id: query_row.get(0)?, location_id: query_row.get(1)?, user_id: query_row.get(2)?,
                element_name: query_row.get(3)?, original_name: query_row.get(4)?,
                element_description: query_row.get(5)?, last_update: query_row.get(6)?,
            })
        })
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les éléments de lieu par série.".to_string() } else { "Unable to retrieve location elements by series.".to_string() }))?
        .collect::<Result<Vec<_>, _>>()
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les éléments de lieu par série.".to_string() } else { "Unable to retrieve location elements by series.".to_string() }))?;

    Ok(elements)
}

/// Fetches all location sub-elements for a series by series ID.
pub fn fetch_series_location_sub_elements_by_series_id(conn: &Connection, user_id: &str, series_id: &str, lang: Lang) -> AppResult<Vec<SeriesLocationSubElementsTableResult>> {
    let mut statement = conn
        .prepare("SELECT slse.sub_element_id, slse.element_id, slse.user_id, slse.sub_elem_name, slse.original_name, slse.sub_elem_description, slse.last_update FROM series_location_sub_elements slse INNER JOIN series_location_elements sle ON slse.element_id = sle.element_id INNER JOIN series_locations sl ON sle.location_id = sl.loc_id WHERE sl.series_id = ?1 AND sl.user_id = ?2")
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les sous-éléments de lieu par série.".to_string() } else { "Unable to retrieve location sub-elements by series.".to_string() }))?;

    let sub_elements = statement
        .query_map(params![series_id, user_id], |query_row| {
            Ok(SeriesLocationSubElementsTableResult {
                sub_element_id: query_row.get(0)?, element_id: query_row.get(1)?, user_id: query_row.get(2)?,
                sub_elem_name: query_row.get(3)?, original_name: query_row.get(4)?,
                sub_elem_description: query_row.get(5)?, last_update: query_row.get(6)?,
            })
        })
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les sous-éléments de lieu par série.".to_string() } else { "Unable to retrieve location sub-elements by series.".to_string() }))?
        .collect::<Result<Vec<_>, _>>()
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les sous-éléments de lieu par série.".to_string() } else { "Unable to retrieve location sub-elements by series.".to_string() }))?;

    Ok(sub_elements)
}

/// Checks if a series location exists (alias for is_location_exist).
pub fn series_location_exists(conn: &Connection, user_id: &str, location_id: &str, lang: Lang) -> AppResult<bool> {
    is_location_exist(conn, user_id, location_id, lang)
}

/// Checks if a series location element exists (alias for is_location_element_exist).
pub fn series_location_element_exists(conn: &Connection, user_id: &str, element_id: &str, lang: Lang) -> AppResult<bool> {
    is_location_element_exist(conn, user_id, element_id, lang)
}

/// Checks if a series location sub-element exists (alias for is_location_sub_element_exist).
pub fn series_location_sub_element_exists(conn: &Connection, user_id: &str, sub_element_id: &str, lang: Lang) -> AppResult<bool> {
    is_location_sub_element_exist(conn, user_id, sub_element_id, lang)
}

/// Inserts a series location for sync (alias with compatible signature).
pub fn insert_sync_series_location(
    conn: &Connection, location_id: &str, series_id: &str, user_id: &str,
    loc_name: &str, loc_original_name: &str, last_update: i64, lang: Lang,
) -> AppResult<bool> {
    insert_sync_location(conn, location_id, series_id, user_id, loc_name, loc_original_name, last_update, lang)
}

/// Updates a series location for sync (without original_name).
pub fn update_sync_series_location(conn: &Connection, location_id: &str, user_id: &str, loc_name: &str, last_update: i64, lang: Lang) -> AppResult<bool> {
    let update_result = conn
        .execute(
            "UPDATE series_locations SET loc_name = ?1, last_update = ?2 WHERE loc_id = ?3 AND user_id = ?4",
            params![loc_name, last_update, location_id, user_id],
        )
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de mettre à jour le lieu série pour sync.".to_string() } else { "Unable to update series location for sync.".to_string() }))?;

    Ok(update_result > 0)
}

/// Inserts a series location element for sync (alias with compatible signature).
pub fn insert_sync_series_location_element(
    conn: &Connection, element_id: &str, location_id: &str, user_id: &str,
    element_name: &str, original_name: &str, element_description: Option<&str>, last_update: i64, lang: Lang,
) -> AppResult<bool> {
    insert_sync_location_element(conn, element_id, location_id, user_id, element_name, original_name, element_description, last_update, lang)
}

/// Updates a series location element for sync (without original_name).
pub fn update_sync_series_location_element(conn: &Connection, element_id: &str, user_id: &str, element_name: &str, element_description: Option<&str>, last_update: i64, lang: Lang) -> AppResult<bool> {
    let update_result = conn
        .execute(
            "UPDATE series_location_elements SET element_name = ?1, element_description = ?2, last_update = ?3 WHERE element_id = ?4 AND user_id = ?5",
            params![element_name, element_description, last_update, element_id, user_id],
        )
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de mettre à jour l'élément de lieu série pour sync.".to_string() } else { "Unable to update series location element for sync.".to_string() }))?;

    Ok(update_result > 0)
}

/// Inserts a series location sub-element for sync (alias with compatible signature).
pub fn insert_sync_series_location_sub_element(
    conn: &Connection, sub_element_id: &str, element_id: &str, user_id: &str,
    sub_elem_name: &str, original_name: &str, sub_elem_description: Option<&str>, last_update: i64, lang: Lang,
) -> AppResult<bool> {
    insert_sync_location_sub_element(conn, sub_element_id, element_id, user_id, sub_elem_name, original_name, sub_elem_description, last_update, lang)
}

/// Updates a series location sub-element for sync (without original_name).
pub fn update_sync_series_location_sub_element(conn: &Connection, sub_element_id: &str, user_id: &str, sub_elem_name: &str, sub_elem_description: Option<&str>, last_update: i64, lang: Lang) -> AppResult<bool> {
    let update_result = conn
        .execute(
            "UPDATE series_location_sub_elements SET sub_elem_name = ?1, sub_elem_description = ?2, last_update = ?3 WHERE sub_element_id = ?4 AND user_id = ?5",
            params![sub_elem_name, sub_elem_description, last_update, sub_element_id, user_id],
        )
        .map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de mettre à jour le sous-élément série pour sync.".to_string() } else { "Unable to update series sub-element for sync.".to_string() }))?;

    Ok(update_result > 0)
}
