use anyhow::Result;
use uuid::Uuid;

use crate::schema::{Conversation, Entity, Memory, MemoryType, Relation, RelationType};

pub trait Store: Send + Sync {
    fn store_memory(&self, memory: &Memory) -> Result<()>;
    fn get_memory(&self, id: Uuid) -> Result<Option<Memory>>;
    fn delete_memory(&self, id: Uuid) -> Result<()>;

    fn store_entity(&self, entity: &Entity) -> Result<()>;
    fn get_entity(&self, id: Uuid) -> Result<Option<Entity>>;
    fn find_entity_by_name(&self, name: &str) -> Result<Option<Entity>>;

    fn store_conversation(&self, conversation: &Conversation) -> Result<()>;

    fn store_relation(&self, relation: &Relation) -> Result<()>;
    fn get_relations(
        &self,
        node_id: Uuid,
        relation_type: Option<RelationType>,
    ) -> Result<Vec<Relation>>;

    fn vector_search(&self, embedding: &[f32], limit: usize) -> Result<Vec<(Memory, f32)>>;

    fn traverse(&self, start_id: Uuid, depth: u32) -> Result<Vec<(Memory, Vec<Relation>)>>;

    fn memories_by_source(&self, source: &str) -> Result<Vec<Memory>>;
    fn memories_by_type(&self, memory_type: MemoryType) -> Result<Vec<Memory>>;
    fn memories_needing_decay(&self, threshold_days: u32) -> Result<Vec<Memory>>;

    fn update_memory(&self, memory: &Memory) -> Result<()>;

    fn record_access(&self, memory: &Memory) -> Result<()>;

    fn text_search(&self, query: &str, limit: usize) -> Result<Vec<Memory>>;

    fn memory_count(&self) -> Result<usize>;

    fn all_memory_ids(&self) -> Result<Vec<Uuid>>;

    // Every Memory-rooted edge as a Relation, mirroring get_relations: strength
    // is always 1.0 and context is always None (get_relations discards edge
    // properties), so a bulk fetch is interchangeable with per-id reads. Used to
    // prewarm a relation cache in one scan instead of thousands of point reads.
    fn all_relations(&self) -> Result<Vec<Relation>>;
}
