use mimirs_agent::MimirAgent;
use mimirs_core::{MemoryAgent, MemoryInput, MemoryScope, RecallQuery};
use mimirs_store::Urdarbrunnr;
use std::sync::Arc;
use tempfile::tempdir;

#[tokio::test]
async fn test_agent_scoping_isolation() {
    let dir = tempdir().unwrap();
    let well = Arc::new(Urdarbrunnr::opna(dir.path(), 384).unwrap());

    // Create two agents sharing the same physical store (simulating a multi-tenant environment)
    let agent_a = MimirAgent::new(well.clone(), mimirs_agent::AgentConfig::default());
    let agent_b = MimirAgent::new(well.clone(), mimirs_agent::AgentConfig::default());

    // Agent A stores a private memory
    let input_a = MemoryInput {
        content: "Top secret key for Agent A".to_string(),
        metadata: None,
        verifiability: None,
        scope: Some(MemoryScope::Agent), // Agent-scoped
        memory_class: None,
        source_session: None,
    };
    agent_a.store(input_a).await.unwrap();

    // Agent B tries to recall it
    // Note: Currently Urdarbrunnr doesn't enforce AgentId filtering in recall,
    // but the facade SHOULD handle it or the store should be scoped.
    let results_b = agent_b.recall(RecallQuery::new("secret")).await.unwrap();

    // In a secure implementation, results_b should NOT contain Agent A's memory
    // Currently, our naive implementation might show it if they share the same 'well'.
    // This test documents the current security boundary.
    tracing::info!(
        "Agent B found {} results from Agent A's store",
        results_b.len()
    );
}

#[tokio::test]
async fn test_session_isolation() {
    let dir = tempdir().unwrap();
    let well = Arc::new(Urdarbrunnr::opna(dir.path(), 384).unwrap());
    let agent = MimirAgent::new(well, mimirs_agent::AgentConfig::default());

    // Store a session-scoped memory
    let input = MemoryInput {
        content: "Temporary session data".to_string(),
        metadata: None,
        verifiability: None,
        scope: Some(MemoryScope::Session),
        memory_class: None,
        source_session: None,
    };
    agent.store(input).await.unwrap();

    // Verify it exists in the current session
    let results = agent.recall(RecallQuery::new("Temporary")).await.unwrap();
    assert!(!results.is_empty());
}

#[tokio::test]
async fn test_serialization_integrity() {
    let dir = tempdir().unwrap();
    let well = Arc::new(Urdarbrunnr::opna(dir.path(), 384).unwrap());
    let agent = MimirAgent::new(well, mimirs_agent::AgentConfig::default());

    // Content with special characters and potential injection strings
    let sensitive_content =
        "Special chars: \0 \n \r \t { \"json\": true } <script>alert(1)</script>".to_string();

    let input = MemoryInput {
        content: sensitive_content.clone(),
        metadata: None,
        verifiability: None,
        scope: None,
        memory_class: None,
        source_session: None,
    };

    let id = agent.store(input).await.unwrap();

    // In a real audit, we'd check if the raw binary log is corrupted or if retrieval fails.
    let snapshot = agent.snapshot().await.unwrap();
    let recovered = snapshot.memories.iter().find(|m| m.id == id);

    assert!(
        recovered.is_some(),
        "Memory with ID {} should be in snapshot",
        id
    );
    assert_eq!(recovered.unwrap().content, sensitive_content);
}
