use serde::{Deserialize, Serialize};

/// Memory categories for the memory system.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum MemoryCategory {
    /// Long-term facts, preferences, patterns, insights (merged fact+insight).
    Knowledge,
    /// Conversation summaries produced by context compression.
    Timeline,
}

impl MemoryCategory {
    pub fn as_str(&self) -> &str {
        match self {
            Self::Knowledge => "knowledge",
            Self::Timeline => "timeline",
        }
    }

    pub fn parse(s: &str) -> Option<Self> {
        match s {
            "knowledge" => Some(Self::Knowledge),
            "timeline" => Some(Self::Timeline),
            _ => None,
        }
    }
}

/// A single memory entry stored in SQLite.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MemoryEntry {
    pub id: String,
    /// Semantic identifier (e.g. "user_prefers_rust").
    pub key: String,
    /// The memory content.
    pub content: String,
    /// Category: knowledge or timeline.
    pub category: MemoryCategory,
    /// Importance score 0.0–1.0 (default 0.5).
    pub importance: f64,
    /// Associated session ID (optional).
    pub session_id: Option<String>,
    /// RFC 3339 creation timestamp.
    pub created_at: String,
    /// RFC 3339 last update timestamp.
    pub updated_at: String,
}

/// Result from an LLM consolidation call.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConsolidationResult {
    /// New or updated knowledge entries extracted from conversation.
    pub facts: Vec<ConsolidationFact>,
    /// Summary entry for timeline (formatted as "[YYYY-MM-DD HH:MM] text...").
    pub timeline: Option<String>,
    /// Keys of existing memories that should be invalidated.
    pub invalidations: Vec<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConsolidationFact {
    pub key: String,
    pub content: String,
    pub importance: f64,
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_memory_category_as_str() {
        assert_eq!(MemoryCategory::Knowledge.as_str(), "knowledge");
        assert_eq!(MemoryCategory::Timeline.as_str(), "timeline");
    }

    #[test]
    fn test_memory_category_from_str() {
        assert_eq!(
            MemoryCategory::parse("knowledge"),
            Some(MemoryCategory::Knowledge)
        );
        assert_eq!(
            MemoryCategory::parse("timeline"),
            Some(MemoryCategory::Timeline)
        );
        assert_eq!(MemoryCategory::parse("invalid"), None);
    }
}
