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

fn get_history_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("query_history.json"))
}

#[tauri::command]
pub async fn add_history_entry(app: AppHandle, entry: HistoryEntry) -> TuskResult<()> {
    let path = get_history_path(&app)?;
    let mut entries = if path.exists() {
        let data = fs::read_to_string(&path)?;
        serde_json::from_str::<Vec<HistoryEntry>>(&data).unwrap_or_default()
    } else {
        vec![]
    };

    entries.insert(0, entry);
    entries.truncate(500);

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

#[tauri::command]
pub async fn get_history(
    app: AppHandle,
    connection_id: Option<String>,
    search: Option<String>,
    limit: Option<usize>,
) -> TuskResult<Vec<HistoryEntry>> {
    let path = get_history_path(&app)?;
    if !path.exists() {
        return Ok(vec![]);
    }
    let data = fs::read_to_string(&path)?;
    let entries: Vec<HistoryEntry> = serde_json::from_str(&data).unwrap_or_default();

    let filtered: Vec<HistoryEntry> = entries
        .into_iter()
        .filter(|e| {
            if let Some(ref cid) = connection_id {
                if &e.connection_id != cid {
                    return false;
                }
            }
            if let Some(ref s) = search {
                let lower = s.to_lowercase();
                if !e.sql.to_lowercase().contains(&lower) {
                    return false;
                }
            }
            true
        })
        .take(limit.unwrap_or(100))
        .collect();

    Ok(filtered)
}

#[tauri::command]
pub async fn clear_history(app: AppHandle) -> TuskResult<()> {
    let path = get_history_path(&app)?;
    if path.exists() {
        fs::remove_file(&path)?;
    }
    Ok(())
}
