use serde::Deserialize;
use tauri::State;

use crate::db::connection::DbManager;
use crate::domains::series_location::service;
use crate::error::AppError;
use crate::shared::session::SessionState;
use crate::shared::types::Lang;

fn get_session(session: &State<SessionState>) -> Result<(String, Lang), AppError> {
    let session_guard = session.lock().map_err(|e| AppError::Internal(format!("Session lock failed: {}", e)))?;
    let user_id = session_guard.get_user_id().map_err(|e| AppError::Auth(e))?.to_string();
    let lang = session_guard.lang;
    Ok((user_id, lang))
}

#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct GetSeriesLocationListData { pub series_id: String }

#[tauri::command]
pub fn get_series_location_list(data: GetSeriesLocationListData, db: State<DbManager>, session: State<SessionState>) -> Result<Vec<service::SeriesLocationListProps>, AppError> {
    let (user_id, lang) = get_session(&session)?;
    let db_manager = db.lock().map_err(|e| AppError::Internal(format!("DB lock failed: {}", e)))?;
    let conn = db_manager.get_connection(&user_id)?;
    service::get_location_list(conn, &user_id, &data.series_id, lang)
}

#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct AddSeriesLocationSectionData { pub series_id: String, pub name: String }

#[tauri::command]
pub fn add_series_location_section(data: AddSeriesLocationSectionData, db: State<DbManager>, session: State<SessionState>) -> Result<String, AppError> {
    let (user_id, lang) = get_session(&session)?;
    let db_manager = db.lock().map_err(|e| AppError::Internal(format!("DB lock failed: {}", e)))?;
    let conn = db_manager.get_connection(&user_id)?;
    service::add_location_section(conn, &user_id, &data.series_id, &data.name, lang)
}

#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct AddSeriesLocationElementData { pub location_id: String, pub name: String, pub description: Option<String> }

#[tauri::command]
pub fn add_series_location_element(data: AddSeriesLocationElementData, db: State<DbManager>, session: State<SessionState>) -> Result<String, AppError> {
    let (user_id, lang) = get_session(&session)?;
    let db_manager = db.lock().map_err(|e| AppError::Internal(format!("DB lock failed: {}", e)))?;
    let conn = db_manager.get_connection(&user_id)?;
    service::add_element(conn, &user_id, &data.location_id, &data.name, lang, data.description.as_deref())
}

#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct AddSeriesLocationSubElementData { pub element_id: String, pub name: String, pub description: Option<String> }

#[tauri::command]
pub fn add_series_location_sub_element(data: AddSeriesLocationSubElementData, db: State<DbManager>, session: State<SessionState>) -> Result<String, AppError> {
    let (user_id, lang) = get_session(&session)?;
    let db_manager = db.lock().map_err(|e| AppError::Internal(format!("DB lock failed: {}", e)))?;
    let conn = db_manager.get_connection(&user_id)?;
    service::add_sub_element(conn, &user_id, &data.element_id, &data.name, lang, data.description.as_deref())
}

#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct DeleteSeriesLocationData { pub location_id: String, pub deleted_at: i64 }

#[tauri::command]
pub fn delete_series_location(data: DeleteSeriesLocationData, db: State<DbManager>, session: State<SessionState>) -> Result<bool, AppError> {
    let (user_id, lang) = get_session(&session)?;
    let db_manager = db.lock().map_err(|e| AppError::Internal(format!("DB lock failed: {}", e)))?;
    let conn = db_manager.get_connection(&user_id)?;
    service::delete_location(conn, &user_id, &data.location_id, data.deleted_at, lang)
}

#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct DeleteSeriesLocationElementData { pub element_id: String, pub deleted_at: i64 }

#[tauri::command]
pub fn delete_series_location_element(data: DeleteSeriesLocationElementData, db: State<DbManager>, session: State<SessionState>) -> Result<bool, AppError> {
    let (user_id, lang) = get_session(&session)?;
    let db_manager = db.lock().map_err(|e| AppError::Internal(format!("DB lock failed: {}", e)))?;
    let conn = db_manager.get_connection(&user_id)?;
    service::delete_element(conn, &user_id, &data.element_id, data.deleted_at, lang)
}

#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct DeleteSeriesLocationSubElementData { pub sub_element_id: String, pub deleted_at: i64 }

#[tauri::command]
pub fn delete_series_location_sub_element(data: DeleteSeriesLocationSubElementData, db: State<DbManager>, session: State<SessionState>) -> Result<bool, AppError> {
    let (user_id, lang) = get_session(&session)?;
    let db_manager = db.lock().map_err(|e| AppError::Internal(format!("DB lock failed: {}", e)))?;
    let conn = db_manager.get_connection(&user_id)?;
    service::delete_sub_element(conn, &user_id, &data.sub_element_id, data.deleted_at, lang)
}
