//! Memory node types for AiFastDb
//! 
//! MemoryNode is the core data structure representing a piece of knowledge
//! with its embedding, metadata, and relationships.

use serde::{Deserialize, Serialize};
use uuid::Uuid;
use std::collections::HashMap;

use super::ownership::{Visibility, ProtectionLevel, Collaborator};

// ============================================================================
// Semantic Axes (BriLLM SiFu inspired)
// ============================================================================

/// 语义轴坐标（3 维语义空间）
///
/// 灵感来源于 Nature 2016 语义图谱研究（Huth et al.）及 BriLLM SiFu 架构。
/// 将高维 Embedding 投影到 3 个可解释的低维语义轴，用于：
/// - 语义门控（Semantic Gating）：缩小 ANN 搜索范围
/// - 语义区域聚类：类似大脑皮层的语义拼贴分布
/// - 查询可解释性：直观理解节点的语义定位
///
/// 三个轴对应人脑皮层语义分布的三个主成分方向。
/// 具体语义含义取决于投影器的训练方式：
/// - Random 模式：轴无特定语义含义（但保持距离关系）
/// - PCA 模式：对应数据中方差最大的 3 个方向
/// - Anchor 模式：对应用户定义的语义维度（如 Social/Sensory/Locality）
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
pub struct SemanticAxes {
    /// 语义轴 0（默认对应 Social 社会性维度）
    pub axis_0: f32,
    /// 语义轴 1（默认对应 Sensory 感官性维度）
    pub axis_1: f32,
    /// 语义轴 2（默认对应 Locality 位置性维度）
    pub axis_2: f32,
}

impl SemanticAxes {
    /// 创建语义轴坐标
    pub fn new(axis_0: f32, axis_1: f32, axis_2: f32) -> Self {
        Self { axis_0, axis_1, axis_2 }
    }

    /// 从切片创建（取前 3 个元素）
    pub fn from_slice(s: &[f32]) -> Self {
        Self {
            axis_0: s.first().copied().unwrap_or(0.0),
            axis_1: s.get(1).copied().unwrap_or(0.0),
            axis_2: s.get(2).copied().unwrap_or(0.0),
        }
    }

    /// 转换为数组
    pub fn to_array(&self) -> [f32; 3] {
        [self.axis_0, self.axis_1, self.axis_2]
    }

    /// 计算与另一个语义轴坐标的欧氏距离
    pub fn distance(&self, other: &SemanticAxes) -> f32 {
        let d0 = self.axis_0 - other.axis_0;
        let d1 = self.axis_1 - other.axis_1;
        let d2 = self.axis_2 - other.axis_2;
        (d0 * d0 + d1 * d1 + d2 * d2).sqrt()
    }

    /// 检查是否在指定的轴范围内
    pub fn in_range(
        &self,
        axis_0_range: Option<(f32, f32)>,
        axis_1_range: Option<(f32, f32)>,
        axis_2_range: Option<(f32, f32)>,
    ) -> bool {
        if let Some((min, max)) = axis_0_range {
            if self.axis_0 < min || self.axis_0 > max {
                return false;
            }
        }
        if let Some((min, max)) = axis_1_range {
            if self.axis_1 < min || self.axis_1 > max {
                return false;
            }
        }
        if let Some((min, max)) = axis_2_range {
            if self.axis_2 < min || self.axis_2 > max {
                return false;
            }
        }
        true
    }
}

impl Default for SemanticAxes {
    fn default() -> Self {
        Self { axis_0: 0.0, axis_1: 0.0, axis_2: 0.0 }
    }
}

// ============================================================================
// ID Validation
// ============================================================================

/// Error type for invalid ID
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct InvalidIdError {
    pub id: String,
    pub reason: String,
}

impl std::fmt::Display for InvalidIdError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "Invalid ID '{}': {}", self.id, self.reason)
    }
}

impl std::error::Error for InvalidIdError {}

