//! Semantic cache check and store operations.

use super::super::AppState;
use super::super::guards::{is_low_value_response, is_parroting_user_prompt};

/// Check the semantic cache. Returns `Some(CachedResponse)` on hit.
pub(crate) async fn check_cache(
    state: &AppState,
    user_content: &str,
    cache_hash: &str,
    query_embedding: Option<&[f32]>,
) -> Option<roboticus_llm::CachedResponse> {
    let _ = user_content;
    let _ = query_embedding;
    // Cache is wrapped in its own Mutex — only a read lock on LlmService needed.
    let llm = state.llm.read().await;
    let mut cache = llm.cache.lock().unwrap_or_else(|e| {
        tracing::warn!("cache lock poisoned during lookup; recovering");
        e.into_inner()
    });
    cache.lookup_strict(cache_hash)
}

/// Store a response in the semantic cache.
pub(crate) async fn store_in_cache(
    state: &AppState,
    cache_hash: &str,
    user_content: &str,
    content: &str,
    model: &str,
    tokens_out: i64,
    intents: &[super::super::intent_registry::Intent],
) {
    if tokens_out > 0
        && !is_low_value_response(user_content, content, intents)
        && !is_parroting_user_prompt(user_content, content)
    {
        let entry = roboticus_llm::CachedResponse {
            content: content.to_string(),
            model: model.to_string(),
            tokens_saved: tokens_out.clamp(0, u32::MAX as i64) as u32,
            created_at: std::time::Instant::now(),
            expires_at: std::time::Instant::now() + std::time::Duration::from_secs(3600),
            hits: 0,
            involved_tools: false,
            embedding: None,
        };
        let llm = state.llm.read().await;
        let mut cache = llm.cache.lock().unwrap_or_else(|e| {
            tracing::warn!("cache lock poisoned during store; recovering");
            e.into_inner()
        });
        cache.store_with_embedding(cache_hash, user_content, entry);
    }
}
