use crate::error::{TuskError, TuskResult};
use crate::models::saved_queries::SavedQuery;
use std::fs;
use tauri::{AppHandle, Manager};

fn get_saved_queries_path(app: &AppHandle) -> TuskResult<std::path::PathBuf> {
    let dir = app
        .path()
        .app_data_dir()
        .map_err(|e| TuskError::Config(e.to_string()))?;
    fs::create_dir_all(&dir)?;
    Ok(dir.join("saved_queries.json"))
}

pub(crate) async fn list_saved_queries_core(
    app: &AppHandle,
    search: Option<&str>,
) -> TuskResult<Vec<SavedQuery>> {
    let path = get_saved_queries_path(app)?;
    if !path.exists() {
        return Ok(vec![]);
    }
    let data = fs::read_to_string(&path)?;
    let entries: Vec<SavedQuery> = serde_json::from_str(&data).unwrap_or_default();

    let filtered: Vec<SavedQuery> = entries
        .into_iter()
        .filter(|e| {
            if let Some(s) = search {
                let lower = s.to_lowercase();
                e.name.to_lowercase().contains(&lower) || e.sql.to_lowercase().contains(&lower)
            } else {
                true
            }
        })
        .collect();

    Ok(filtered)
}

pub(crate) async fn save_query_core(app: &AppHandle, query: SavedQuery) -> TuskResult<()> {
    let path = get_saved_queries_path(app)?;
    let mut entries = if path.exists() {
        let data = fs::read_to_string(&path)?;
        serde_json::from_str::<Vec<SavedQuery>>(&data).unwrap_or_default()
    } else {
        vec![]
    };

    entries.insert(0, query);

    let data = serde_json::to_string_pretty(&entries)?;
    fs::write(&path, data)?;
    Ok(())
}

/// Drop every saved-query entry tied to a specific connection_id. Entries with
/// `connection_id == None` (older "global" saves) are deliberately preserved
/// so they remain visible across all connections.
pub(crate) async fn delete_by_connection_core(
    app: &AppHandle,
    connection_id: &str,
) -> TuskResult<()> {
    let path = get_saved_queries_path(app)?;
    if !path.exists() {
        return Ok(());
    }
    let data = fs::read_to_string(&path)?;
    let mut entries: Vec<SavedQuery> = serde_json::from_str(&data).unwrap_or_default();
    let before = entries.len();
    entries.retain(|e| e.connection_id.as_deref() != Some(connection_id));
    if entries.len() == before {
        return Ok(());
    }
    let data = serde_json::to_string_pretty(&entries)?;
    fs::write(&path, data)?;
    Ok(())
}

#[tauri::command]
pub async fn list_saved_queries(
    app: AppHandle,
    search: Option<String>,
) -> TuskResult<Vec<SavedQuery>> {
    list_saved_queries_core(&app, search.as_deref()).await
}

#[tauri::command]
pub async fn save_query(app: AppHandle, query: SavedQuery) -> TuskResult<()> {
    save_query_core(&app, query).await
}

#[tauri::command]
pub async fn delete_saved_query(app: AppHandle, id: String) -> TuskResult<()> {
    let path = get_saved_queries_path(&app)?;
    if !path.exists() {
        return Ok(());
    }
    let data = fs::read_to_string(&path)?;
    let mut entries: Vec<SavedQuery> = serde_json::from_str(&data).unwrap_or_default();
    entries.retain(|e| e.id != id);

    let data = serde_json::to_string_pretty(&entries)?;
    fs::write(&path, data)?;
    Ok(())
}