/// Validate that an ID contains only ASCII alphanumeric characters, underscores, and hyphens.
/// 
/// Valid IDs:
/// - Must only contain: a-z, A-Z, 0-9, underscore (_), hyphen (-)
/// - Must not be empty
/// - Must not exceed 255 characters
/// 
/// # Examples
/// 
/// ```
/// use aifastdb_core::types::validate_id;
/// 
/// assert!(validate_id("user_123").is_ok());
/// assert!(validate_id("cat-tech").is_ok());
/// assert!(validate_id("ABC123").is_ok());
/// assert!(validate_id("cat_影视").is_err()); // Contains Chinese
/// assert!(validate_id("").is_err()); // Empty
/// ```
pub fn validate_id(id: &str) -> Result<(), InvalidIdError> {
    // Check for empty ID
    if id.is_empty() {
        return Err(InvalidIdError {
            id: id.to_string(),
            reason: "ID cannot be empty".to_string(),
        });
    }
    
    // Check length limit
    if id.len() > 255 {
        return Err(InvalidIdError {
            id: id.to_string(),
            reason: format!("ID exceeds maximum length of 255 characters (got {})", id.len()),
        });
    }
    
    // Check for valid characters: alphanumeric, underscore, hyphen
    for (i, c) in id.chars().enumerate() {
        if !c.is_ascii_alphanumeric() && c != '_' && c != '-' {
            return Err(InvalidIdError {
                id: id.to_string(),
                reason: format!(
                    "ID contains invalid character '{}' at position {}. Only ASCII letters (a-z, A-Z), digits (0-9), underscore (_), and hyphen (-) are allowed",
                    c, i
                ),
            });
        }
    }
    
    Ok(())
}

/// Check if an ID is valid without returning an error
pub fn is_valid_id(id: &str) -> bool {
    validate_id(id).is_ok()
}

/// Content type of a memory node
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ContentType {
    /// Plain text content
    Text,
    /// Image reference or description (legacy — for text-only image refs)
    Image,
    /// Code snippet
    Code,
    /// Conversation message
    Conversation,
    /// Document chunk
    Document,
    /// Audio data (WAV/MP3/FLAC/OGG — binary stored in blob column)
    Audio,
    /// Video data (MP4/WebM/AVI — binary stored in blob column)
    Video,
    /// Image binary (JPEG/PNG/WebP — binary stored in blob column)
    ImageBinary,
    /// Other/custom type
    Other,
}

impl Default for ContentType {
    fn default() -> Self {
        Self::Text
    }
}

/// A memory node representing a piece of knowledge in the database
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MemoryNode {
    /// Unique identifier
    pub id: String,
    
    // === Content Layer ===
    /// The actual content (text, code, etc.)
    pub content: String,
    
    /// Vector embedding of the content
    #[serde(skip_serializing_if = "Option::is_none")]
    pub embedding: Option<Vec<f32>>,
    
    /// Type of content
    pub content_type: ContentType,
    
    // === Hierarchy ===
    /// Parent node ID (for chunked documents)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub parent_id: Option<String>,
    
    /// Child node IDs
    #[serde(default)]
    pub children: Vec<String>,
    
    /// Depth in the hierarchy (0 = root)
    #[serde(default)]
    pub depth: u32,
    
    // === Metadata ===
    /// Arbitrary metadata key-value pairs
    #[serde(default)]
    pub metadata: HashMap<String, serde_json::Value>,
    
    /// Tags for categorization
    #[serde(default)]
    pub tags: Vec<String>,
    
    // === Time & Importance ===
    /// Creation timestamp (Unix milliseconds)
    pub created_at: i64,
    
    /// Last access timestamp (Unix milliseconds)
    pub last_accessed_at: i64,
    
    /// Number of times this memory has been accessed
    #[serde(default)]
    pub access_count: u64,
    
    /// Base importance score (0.0 - 1.0)
    #[serde(default = "default_importance")]
    pub importance: f64,
    
    /// Decay rate for importance (higher = faster decay)
    #[serde(default = "default_decay_rate")]
    pub decay_rate: f64,
    
    // === Knowledge Graph ===
    /// Entity IDs associated with this memory
    #[serde(default)]
    pub entity_ids: Vec<String>,
    
    /// Relation IDs where this memory is involved
    #[serde(default)]
    pub relation_ids: Vec<String>,
    
    // === Ownership & Visibility ===
    /// Owner user ID (None = no ownership control, backward compatible)
    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde(default)]
    pub owner_id: Option<String>,
    
    /// Visibility control
    #[serde(default)]
    pub visibility: Visibility,
    
    /// Data protection level
    #[serde(default)]
    pub protection: ProtectionLevel,
    
    /// Collaborators with record-level permissions
    #[serde(default)]
    #[serde(skip_serializing_if = "Vec::is_empty")]
    pub collaborators: Vec<Collaborator>,

    // === Semantic Axes (BriLLM SiFu) ===
    /// 语义轴坐标（可选，通过 SemanticProjector 自动计算）
    ///
    /// 将高维 Embedding 投影到 3 维可解释语义空间，
    /// 用于语义门控查询预过滤和可视化。
    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde(default)]
    pub semantic_axes: Option<SemanticAxes>,
}

