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

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

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

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

#[tauri::command]
pub fn get_spell_tags(data: GetSpellTagsData, db: State<DbManager>, session: State<SessionState>) -> Result<Vec<service::SpellTagProps>, 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_spell_tags(conn, &user_id, &data.book_id, lang)
}

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

#[tauri::command]
pub fn get_spell_detail(data: GetSpellDetailData, db: State<DbManager>, session: State<SessionState>) -> Result<service::SpellProps, 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_spell_detail(conn, &user_id, &data.spell_id, lang)
}

#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SpellData {
    pub name: String,
    pub description: String,
    pub appearance: String,
    pub tags: Vec<String>,
    pub power_level: Option<String>,
    pub components: Option<String>,
    pub limitations: Option<String>,
    pub notes: Option<String>,
    pub series_spell_id: Option<String>,
}

#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CreateSpellData {
    pub book_id: String,
    pub spell: SpellData,
}

#[tauri::command]
pub fn create_spell(data: CreateSpellData, db: State<DbManager>, session: State<SessionState>) -> Result<service::SpellProps, 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_spell(
        conn, &user_id, &data.book_id, &data.spell.name, &data.spell.description, &data.spell.appearance,
        data.spell.tags, data.spell.power_level.as_deref(), data.spell.components.as_deref(),
        data.spell.limitations.as_deref(), data.spell.notes.as_deref(), None, lang, data.spell.series_spell_id.as_deref(),
    )
}

#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct UpdateSpellData {
    pub spell_id: String,
    pub spell: SpellData,
}

#[tauri::command]
pub fn update_spell(data: UpdateSpellData, 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_spell(
        conn, &user_id, &data.spell_id, &data.spell.name, &data.spell.description, &data.spell.appearance,
        data.spell.tags, data.spell.power_level.as_deref(), data.spell.components.as_deref(),
        data.spell.limitations.as_deref(), data.spell.notes.as_deref(), lang, data.spell.series_spell_id.as_deref(),
    )
}

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

#[tauri::command]
pub fn delete_spell(data: DeleteSpellData, 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_spell(conn, &user_id, &data.book_id, &data.spell_id, data.deleted_at, lang)
}

#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CreateSpellTagData {
    pub book_id: String,
    pub name: String,
    pub color: Option<String>,
    pub id: Option<String>,
}

#[tauri::command]
pub fn create_spell_tag(data: CreateSpellTagData, db: State<DbManager>, session: State<SessionState>) -> Result<service::SpellTagProps, 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_spell_tag(conn, &user_id, &data.book_id, &data.name, data.color.as_deref(), data.id.as_deref(), lang)
}

#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct UpdateSpellTagData {
    pub tag_id: String,
    pub name: String,
    pub color: Option<String>,
}

#[tauri::command]
pub fn update_spell_tag(data: UpdateSpellTagData, 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_spell_tag(conn, &user_id, &data.tag_id, &data.name, data.color.as_deref(), lang)
}

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

#[tauri::command]
pub fn delete_spell_tag(data: DeleteSpellTagData, 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_spell_tag(conn, &user_id, &data.book_id, &data.tag_id, data.deleted_at, lang)
}
