use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use uuid::Uuid;

use crate::extraction::MemoryType;

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Memory {
    pub id: Uuid,
    pub user_id: Uuid,
    pub conversation_id: Option<Uuid>,
    pub text: String,
    #[serde(rename = "type")]
    pub memory_type: MemoryType,
    pub importance: f32,
    pub is_active: bool,
    pub embedding: Option<Vec<f32>>,
    pub metadata: Option<serde_json::Value>,
    pub created_at: DateTime<Utc>,
    pub updated_at: DateTime<Utc>,
    pub occurred_at: Option<DateTime<Utc>>,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "UPPERCASE")]
pub enum MemoryAction {
    Add,
    Update,
    Replace,
    Delete,
    Noop,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct MemoryDecision {
    pub action: MemoryAction,
    pub memory_id: Option<Uuid>,
    pub text: Option<String>,
}

impl MemoryDecision {
    pub fn noop() -> Self {
        Self {
            action: MemoryAction::Noop,
            memory_id: None,
            text: None,
        }
    }

    pub fn add(text: impl Into<String>) -> Self {
        Self {
            action: MemoryAction::Add,
            memory_id: None,
            text: Some(text.into()),
        }
    }

    pub fn update(memory_id: Uuid, text: impl Into<String>) -> Self {
        Self {
            action: MemoryAction::Update,
            memory_id: Some(memory_id),
            text: Some(text.into()),
        }
    }

    pub fn replace(memory_id: Uuid, text: impl Into<String>) -> Self {
        Self {
            action: MemoryAction::Replace,
            memory_id: Some(memory_id),
            text: Some(text.into()),
        }
    }

    pub fn delete(memory_id: Uuid) -> Self {
        Self {
            action: MemoryAction::Delete,
            memory_id: Some(memory_id),
            text: None,
        }
    }
}