fn default_importance() -> f64 {
    0.5
}

fn default_decay_rate() -> f64 {
    0.0001
}

impl MemoryNode {
    /// Create a new memory node with content
    pub fn new(content: impl Into<String>) -> Self {
        let now = chrono_now();
        Self {
            id: Uuid::new_v4().to_string(),
            content: content.into(),
            embedding: None,
            content_type: ContentType::Text,
            parent_id: None,
            children: Vec::new(),
            depth: 0,
            metadata: HashMap::new(),
            tags: Vec::new(),
            created_at: now,
            last_accessed_at: now,
            access_count: 0,
            importance: 0.5,
            decay_rate: 0.0001,
            entity_ids: Vec::new(),
            relation_ids: Vec::new(),
            owner_id: None,
            visibility: Visibility::default(),
            protection: ProtectionLevel::default(),
            collaborators: Vec::new(),
            semantic_axes: None,
        }
    }
    
    /// Create with a specific ID (no validation - use for trusted sources like UUID)
    /// 
    /// For user-provided IDs, use `try_with_id()` instead to validate the ID format.
    pub fn with_id(mut self, id: impl Into<String>) -> Self {
        self.id = id.into();
        self
    }
    
    /// Create with a specific ID with validation
    /// 
    /// Validates that the ID contains only ASCII alphanumeric characters,
    /// underscores, and hyphens.
    /// 
    /// # Errors
    /// 
    /// Returns `InvalidIdError` if the ID contains invalid characters.
    /// 
    /// # Examples
    /// 
    /// ```
    /// use aifastdb_core::types::MemoryNode;
    /// 
    /// // Valid IDs
    /// let node = MemoryNode::new("content").try_with_id("user_123").unwrap();
    /// let node = MemoryNode::new("content").try_with_id("cat-tech").unwrap();
    /// 
    /// // Invalid IDs
    /// assert!(MemoryNode::new("content").try_with_id("cat_影视").is_err());
    /// assert!(MemoryNode::new("content").try_with_id("").is_err());
    /// ```
    pub fn try_with_id(mut self, id: impl Into<String>) -> Result<Self, InvalidIdError> {
        let id = id.into();
        validate_id(&id)?;
        self.id = id;
        Ok(self)
    }
    
    /// Set the embedding vector
    pub fn with_embedding(mut self, embedding: Vec<f32>) -> Self {
        self.embedding = Some(embedding);
        self
    }
    
    /// Set the content type
    pub fn with_content_type(mut self, content_type: ContentType) -> Self {
        self.content_type = content_type;
        self
    }
    
    /// Set the parent ID
    pub fn with_parent(mut self, parent_id: impl Into<String>) -> Self {
        self.parent_id = Some(parent_id.into());
        self
    }
    
    /// Add a tag
    pub fn with_tag(mut self, tag: impl Into<String>) -> Self {
        self.tags.push(tag.into());
        self
    }
    
    /// Add multiple tags
    pub fn with_tags(mut self, tags: impl IntoIterator<Item = impl Into<String>>) -> Self {
        self.tags.extend(tags.into_iter().map(|t| t.into()));
        self
    }
    
    /// Add metadata
    pub fn with_metadata(mut self, key: impl Into<String>, value: serde_json::Value) -> Self {
        self.metadata.insert(key.into(), value);
        self
    }
    
    /// Set importance
    pub fn with_importance(mut self, importance: f64) -> Self {
        self.importance = importance.clamp(0.0, 1.0);
        self
    }
    
    /// Set decay rate
    pub fn with_decay_rate(mut self, decay_rate: f64) -> Self {
        self.decay_rate = decay_rate.max(0.0);
        self
    }
    
    /// Set owner ID
    pub fn with_owner(mut self, owner_id: impl Into<String>) -> Self {
        self.owner_id = Some(owner_id.into());
        self
    }
    
    /// Set visibility
    pub fn with_visibility(mut self, visibility: Visibility) -> Self {
        self.visibility = visibility;
        self
    }

    /// Set semantic axes coordinates
    pub fn with_semantic_axes(mut self, axes: SemanticAxes) -> Self {
        self.semantic_axes = Some(axes);
        self
    }
    
