//! Knowledge graph types for AiFastDb
//!
//! Provides Entity and Relation types for building semantic knowledge graphs
//! that connect memory nodes.

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

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

/// An entity in the knowledge graph
/// 
/// Entities represent concepts, people, places, events, etc.
/// They can be linked to memory nodes and connected via relations.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Entity {
    /// Unique identifier
    pub id: String,
    
    /// Human-readable name
    pub name: String,
    
    /// Entity type (person, concept, event, location, etc.)
    pub entity_type: String,
    
    /// Additional properties (BTreeMap for deterministic serialization order)
    #[serde(default)]
    pub properties: BTreeMap<String, serde_json::Value>,
    
    /// References to memory nodes that mention this entity
    #[serde(default)]
    pub memory_refs: Vec<String>,
    
    /// Optional embedding for semantic similarity
    #[serde(skip_serializing_if = "Option::is_none")]
    pub embedding: Option<Vec<f32>>,
    
    /// Creation timestamp
    pub created_at: i64,
    
    /// Last update timestamp
    pub updated_at: i64,
    
    // === 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>,
}

impl Entity {
    /// Create a new entity
    pub fn new(name: impl Into<String>, entity_type: impl Into<String>) -> Self {
        let now = chrono_now();
        Self {
            id: Uuid::new_v4().to_string(),
            name: name.into(),
            entity_type: entity_type.into(),
            properties: BTreeMap::new(),
            memory_refs: Vec::new(),
            embedding: None,
            created_at: now,
            updated_at: now,
            owner_id: None,
            visibility: Visibility::default(),
            protection: ProtectionLevel::default(),
            collaborators: Vec::new(),
        }
    }
    
    /// Create with a specific ID
    pub fn with_id(mut self, id: impl Into<String>) -> Self {
        self.id = id.into();
        self
    }
    
    /// Add a property
    pub fn with_property(mut self, key: impl Into<String>, value: serde_json::Value) -> Self {
        self.properties.insert(key.into(), value);
        self
    }
    
    /// Add a memory reference
    pub fn with_memory_ref(mut self, memory_id: impl Into<String>) -> Self {
        self.memory_refs.push(memory_id.into());
        self
    }
    
    /// Set embedding
    pub fn with_embedding(mut self, embedding: Vec<f32>) -> Self {
        self.embedding = Some(embedding);
        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
    }
    
    /// Add a memory reference (mutable)
    pub fn add_memory_ref(&mut self, memory_id: impl Into<String>) {
        let id = memory_id.into();
        if !self.memory_refs.contains(&id) {
            self.memory_refs.push(id);
            self.updated_at = chrono_now();
        }
    }
    
    /// Remove a memory reference
    pub fn remove_memory_ref(&mut self, memory_id: &str) {
        if let Some(pos) = self.memory_refs.iter().position(|x| x == memory_id) {
            self.memory_refs.remove(pos);
            self.updated_at = chrono_now();
        }
    }
}

/// A relation between two entities in the knowledge graph
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Relation {
    /// Unique identifier
    pub id: String,
    
    /// Source entity ID
    pub source: String,
    
    /// Target entity ID
    pub target: String,
    
    /// Relation type (relates_to, part_of, causes, etc.)
    pub relation_type: String,
    
    /// Relation weight/strength (0.0 - 1.0)
    #[serde(default = "default_weight")]
    pub weight: f64,
    
    /// Whether this relation is bidirectional
    #[serde(default)]
    pub bidirectional: bool,
    
    /// Additional metadata (BTreeMap for deterministic serialization order)
    #[serde(default)]
    pub metadata: BTreeMap<String, serde_json::Value>,
    
    /// Creation timestamp
    pub created_at: i64,
}

fn default_weight() -> f64 {
    1.0
}

impl Relation {
    /// Create a new relation
    pub fn new(
        source: impl Into<String>,
        target: impl Into<String>,
        relation_type: impl Into<String>,
    ) -> Self {
        Self {
            id: Uuid::new_v4().to_string(),
            source: source.into(),
            target: target.into(),
            relation_type: relation_type.into(),
            weight: 1.0,
            bidirectional: false,
            metadata: BTreeMap::new(),
            created_at: chrono_now(),
        }
    }
    
    /// Create with a specific ID
    pub fn with_id(mut self, id: impl Into<String>) -> Self {
        self.id = id.into();
        self
    }
    
    /// Set weight
    pub fn with_weight(mut self, weight: f64) -> Self {
        self.weight = weight.clamp(0.0, 1.0);
        self
    }
    
    /// Set bidirectional
    pub fn bidirectional(mut self) -> Self {
        self.bidirectional = true;
        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
    }
    
    /// Check if this relation connects two specific entities (in either direction if bidirectional)
    pub fn connects(&self, entity_a: &str, entity_b: &str) -> bool {
        if self.source == entity_a && self.target == entity_b {
            return true;
        }
        if self.bidirectional && self.source == entity_b && self.target == entity_a {
            return true;
        }
        false
    }
    
