use crate::llm::AppState;
use serde::{Deserialize, Serialize};

#[derive(Debug, Deserialize)]
pub struct RagAddRequest {
    pub source: String,
    pub text: String,
}

#[derive(Debug, Serialize)]
pub struct RagHit {
    pub text: String,
    pub source: String,
    pub score: f32,
}

#[derive(Debug, Serialize)]
pub struct RagSource {
    pub source: String,
    pub chunks: i64,
}

#[tauri::command]
pub async fn rag_add(state: tauri::State<'_, AppState>, req: RagAddRequest) -> Result<usize, String> {
    let config = state.config.lock().map_err(|e| e.to_string())?.clone();
    state.rag.add_document(&config, &req.source, &req.text).await.map_err(|e| e.to_string())
}

#[tauri::command]
pub async fn rag_search(
    state: tauri::State<'_, AppState>,
    query: String,
    top_k: Option<usize>,
) -> Result<Vec<RagHit>, String> {
    let config = state.config.lock().map_err(|e| e.to_string())?.clone();
    let hits = state
        .rag
        .search(&config, &query, top_k.unwrap_or(4))
        .await
        .map_err(|e| e.to_string())?;
    Ok(hits.into_iter().map(|(text, source, score)| RagHit { text, source, score }).collect())
}

#[tauri::command]
pub fn rag_list(state: tauri::State<'_, AppState>) -> Result<Vec<RagSource>, String> {
    state
        .rag
        .list_sources()
        .map_err(|e| e.to_string())?
        .into_iter()
        .map(|(source, chunks)| Ok(RagSource { source, chunks }))
        .collect()
}

#[tauri::command]
pub fn rag_clear(state: tauri::State<'_, AppState>, source: Option<String>) -> Result<(), String> {
    state.rag.clear(source.as_deref()).map_err(|e| e.to_string())
}