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

fn epoch() -> DateTime<Utc> {
    DateTime::UNIX_EPOCH
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum MemoryType {
    Episodic,
    Semantic,
    Procedural,
    Decision,
    Architecture,
    Debugging,
    Task,
    Question,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Memory {
    pub id: Uuid,
    pub content: String,
    pub embedding: Vec<f32>,
    pub memory_type: MemoryType,
    pub confidence: f32,
    pub created_at: DateTime<Utc>,
    pub last_accessed: DateTime<Utc>,
    pub access_count: u32,
    pub source: String,
    pub source_id: String,
    #[serde(default)]
    pub project_path: Option<String>,
    #[serde(default)]
    pub machine_id: String,
    #[serde(default = "epoch")]
    pub updated_at: DateTime<Utc>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Entity {
    pub id: Uuid,
    pub name: String,
    pub entity_type: String,
    pub embedding: Vec<f32>,
    pub aliases: Vec<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Conversation {
    pub id: Uuid,
    pub source: String,
    pub machine_id: String,
    pub started_at: DateTime<Utc>,
    pub project_path: Option<String>,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum RelationType {
    RelatesTo,
    Mentions,
    DerivedFrom,
    Contradicts,
    Reinforces,
    Supersedes,
    DistilledFrom,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Relation {
    pub from_id: Uuid,
    pub to_id: Uuid,
    pub relation_type: RelationType,
    pub strength: f32,
    pub context: Option<String>,
}

impl Memory {
    pub fn new(
        content: String,
        memory_type: MemoryType,
        source: String,
        source_id: String,
    ) -> Self {
        let now = Utc::now();
        Self {
            id: Uuid::new_v4(),
            content,
            embedding: Vec::new(),
            memory_type,
            confidence: 1.0,
            created_at: now,
            last_accessed: now,
            access_count: 0,
            source,
            source_id,
            project_path: None,
            machine_id: String::new(),
            updated_at: now,
        }
    }

    pub fn with_project_path(mut self, path: Option<String>) -> Self {
        self.project_path = path;
        self
    }

    pub fn with_machine_id(mut self, machine_id: String) -> Self {
        self.machine_id = machine_id;
        self
    }

    pub fn reinforce(&mut self) {
        self.access_count += 1;
        self.last_accessed = Utc::now();
        self.confidence = (self.confidence + 0.1).min(1.0);
    }
}

impl Entity {
    pub fn new(name: String, entity_type: String) -> Self {
        Self {
            id: Uuid::new_v4(),
            name,
            entity_type,
            embedding: Vec::new(),
            aliases: Vec::new(),
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum SyncOp {
    Create,
    Update,
    Delete,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum SyncNodeType {
    Memory,
    Entity,
    Conversation,
    Relation,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SyncEntry {
    pub id: String,
    pub local_seq: i64,
    pub origin_machine_id: String,
    pub origin_seq: i64,
    pub op: SyncOp,
    pub node_type: SyncNodeType,
    pub node_id: String,
    pub timestamp: DateTime<Utc>,
    pub data: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SyncState {
    pub peer_id: String,
    pub last_seq: u64,
    pub last_sync_at: DateTime<Utc>,
}