    /// Record an access to this memory
    pub fn record_access(&mut self) {
        self.last_accessed_at = chrono_now();
        self.access_count += 1;
    }
    
    /// Calculate current importance with time decay
    /// 
    /// Formula: importance * e^(-decay_rate * time_elapsed_hours)
    pub fn current_importance(&self) -> f64 {
        let now = chrono_now();
        let elapsed_hours = (now - self.last_accessed_at) as f64 / (1000.0 * 60.0 * 60.0);
        self.importance * (-self.decay_rate * elapsed_hours).exp()
    }
    
    /// Calculate importance with access factor
    /// 
    /// Combines base importance, time decay, and access frequency
    pub fn computed_importance(&self) -> f64 {
        let decayed = self.current_importance();
        // Use max(1, access_count) to avoid ln(0) = -inf
        let access_factor = (1.0 + (self.access_count.max(1) as f64).ln()).min(2.0);
        (decayed * access_factor).min(1.0)
    }
    
    /// Check if this memory has an embedding
    pub fn has_embedding(&self) -> bool {
        self.embedding.is_some()
    }
    
    /// Get the embedding dimension
    pub fn embedding_dimension(&self) -> Option<usize> {
        self.embedding.as_ref().map(|e| e.len())
    }
}

/// Get current Unix timestamp in milliseconds
fn chrono_now() -> i64 {
    use std::time::{SystemTime, UNIX_EPOCH};
    SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .unwrap()
        .as_millis() as i64
}

/// Builder for creating memory nodes
#[derive(Debug, Default)]
pub struct MemoryNodeBuilder {
    content: String,
    embedding: Option<Vec<f32>>,
    content_type: ContentType,
    parent_id: Option<String>,
    metadata: HashMap<String, serde_json::Value>,
    tags: Vec<String>,
    importance: f64,
    decay_rate: f64,
}

impl MemoryNodeBuilder {
    pub fn new(content: impl Into<String>) -> Self {
        Self {
            content: content.into(),
            importance: 0.5,
            decay_rate: 0.0001,
            ..Default::default()
        }
    }
    
    pub fn embedding(mut self, embedding: Vec<f32>) -> Self {
        self.embedding = Some(embedding);
        self
    }
    
    pub fn content_type(mut self, content_type: ContentType) -> Self {
        self.content_type = content_type;
        self
    }
    
    pub fn parent_id(mut self, parent_id: impl Into<String>) -> Self {
        self.parent_id = Some(parent_id.into());
        self
    }
    
    pub fn metadata(mut self, key: impl Into<String>, value: serde_json::Value) -> Self {
        self.metadata.insert(key.into(), value);
        self
    }
    
    pub fn tag(mut self, tag: impl Into<String>) -> Self {
        self.tags.push(tag.into());
        self
    }
    
    pub fn importance(mut self, importance: f64) -> Self {
        self.importance = importance;
        self
    }
    
    pub fn decay_rate(mut self, decay_rate: f64) -> Self {
        self.decay_rate = decay_rate;
        self
    }
    