    /// Get the other entity in this relation given one entity
    pub fn other_entity(&self, entity_id: &str) -> Option<&str> {
        if self.source == entity_id {
            Some(&self.target)
        } else if self.target == entity_id {
            Some(&self.source)
        } else {
            None
        }
    }
}

/// Common relation types
pub mod relation_types {
    // 基础关系类型
    pub const RELATES_TO: &str = "relates_to";
    pub const PART_OF: &str = "part_of";
    pub const CONTAINS: &str = "contains";
    pub const CAUSES: &str = "causes";
    pub const CAUSED_BY: &str = "caused_by";
    pub const SIMILAR_TO: &str = "similar_to";
    pub const OPPOSITE_OF: &str = "opposite_of";
    pub const DERIVED_FROM: &str = "derived_from";
    pub const INSTANCE_OF: &str = "instance_of";
    pub const SUBCLASS_OF: &str = "subclass_of";
    pub const CREATED_BY: &str = "created_by";
    pub const LOCATED_IN: &str = "located_in";
    pub const BELONGS_TO: &str = "belongs_to";
    pub const ASSOCIATED_WITH: &str = "associated_with";
    
    // 社交关系类型
    pub const FRIEND: &str = "friend";
    pub const KNOWS: &str = "knows";
    pub const COLLEAGUE: &str = "colleague";
    pub const CLASSMATE: &str = "classmate";
    pub const FAMILY: &str = "family";
    pub const MENTOR: &str = "mentor";
    pub const INTRODUCED_BY: &str = "introduced_by";
    
    // 组织关系类型
    pub const MEMBER_OF: &str = "member_of";
    pub const WORK_FOR: &str = "work_for";
    pub const PARENT_OF: &str = "parent_of";
    
    // 标签关系类型
    pub const HAS_TAGS: &str = "has_tags";
    
    // 物品关系类型
    pub const OWNS: &str = "owns";
    pub const USED_TO_OWN: &str = "used_to_own";
    pub const WANTS: &str = "wants";
    
    // 属性关系类型
    pub const HAS_ATTRIBUTE: &str = "has_attribute";
    pub const GRADUATED_FROM: &str = "graduated_from";
    pub const LIVES_IN: &str = "lives_in";
    pub const BORN_IN: &str = "born_in";
    pub const INTERESTED_IN: &str = "interested_in";
    
    // 生日关系类型
    pub const BORN_ON: &str = "born_on";           // 出生于某日 (YYYY-MM-DD)
    pub const BIRTHDAY_MD: &str = "birthday_md";   // 月日生日 (MM-DD)
    
    // ========== 家谱关系类型 ==========
    
    // 直系血亲 (PARENT_OF already defined above for tag hierarchy, reused for family)
    pub const CHILD_OF: &str = "child_of";         // 子女 → 父母
    pub const FATHER_OF: &str = "father_of";       // 父亲 → 子女
    pub const MOTHER_OF: &str = "mother_of";       // 母亲 → 子女
    
    // 配偶关系
    pub const SPOUSE_OF: &str = "spouse_of";       // 配偶（双向）
    pub const HUSBAND_OF: &str = "husband_of";     // 丈夫 → 妻子
    pub const WIFE_OF: &str = "wife_of";           // 妻子 → 丈夫
    pub const EX_SPOUSE_OF: &str = "ex_spouse_of"; // 前配偶
    
    // 兄弟姐妹
    pub const SIBLING_OF: &str = "sibling_of";     // 兄弟姐妹（双向）
    pub const BROTHER_OF: &str = "brother_of";     // 兄/弟 → 对方
    pub const SISTER_OF: &str = "sister_of";       // 姐/妹 → 对方
    pub const HALF_SIBLING_OF: &str = "half_sibling_of"; // 同父异母/同母异父
    
    // 祖孙关系（可通过直系血亲推导）
    pub const GRANDPARENT_OF: &str = "grandparent_of";
    pub const GRANDCHILD_OF: &str = "grandchild_of";
    
    // 继父母/继子女关系（再婚家庭）
    pub const STEP_PARENT_OF: &str = "step_parent_of";     // 继父母 → 继子女
    pub const STEP_FATHER_OF: &str = "step_father_of";     // 继父 → 继子女
    pub const STEP_MOTHER_OF: &str = "step_mother_of";     // 继母 → 继子女
    pub const STEP_CHILD_OF: &str = "step_child_of";       // 继子女 → 继父母
    
    // 养父母/养子女关系
    pub const ADOPTIVE_PARENT_OF: &str = "adoptive_parent_of";   // 养父母 → 养子女
    pub const ADOPTIVE_FATHER_OF: &str = "adoptive_father_of";   // 养父 → 养子女
    pub const ADOPTIVE_MOTHER_OF: &str = "adoptive_mother_of";   // 养母 → 养子女
    pub const ADOPTED_CHILD_OF: &str = "adopted_child_of";       // 养子女 → 养父母
}

