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

use crate::db::connection::DbManager;
use crate::domains::character::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 GetCharacterListData {
    pub book_id: String,
}

#[tauri::command]
pub fn get_character_list(data: GetCharacterListData, db: State<DbManager>, session: State<SessionState>) -> Result<service::CharacterListResponse, 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_character_list(conn, &user_id, &data.book_id, lang)
}

#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct GetCharacterAttributesData {
    pub character_id: String,
}

#[tauri::command]
pub fn get_character_attributes(data: GetCharacterAttributesData, db: State<DbManager>, session: State<SessionState>) -> Result<Vec<service::CharacterAttribute>, 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_attributes(conn, &data.character_id, &user_id, lang)
}

#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CreateCharacterData {
    pub character: service::CharacterPropsPost,
    pub book_id: String,
    pub id: Option<String>,
}

#[tauri::command]
pub fn create_character(data: CreateCharacterData, 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_new_character(conn, &user_id, &data.character, &data.book_id, lang, data.id.as_deref())
}

#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct AddCharacterAttributeData {
    pub character_id: String,
    pub r#type: String,
    pub name: String,
    pub id: Option<String>,
}

#[tauri::command]
pub fn add_character_attribute(data: AddCharacterAttributeData, 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_new_attribute(conn, &data.character_id, &user_id, &data.r#type, &data.name, lang, data.id.as_deref())
}

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

#[tauri::command]
pub fn delete_character_attribute(data: DeleteCharacterAttributeData, 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_attribute(conn, &user_id, &data.book_id, &data.attribute_id, data.deleted_at, lang)
}

#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct UpdateCharacterData {
    pub character: service::CharacterPropsPost,
}

#[tauri::command]
pub fn update_character(data: UpdateCharacterData, 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::update_character(conn, &user_id, &data.character, lang)
}

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

#[tauri::command]
pub fn delete_character(data: DeleteCharacterData, 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_character(conn, &user_id, &data.book_id, &data.character_id, data.deleted_at, lang)
}