    pub fn build(self) -> MemoryNode {
        MemoryNode::new(self.content)
            .with_content_type(self.content_type)
            .with_importance(self.importance)
            .with_decay_rate(self.decay_rate)
            .with_tags(self.tags)
    }
}

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

    #[test]
    fn test_memory_node_creation() {
        let node = MemoryNode::new("Test content");
        assert!(!node.id.is_empty());
        assert_eq!(node.content, "Test content");
        assert_eq!(node.content_type, ContentType::Text);
        assert!(node.embedding.is_none());
    }

    #[test]
    fn test_memory_node_builder() {
        let node = MemoryNode::new("Hello world")
            .with_content_type(ContentType::Conversation)
            .with_tag("greeting")
            .with_importance(0.8)
            .with_metadata("source".to_string(), serde_json::json!("chat"));
        
        assert_eq!(node.content_type, ContentType::Conversation);
        assert!(node.tags.contains(&"greeting".to_string()));
        assert_eq!(node.importance, 0.8);
        assert!(node.metadata.contains_key("source"));
    }

    #[test]
    fn test_importance_decay() {
        let mut node = MemoryNode::new("Test")
            .with_importance(1.0)
            .with_decay_rate(0.1);
        
        // Initial importance should be close to 1.0
        let initial = node.current_importance();
        assert!(initial > 0.99);
        
        // Record access should update timestamp
        node.record_access();
        assert_eq!(node.access_count, 1);
    }

    #[test]
    fn test_embedding() {
        let embedding = vec![0.1, 0.2, 0.3, 0.4];
        let node = MemoryNode::new("Test").with_embedding(embedding.clone());
        
        assert!(node.has_embedding());
        assert_eq!(node.embedding_dimension(), Some(4));
        assert_eq!(node.embedding, Some(embedding));
    }

    // ========================================================================
    // ID Validation Tests
    // ========================================================================

    #[test]
    fn test_validate_id_valid_cases() {
        // Simple alphanumeric
        assert!(validate_id("abc123").is_ok());
        assert!(validate_id("ABC123").is_ok());
        assert!(validate_id("abc").is_ok());
        assert!(validate_id("123").is_ok());
        
        // With underscores
        assert!(validate_id("user_123").is_ok());
        assert!(validate_id("cat_tech").is_ok());
        assert!(validate_id("_underscore").is_ok());
        assert!(validate_id("underscore_").is_ok());
        
        // With hyphens
        assert!(validate_id("user-123").is_ok());
        assert!(validate_id("cat-tech").is_ok());
        assert!(validate_id("-hyphen").is_ok());
        assert!(validate_id("hyphen-").is_ok());
        
        // Mixed
        assert!(validate_id("user_123-abc").is_ok());
        assert!(validate_id("Cat_Tech-2024").is_ok());
        
        // UUID format (common case)
        assert!(validate_id("550e8400-e29b-41d4-a716-446655440000").is_ok());
    }

    #[test]
    fn test_validate_id_invalid_cases() {
        // Empty ID
        assert!(validate_id("").is_err());
        
        // Chinese characters
        assert!(validate_id("cat_影视").is_err());
        assert!(validate_id("分类").is_err());
        assert!(validate_id("用户123").is_err());
        
        // Other non-ASCII characters
        assert!(validate_id("café").is_err());
        assert!(validate_id("naïve").is_err());
        assert!(validate_id("日本語").is_err());
        assert!(validate_id("한국어").is_err());
        assert!(validate_id("emoji😀").is_err());
        
        // Special characters (not allowed)
        assert!(validate_id("user@123").is_err());
        assert!(validate_id("user#123").is_err());
        assert!(validate_id("user$123").is_err());
        assert!(validate_id("user%123").is_err());
        assert!(validate_id("user.123").is_err());
        assert!(validate_id("user/123").is_err());
        assert!(validate_id("user\\123").is_err());
        assert!(validate_id("user 123").is_err()); // space
        
        // Too long (> 255 characters)
        let long_id = "a".repeat(256);
        assert!(validate_id(&long_id).is_err());
    }

    #[test]
    fn test_validate_id_boundary_cases() {
        // Single character
        assert!(validate_id("a").is_ok());
        assert!(validate_id("1").is_ok());
        assert!(validate_id("_").is_ok());
        assert!(validate_id("-").is_ok());
        
        // Exactly 255 characters (max allowed)
        let max_id = "a".repeat(255);
        assert!(validate_id(&max_id).is_ok());
    }

    #[test]
    fn test_is_valid_id() {
        assert!(is_valid_id("valid_id"));
        assert!(!is_valid_id("invalid_中文"));
        assert!(!is_valid_id(""));
    }

    #[test]
    fn test_memory_node_try_with_id_valid() {
        let node = MemoryNode::new("Test content")
            .try_with_id("custom_id_123")
            .expect("Should succeed with valid ID");
        
        assert_eq!(node.id, "custom_id_123");
        assert_eq!(node.content, "Test content");
    }

    #[test]
    fn test_memory_node_try_with_id_invalid_chinese() {
        let result = MemoryNode::new("Test content")
            .try_with_id("cat_影视");
        
        assert!(result.is_err());
        let err = result.unwrap_err();
        assert!(err.to_string().contains("影"));
    }

    #[test]
    fn test_memory_node_try_with_id_empty() {
        let result = MemoryNode::new("Test content")
            .try_with_id("");
        
        assert!(result.is_err());
        let err = result.unwrap_err();
        assert!(err.to_string().contains("empty"));
    }

    #[test]
    fn test_invalid_id_error_display() {
        let err = InvalidIdError {
            id: "test_中文".to_string(),
            reason: "contains non-ASCII characters".to_string(),
        };
        
        let msg = err.to_string();
        assert!(msg.contains("test_中文"));
        assert!(msg.contains("contains non-ASCII characters"));
    }
}