/// Common entity types
pub mod entity_types {
    // 基础实体类型
    pub const PERSON: &str = "person";
    pub const ORGANIZATION: &str = "organization";
    pub const LOCATION: &str = "location";
    pub const EVENT: &str = "event";
    pub const CONCEPT: &str = "concept";
    pub const OBJECT: &str = "object";
    pub const DOCUMENT: &str = "document";
    pub const TOPIC: &str = "topic";
    pub const DATE: &str = "date";
    pub const QUANTITY: &str = "quantity";
    
    // 社交实体类型
    pub const COMPANY: &str = "company";
    pub const COMMUNITY: &str = "community";
    pub const SKILL: &str = "skill";
    pub const INTEREST: &str = "interest";
    pub const TAG: &str = "tag";
    
    // 物品实体类型
    pub const ITEM: &str = "item";
    pub const VEHICLE: &str = "vehicle";
    pub const DEVICE: &str = "device";
    pub const EQUIPMENT: &str = "equipment";
    
    // 属性值实体类型
    pub const ATTRIBUTE: &str = "attribute";
    pub const ZODIAC: &str = "zodiac";
    pub const SCHOOL: &str = "school";
    pub const CITY: &str = "city";
    pub const HOBBY: &str = "hobby";
    pub const AGE_GROUP: &str = "age_group";
    pub const INDUSTRY: &str = "industry";
    
    // 生日实体类型
    pub const BIRTHDAY: &str = "birthday";         // 完整生日 (YYYY-MM-DD)
    pub const BIRTHDAY_MD: &str = "birthday_md";   // 月日生日 (MM-DD)
    
    // 家谱实体类型
    pub const FAMILY_TREE: &str = "family_tree";   // 家谱树根节点
}

/// Attribute categories for social matching
pub mod attribute_categories {
    pub const ZODIAC: &str = "zodiac";
    pub const MBTI: &str = "mbti";
    pub const BLOOD_TYPE: &str = "blood_type";
    pub const EDUCATION: &str = "education";
    pub const LOCATION: &str = "location";
    pub const AGE: &str = "age";
    pub const HOBBY: &str = "hobby";
    pub const INDUSTRY: &str = "industry";
    pub const LANGUAGE: &str = "language";
    pub const BIRTHDAY: &str = "birthday";         // 完整生日 (YYYY-MM-DD)
    pub const BIRTHDAY_MD: &str = "birthday_md";   // 月日生日 (MM-DD)
}

/// Gender constants for family tree
pub mod gender {
    pub const MALE: &str = "male";
    pub const FEMALE: &str = "female";
    pub const UNKNOWN: &str = "unknown";
}

/// Item categories for social matching
pub mod item_categories {
    pub const VEHICLE: &str = "vehicle";
    pub const PHONE: &str = "phone";
    pub const COMPUTER: &str = "computer";
    pub const CAMERA: &str = "camera";
    pub const WATCH: &str = "watch";
    pub const HEADPHONE: &str = "headphone";
    pub const GAME_CONSOLE: &str = "game_console";
}

/// 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
}

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

    #[test]
    fn test_entity_creation() {
        let entity = Entity::new("Albert Einstein", entity_types::PERSON)
            .with_property("birth_year".to_string(), serde_json::json!(1879))
            .with_memory_ref("memory-123");
        
        assert!(!entity.id.is_empty());
        assert_eq!(entity.name, "Albert Einstein");
        assert_eq!(entity.entity_type, entity_types::PERSON);
        assert!(entity.properties.contains_key("birth_year"));
        assert!(entity.memory_refs.contains(&"memory-123".to_string()));
    }

    #[test]
    fn test_relation_creation() {
        let relation = Relation::new("entity-1", "entity-2", relation_types::RELATES_TO)
            .with_weight(0.8)
            .bidirectional();
        
        assert!(!relation.id.is_empty());
        assert_eq!(relation.source, "entity-1");
        assert_eq!(relation.target, "entity-2");
        assert_eq!(relation.relation_type, relation_types::RELATES_TO);
        assert_eq!(relation.weight, 0.8);
        assert!(relation.bidirectional);
    }

    #[test]
    fn test_relation_connects() {
        let relation = Relation::new("a", "b", "test").bidirectional();
        
        assert!(relation.connects("a", "b"));
        assert!(relation.connects("b", "a")); // bidirectional
        assert!(!relation.connects("a", "c"));
    }

    #[test]
    fn test_relation_other_entity() {
        let relation = Relation::new("a", "b", "test");
        
        assert_eq!(relation.other_entity("a"), Some("b"));
        assert_eq!(relation.other_entity("b"), Some("a"));
        assert_eq!(relation.other_entity("c"), None);
    }

    #[test]
    fn test_entity_memory_refs() {
        let mut entity = Entity::new("Test", "concept");
        
        entity.add_memory_ref("mem-1");
        entity.add_memory_ref("mem-2");
        entity.add_memory_ref("mem-1"); // duplicate, should not be added
        
        assert_eq!(entity.memory_refs.len(), 2);
        
        entity.remove_memory_ref("mem-1");
        assert_eq!(entity.memory_refs.len(), 1);
        assert!(entity.memory_refs.contains(&"mem-2".to_string()));
    }
}
