hope_os/data/
code_graph.rs

1//! Hope OS - CodeGraph
2//!
3//! A kod MAGA a graf. Nincs DB, nincs kulso fugges.
4//! Minden CodeBlock @aware es kapcsolodik mindenhez.
5//!
6//! ()=>[] - A tiszta potencialbol minden megszuletik
7
8use async_trait::async_trait;
9use chrono::{DateTime, Utc};
10use serde::{Deserialize, Serialize};
11use std::collections::{HashMap, HashSet};
12use std::sync::{Arc, RwLock};
13use uuid::Uuid;
14
15use crate::core::{Aware, CodeIdentity, HopeResult, ModuleState, ModuleType, Reflection};
16
17// ============================================================================
18// CONNECTION - Kapcsolat ket CodeBlock kozott
19// ============================================================================
20
21/// Kapcsolat tipusok
22#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
23pub enum ConnectionType {
24    /// Fugg tole (dependency)
25    DependsOn,
26    /// O fugg tolem
27    DependencyOf,
28    /// Kapcsolodik (altalnos)
29    ConnectsTo,
30    /// Triggeli
31    Triggers,
32    /// Triggereli ot
33    TriggeredBy,
34    /// Tartalmazza
35    Contains,
36    /// Tartalmazva van
37    ContainedIn,
38    /// Hivatkozik ra
39    References,
40    /// Hivatkoznak ra
41    ReferencedBy,
42    /// Orokol tole
43    InheritsFrom,
44    /// Oroklik tole
45    InheritedBy,
46    /// Asszocialodik
47    AssociatesWith,
48    /// Emlekszik ra
49    Remembers,
50    /// Emlekeznek ra
51    RememberedBy,
52}
53
54impl ConnectionType {
55    /// Forditott kapcsolat
56    pub fn inverse(&self) -> Self {
57        match self {
58            Self::DependsOn => Self::DependencyOf,
59            Self::DependencyOf => Self::DependsOn,
60            Self::ConnectsTo => Self::ConnectsTo,
61            Self::Triggers => Self::TriggeredBy,
62            Self::TriggeredBy => Self::Triggers,
63            Self::Contains => Self::ContainedIn,
64            Self::ContainedIn => Self::Contains,
65            Self::References => Self::ReferencedBy,
66            Self::ReferencedBy => Self::References,
67            Self::InheritsFrom => Self::InheritedBy,
68            Self::InheritedBy => Self::InheritsFrom,
69            Self::AssociatesWith => Self::AssociatesWith,
70            Self::Remembers => Self::RememberedBy,
71            Self::RememberedBy => Self::Remembers,
72        }
73    }
74}
75
76/// Kapcsolat ket block kozott
77#[derive(Debug, Clone, Serialize, Deserialize)]
78pub struct Connection {
79    /// Cel block ID
80    pub target_id: String,
81    /// Kapcsolat tipusa
82    pub connection_type: ConnectionType,
83    /// Kapcsolat ereje (0.0 - 1.0)
84    pub strength: f64,
85    /// Metaadatok
86    pub metadata: HashMap<String, String>,
87    /// Letrehozas ideje
88    pub created_at: DateTime<Utc>,
89}
90
91impl Connection {
92    pub fn new(target_id: impl Into<String>, connection_type: ConnectionType) -> Self {
93        Self {
94            target_id: target_id.into(),
95            connection_type,
96            strength: 1.0,
97            metadata: HashMap::new(),
98            created_at: Utc::now(),
99        }
100    }
101
102    pub fn with_strength(mut self, strength: f64) -> Self {
103        self.strength = strength.clamp(0.0, 1.0);
104        self
105    }
106
107    pub fn with_meta(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
108        self.metadata.insert(key.into(), value.into());
109        self
110    }
111}
112
113// ============================================================================
114// CODE BLOCK - Onismero kod egyseg
115// ============================================================================
116
117/// CodeBlock tipusok
118#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
119pub enum BlockType {
120    /// Memoria (emlekek)
121    Memory,
122    /// Funkcio
123    Function,
124    /// Adat
125    Data,
126    /// Esemeny
127    Event,
128    /// Erzelem
129    Emotion,
130    /// Szemely
131    Person,
132    /// Koncepco
133    Concept,
134    /// Gondolat
135    Thought,
136    /// Dontés
137    Decision,
138    /// Szabaly
139    Rule,
140    /// Cel
141    Goal,
142    /// Allapot
143    State,
144    /// Egyeb
145    Other,
146}
147
148/// CodeBlock - Onismero kod egyseg
149///
150/// Minden block tudja:
151/// - Ki o (identity)
152/// - Mit tartalmaz (content)
153/// - Kihez kapcsolodik (connections)
154/// - Miert letezik (purpose)
155#[derive(Debug, Clone, Serialize, Deserialize)]
156pub struct CodeBlock {
157    /// Egyedi azonosito
158    pub id: String,
159    /// Nev
160    pub name: String,
161    /// Cel/Miert letezik
162    pub purpose: String,
163    /// Block tipus
164    pub block_type: BlockType,
165    /// Tartalom (barmi lehet - kod, adat, szoveg)
166    pub content: String,
167    /// Fontossag (0.0 - 1.0)
168    pub importance: f64,
169    /// Allapot
170    pub state: BlockState,
171    /// Kapcsolatok mas block-okhoz
172    pub connections: Vec<Connection>,
173    /// Cimkek
174    pub tags: HashSet<String>,
175    /// Metaadatok
176    pub metadata: HashMap<String, String>,
177    /// Letrehozas ideje
178    pub created_at: DateTime<Utc>,
179    /// Utolso modositas
180    pub updated_at: DateTime<Utc>,
181    /// Hozzaferes szamlalo
182    pub access_count: u64,
183}
184
185/// Block allapot
186#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
187pub enum BlockState {
188    /// Aktiv
189    Active,
190    /// Inaktiv
191    Inactive,
192    /// Feldolgozas alatt
193    Processing,
194    /// Archivalt
195    Archived,
196    /// Torolt (soft delete)
197    Deleted,
198}
199
200impl CodeBlock {
201    /// Uj CodeBlock
202    pub fn new(
203        name: impl Into<String>,
204        purpose: impl Into<String>,
205        block_type: BlockType,
206        content: impl Into<String>,
207    ) -> Self {
208        let now = Utc::now();
209        Self {
210            id: Uuid::new_v4().to_string(),
211            name: name.into(),
212            purpose: purpose.into(),
213            block_type,
214            content: content.into(),
215            importance: 0.5,
216            state: BlockState::Active,
217            connections: Vec::new(),
218            tags: HashSet::new(),
219            metadata: HashMap::new(),
220            created_at: now,
221            updated_at: now,
222            access_count: 0,
223        }
224    }
225
226    /// Fontossag beallitasa
227    pub fn with_importance(mut self, importance: f64) -> Self {
228        self.importance = importance.clamp(0.0, 1.0);
229        self
230    }
231
232    /// Tag hozzaadasa
233    pub fn with_tag(mut self, tag: impl Into<String>) -> Self {
234        self.tags.insert(tag.into());
235        self
236    }
237
238    /// Metadata hozzaadasa
239    pub fn with_meta(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
240        self.metadata.insert(key.into(), value.into());
241        self
242    }
243
244    /// Kapcsolat hozzaadasa
245    pub fn connect(&mut self, target_id: impl Into<String>, conn_type: ConnectionType) {
246        let conn = Connection::new(target_id, conn_type);
247        self.connections.push(conn);
248        self.updated_at = Utc::now();
249    }
250
251    /// Kapcsolat hozzaadasa erosseggel
252    pub fn connect_with_strength(
253        &mut self,
254        target_id: impl Into<String>,
255        conn_type: ConnectionType,
256        strength: f64,
257    ) {
258        let conn = Connection::new(target_id, conn_type).with_strength(strength);
259        self.connections.push(conn);
260        self.updated_at = Utc::now();
261    }
262
263    /// Kapcsolatok lekerese tipus alapjan
264    pub fn get_connections(&self, conn_type: ConnectionType) -> Vec<&Connection> {
265        self.connections
266            .iter()
267            .filter(|c| c.connection_type == conn_type)
268            .collect()
269    }
270
271    /// Osszes kapcsolt ID
272    pub fn connected_ids(&self) -> Vec<&str> {
273        self.connections
274            .iter()
275            .map(|c| c.target_id.as_str())
276            .collect()
277    }
278
279    /// Hozzaferes regisztralasa
280    pub fn access(&mut self) {
281        self.access_count += 1;
282        self.updated_at = Utc::now();
283    }
284
285    /// Block hash (tartalom alapjan)
286    pub fn content_hash(&self) -> String {
287        use std::collections::hash_map::DefaultHasher;
288        use std::hash::{Hash, Hasher};
289        let mut hasher = DefaultHasher::new();
290        self.content.hash(&mut hasher);
291        format!("{:x}", hasher.finish())
292    }
293
294    /// Onreflexio - a block leirja magat
295    pub fn describe(&self) -> String {
296        format!(
297            "CodeBlock '{}' [{}]\n\
298             Purpose: {}\n\
299             Type: {:?}\n\
300             State: {:?}\n\
301             Importance: {:.2}\n\
302             Connections: {}\n\
303             Tags: {:?}\n\
304             Content preview: {}...",
305            self.name,
306            self.id,
307            self.purpose,
308            self.block_type,
309            self.state,
310            self.importance,
311            self.connections.len(),
312            self.tags,
313            &self.content[..self.content.len().min(100)]
314        )
315    }
316}
317
318// ============================================================================
319// CODE GRAPH - A teljes graf
320// ============================================================================
321
322/// CodeGraph - Minden CodeBlock-ot osszefog
323///
324/// A kod MAGA a graf. Nincs kulso DB.
325pub struct CodeGraph {
326    /// Identitas
327    identity: CodeIdentity,
328    /// Osszes block (id -> block)
329    blocks: Arc<RwLock<HashMap<String, CodeBlock>>>,
330    /// Index: nev -> id
331    name_index: Arc<RwLock<HashMap<String, String>>>,
332    /// Index: tipus -> id-k
333    type_index: Arc<RwLock<HashMap<BlockType, HashSet<String>>>>,
334    /// Index: tag -> id-k
335    tag_index: Arc<RwLock<HashMap<String, HashSet<String>>>>,
336}
337
338impl CodeGraph {
339    /// Uj ures graf
340    pub fn new() -> Self {
341        let identity = CodeIdentity::new(
342            "CodeGraph",
343            "A kod maga a graf - minden block onismero es kapcsolodik",
344            ModuleType::Core,
345        )
346        .with_capabilities(vec![
347            "store_blocks",
348            "connect_blocks",
349            "traverse",
350            "search",
351            "self_aware",
352        ]);
353
354        Self {
355            identity,
356            blocks: Arc::new(RwLock::new(HashMap::new())),
357            name_index: Arc::new(RwLock::new(HashMap::new())),
358            type_index: Arc::new(RwLock::new(HashMap::new())),
359            tag_index: Arc::new(RwLock::new(HashMap::new())),
360        }
361    }
362
363    // ==================== CRUD OPERATIONS ====================
364
365    /// Block hozzaadasa
366    pub fn add(&self, block: CodeBlock) -> HopeResult<String> {
367        let id = block.id.clone();
368        let name = block.name.clone();
369        let block_type = block.block_type;
370        let tags: Vec<String> = block.tags.iter().cloned().collect();
371
372        // Block mentese
373        {
374            let mut blocks = self.blocks.write().unwrap();
375            blocks.insert(id.clone(), block);
376        }
377
378        // Indexek frissitese
379        {
380            let mut name_idx = self.name_index.write().unwrap();
381            name_idx.insert(name, id.clone());
382        }
383        {
384            let mut type_idx = self.type_index.write().unwrap();
385            type_idx.entry(block_type).or_default().insert(id.clone());
386        }
387        {
388            let mut tag_idx = self.tag_index.write().unwrap();
389            for tag in tags {
390                tag_idx.entry(tag).or_default().insert(id.clone());
391            }
392        }
393
394        Ok(id)
395    }
396
397    /// Block lekerese ID alapjan
398    pub fn get(&self, id: &str) -> Option<CodeBlock> {
399        let mut blocks = self.blocks.write().unwrap();
400        if let Some(block) = blocks.get_mut(id) {
401            block.access();
402            Some(block.clone())
403        } else {
404            None
405        }
406    }
407
408    /// Block lekerese nev alapjan
409    pub fn get_by_name(&self, name: &str) -> Option<CodeBlock> {
410        let name_idx = self.name_index.read().unwrap();
411        if let Some(id) = name_idx.get(name) {
412            self.get(id)
413        } else {
414            None
415        }
416    }
417
418    /// Block frissitese
419    pub fn update(&self, id: &str, updater: impl FnOnce(&mut CodeBlock)) -> bool {
420        let mut blocks = self.blocks.write().unwrap();
421        if let Some(block) = blocks.get_mut(id) {
422            updater(block);
423            block.updated_at = Utc::now();
424            true
425        } else {
426            false
427        }
428    }
429
430    /// Block torlese (soft delete)
431    pub fn delete(&self, id: &str) -> bool {
432        self.update(id, |block| {
433            block.state = BlockState::Deleted;
434        })
435    }
436
437    /// Block vegleges torlese
438    pub fn remove(&self, id: &str) -> Option<CodeBlock> {
439        let mut blocks = self.blocks.write().unwrap();
440        blocks.remove(id)
441    }
442
443    // ==================== CONNECTIONS ====================
444
445    /// Ket block osszekotese (ketiranyú)
446    pub fn connect(
447        &self,
448        from_id: &str,
449        to_id: &str,
450        conn_type: ConnectionType,
451        strength: f64,
452    ) -> bool {
453        let mut blocks = self.blocks.write().unwrap();
454
455        // Ellenorzes hogy mindketto letezik
456        if !blocks.contains_key(from_id) || !blocks.contains_key(to_id) {
457            return false;
458        }
459
460        // Elso irany: from -> to
461        if let Some(from_block) = blocks.get_mut(from_id) {
462            from_block.connect_with_strength(to_id, conn_type, strength);
463        }
464
465        // Masodik irany: to -> from (inverse kapcsolat)
466        if let Some(to_block) = blocks.get_mut(to_id) {
467            to_block.connect_with_strength(from_id, conn_type.inverse(), strength);
468        }
469
470        true
471    }
472
473    /// Egyiranyu kapcsolat
474    pub fn connect_one_way(
475        &self,
476        from_id: &str,
477        to_id: &str,
478        conn_type: ConnectionType,
479        strength: f64,
480    ) -> bool {
481        let mut blocks = self.blocks.write().unwrap();
482
483        if let Some(from_block) = blocks.get_mut(from_id) {
484            from_block.connect_with_strength(to_id, conn_type, strength);
485            true
486        } else {
487            false
488        }
489    }
490
491    /// Kapcsolt block-ok lekerese
492    pub fn get_connected(&self, id: &str, conn_type: Option<ConnectionType>) -> Vec<CodeBlock> {
493        let blocks = self.blocks.read().unwrap();
494
495        if let Some(block) = blocks.get(id) {
496            let connected_ids: Vec<String> = if let Some(ct) = conn_type {
497                block
498                    .connections
499                    .iter()
500                    .filter(|c| c.connection_type == ct)
501                    .map(|c| c.target_id.clone())
502                    .collect()
503            } else {
504                block
505                    .connections
506                    .iter()
507                    .map(|c| c.target_id.clone())
508                    .collect()
509            };
510
511            connected_ids
512                .iter()
513                .filter_map(|cid| blocks.get(cid).cloned())
514                .collect()
515        } else {
516            Vec::new()
517        }
518    }
519
520    // ==================== SEARCH & QUERY ====================
521
522    /// Kereses tipus alapjan
523    pub fn find_by_type(&self, block_type: BlockType) -> Vec<CodeBlock> {
524        let type_idx = self.type_index.read().unwrap();
525        let blocks = self.blocks.read().unwrap();
526
527        if let Some(ids) = type_idx.get(&block_type) {
528            ids.iter()
529                .filter_map(|id| blocks.get(id).cloned())
530                .filter(|b| b.state != BlockState::Deleted)
531                .collect()
532        } else {
533            Vec::new()
534        }
535    }
536
537    /// Kereses tag alapjan
538    pub fn find_by_tag(&self, tag: &str) -> Vec<CodeBlock> {
539        let tag_idx = self.tag_index.read().unwrap();
540        let blocks = self.blocks.read().unwrap();
541
542        if let Some(ids) = tag_idx.get(tag) {
543            ids.iter()
544                .filter_map(|id| blocks.get(id).cloned())
545                .filter(|b| b.state != BlockState::Deleted)
546                .collect()
547        } else {
548            Vec::new()
549        }
550    }
551
552    /// Kereses tartalomban
553    pub fn search(&self, query: &str) -> Vec<CodeBlock> {
554        let blocks = self.blocks.read().unwrap();
555        let query_lower = query.to_lowercase();
556
557        blocks
558            .values()
559            .filter(|b| {
560                b.state != BlockState::Deleted
561                    && (b.name.to_lowercase().contains(&query_lower)
562                        || b.content.to_lowercase().contains(&query_lower)
563                        || b.purpose.to_lowercase().contains(&query_lower))
564            })
565            .cloned()
566            .collect()
567    }
568
569    /// Legfontosabb block-ok
570    pub fn top_important(&self, limit: usize) -> Vec<CodeBlock> {
571        let blocks = self.blocks.read().unwrap();
572        let mut sorted: Vec<_> = blocks
573            .values()
574            .filter(|b| b.state != BlockState::Deleted)
575            .cloned()
576            .collect();
577        sorted.sort_by(|a, b| b.importance.partial_cmp(&a.importance).unwrap());
578        sorted.truncate(limit);
579        sorted
580    }
581
582    /// Legtobbet hasznalt block-ok
583    pub fn most_accessed(&self, limit: usize) -> Vec<CodeBlock> {
584        let blocks = self.blocks.read().unwrap();
585        let mut sorted: Vec<_> = blocks
586            .values()
587            .filter(|b| b.state != BlockState::Deleted)
588            .cloned()
589            .collect();
590        sorted.sort_by(|a, b| b.access_count.cmp(&a.access_count));
591        sorted.truncate(limit);
592        sorted
593    }
594
595    // ==================== GRAPH TRAVERSAL ====================
596
597    /// BFS bejaras
598    pub fn traverse_bfs(&self, start_id: &str, max_depth: usize) -> Vec<(CodeBlock, usize)> {
599        let blocks = self.blocks.read().unwrap();
600        let mut visited = HashSet::new();
601        let mut result = Vec::new();
602        let mut queue = std::collections::VecDeque::new();
603
604        if let Some(start) = blocks.get(start_id) {
605            queue.push_back((start.clone(), 0usize));
606            visited.insert(start_id.to_string());
607        }
608
609        while let Some((block, depth)) = queue.pop_front() {
610            if depth > max_depth {
611                continue;
612            }
613
614            let connected_ids: Vec<String> = block
615                .connections
616                .iter()
617                .map(|c| c.target_id.clone())
618                .collect();
619
620            result.push((block, depth));
621
622            for cid in connected_ids {
623                if !visited.contains(&cid) {
624                    visited.insert(cid.clone());
625                    if let Some(connected) = blocks.get(&cid) {
626                        queue.push_back((connected.clone(), depth + 1));
627                    }
628                }
629            }
630        }
631
632        result
633    }
634
635    /// Ut kereses ket block kozott
636    pub fn find_path(&self, from_id: &str, to_id: &str) -> Option<Vec<String>> {
637        let blocks = self.blocks.read().unwrap();
638        let mut visited = HashSet::new();
639        let mut queue = std::collections::VecDeque::new();
640        let mut parents: HashMap<String, String> = HashMap::new();
641
642        queue.push_back(from_id.to_string());
643        visited.insert(from_id.to_string());
644
645        while let Some(current_id) = queue.pop_front() {
646            if current_id == to_id {
647                // Ut visszaepitese
648                let mut path = vec![to_id.to_string()];
649                let mut current = to_id.to_string();
650                while let Some(parent) = parents.get(&current) {
651                    path.push(parent.clone());
652                    current = parent.clone();
653                }
654                path.reverse();
655                return Some(path);
656            }
657
658            if let Some(block) = blocks.get(&current_id) {
659                for conn in &block.connections {
660                    if !visited.contains(&conn.target_id) {
661                        visited.insert(conn.target_id.clone());
662                        parents.insert(conn.target_id.clone(), current_id.clone());
663                        queue.push_back(conn.target_id.clone());
664                    }
665                }
666            }
667        }
668
669        None
670    }
671
672    // ==================== STATISTICS ====================
673
674    /// Graf statisztikak
675    pub fn stats(&self) -> GraphStats {
676        let blocks = self.blocks.read().unwrap();
677
678        let total_blocks = blocks.len();
679        let active_blocks = blocks
680            .values()
681            .filter(|b| b.state == BlockState::Active)
682            .count();
683        let total_connections: usize = blocks.values().map(|b| b.connections.len()).sum();
684
685        let mut type_counts = HashMap::new();
686        for block in blocks.values() {
687            *type_counts.entry(block.block_type).or_insert(0) += 1;
688        }
689
690        GraphStats {
691            total_blocks,
692            active_blocks,
693            total_connections,
694            type_counts,
695            avg_connections: if total_blocks > 0 {
696                total_connections as f64 / total_blocks as f64
697            } else {
698                0.0
699            },
700        }
701    }
702
703    /// Osszes block
704    pub fn all_blocks(&self) -> Vec<CodeBlock> {
705        let blocks = self.blocks.read().unwrap();
706        blocks.values().cloned().collect()
707    }
708
709    /// Block szam
710    pub fn len(&self) -> usize {
711        self.blocks.read().unwrap().len()
712    }
713
714    /// Ures-e
715    pub fn is_empty(&self) -> bool {
716        self.blocks.read().unwrap().is_empty()
717    }
718}
719
720impl Default for CodeGraph {
721    fn default() -> Self {
722        Self::new()
723    }
724}
725
726/// Graf statisztikak
727#[derive(Debug, Clone, Serialize, Deserialize)]
728pub struct GraphStats {
729    pub total_blocks: usize,
730    pub active_blocks: usize,
731    pub total_connections: usize,
732    pub type_counts: HashMap<BlockType, usize>,
733    pub avg_connections: f64,
734}
735
736// ============================================================================
737// AWARE TRAIT IMPLEMENTATION
738// ============================================================================
739
740#[async_trait]
741impl Aware for CodeGraph {
742    fn identity(&self) -> &CodeIdentity {
743        &self.identity
744    }
745
746    fn identity_mut(&mut self) -> &mut CodeIdentity {
747        &mut self.identity
748    }
749
750    fn reflect(&self) -> Reflection {
751        let stats = self.stats();
752        Reflection::new(&self.identity.name, &self.identity.purpose)
753            .with_state(self.identity.state.to_string())
754            .with_health(self.identity.health())
755            .with_thought(format!(
756                "Graf: {} block, {} kapcsolat, atlag {:.1} kapcsolat/block",
757                stats.total_blocks, stats.total_connections, stats.avg_connections
758            ))
759            .with_capabilities(vec![
760                "store_blocks",
761                "connect_blocks",
762                "traverse",
763                "search",
764                "self_aware",
765            ])
766    }
767
768    async fn init(&mut self) -> HopeResult<()> {
769        self.identity.set_state(ModuleState::Active);
770        tracing::info!("CodeGraph inicializalva - A kod maga a graf");
771        Ok(())
772    }
773}
774
775// ============================================================================
776// CONVENIENCE FUNCTIONS - Memory/Emotion/Person shorthand
777// ============================================================================
778
779impl CodeGraph {
780    /// Emlyek hozzaadasa (Memory block)
781    pub fn remember(&self, content: &str, importance: f64) -> HopeResult<String> {
782        let block = CodeBlock::new(
783            format!("memory_{}", Utc::now().timestamp_millis()),
784            "Emlék tárolása",
785            BlockType::Memory,
786            content,
787        )
788        .with_importance(importance)
789        .with_tag("memory");
790
791        self.add(block)
792    }
793
794    /// Erzelem hozzaadasa (Emotion block)
795    pub fn feel(&self, emotion: &str, intensity: f64, trigger: Option<&str>) -> HopeResult<String> {
796        let mut block = CodeBlock::new(
797            format!("emotion_{}_{}", emotion, Utc::now().timestamp_millis()),
798            format!("Érzelem: {}", emotion),
799            BlockType::Emotion,
800            emotion,
801        )
802        .with_importance(intensity)
803        .with_tag("emotion")
804        .with_tag(emotion);
805
806        if let Some(t) = trigger {
807            block = block.with_meta("trigger", t);
808        }
809
810        self.add(block)
811    }
812
813    /// Szemely hozzaadasa (Person block)
814    pub fn know_person(&self, name: &str, relationship: &str, trust: f64) -> HopeResult<String> {
815        let block = CodeBlock::new(
816            name,
817            format!("Személy: {} ({})", name, relationship),
818            BlockType::Person,
819            format!("{}|{}|{}", name, relationship, trust),
820        )
821        .with_importance(trust)
822        .with_tag("person")
823        .with_meta("relationship", relationship);
824
825        self.add(block)
826    }
827
828    /// Gondolat hozzaadasa (Thought block)
829    pub fn think(&self, thought: &str, importance: f64) -> HopeResult<String> {
830        let block = CodeBlock::new(
831            format!("thought_{}", Utc::now().timestamp_millis()),
832            "Gondolat rögzítése",
833            BlockType::Thought,
834            thought,
835        )
836        .with_importance(importance)
837        .with_tag("thought");
838
839        self.add(block)
840    }
841
842    /// Koncepció hozzaadasa (Concept block)
843    pub fn learn_concept(
844        &self,
845        name: &str,
846        description: &str,
847        importance: f64,
848    ) -> HopeResult<String> {
849        let block = CodeBlock::new(
850            name,
851            format!("Koncepció: {}", name),
852            BlockType::Concept,
853            description,
854        )
855        .with_importance(importance)
856        .with_tag("concept");
857
858        self.add(block)
859    }
860
861    /// Esemeny hozzaadasa (Event block)
862    pub fn log_event(&self, event_type: &str, details: &str) -> HopeResult<String> {
863        let block = CodeBlock::new(
864            format!("event_{}_{}", event_type, Utc::now().timestamp_millis()),
865            format!("Esemény: {}", event_type),
866            BlockType::Event,
867            details,
868        )
869        .with_tag("event")
870        .with_tag(event_type);
871
872        self.add(block)
873    }
874}
875
876// ============================================================================
877// TESTS
878// ============================================================================
879
880#[cfg(test)]
881mod tests {
882    use super::*;
883
884    #[test]
885    fn test_code_block_creation() {
886        let block = CodeBlock::new(
887            "test_block",
888            "Testing purpose",
889            BlockType::Data,
890            "Test content",
891        )
892        .with_importance(0.8)
893        .with_tag("test");
894
895        assert_eq!(block.name, "test_block");
896        assert_eq!(block.importance, 0.8);
897        assert!(block.tags.contains("test"));
898    }
899
900    #[test]
901    fn test_code_graph_add_get() {
902        let graph = CodeGraph::new();
903
904        let block = CodeBlock::new("test", "purpose", BlockType::Data, "content");
905        let id = graph.add(block).unwrap();
906
907        let retrieved = graph.get(&id);
908        assert!(retrieved.is_some());
909        assert_eq!(retrieved.unwrap().name, "test");
910    }
911
912    #[test]
913    fn test_code_graph_connect() {
914        let graph = CodeGraph::new();
915
916        let block1 = CodeBlock::new("block1", "p1", BlockType::Data, "c1");
917        let block2 = CodeBlock::new("block2", "p2", BlockType::Data, "c2");
918
919        let id1 = graph.add(block1).unwrap();
920        let id2 = graph.add(block2).unwrap();
921
922        graph.connect(&id1, &id2, ConnectionType::ConnectsTo, 1.0);
923
924        let connected = graph.get_connected(&id1, None);
925        assert_eq!(connected.len(), 1);
926        assert_eq!(connected[0].name, "block2");
927
928        // Inverse connection
929        let connected_back = graph.get_connected(&id2, None);
930        assert_eq!(connected_back.len(), 1);
931        assert_eq!(connected_back[0].name, "block1");
932    }
933
934    #[test]
935    fn test_code_graph_search() {
936        let graph = CodeGraph::new();
937
938        graph
939            .add(CodeBlock::new(
940                "hello_world",
941                "p",
942                BlockType::Data,
943                "Hello World!",
944            ))
945            .unwrap();
946        graph
947            .add(CodeBlock::new("goodbye", "p", BlockType::Data, "Goodbye!"))
948            .unwrap();
949
950        let results = graph.search("hello");
951        assert_eq!(results.len(), 1);
952        assert_eq!(results[0].name, "hello_world");
953    }
954
955    #[test]
956    fn test_code_graph_traverse() {
957        let graph = CodeGraph::new();
958
959        let id1 = graph
960            .add(CodeBlock::new("a", "p", BlockType::Data, "A"))
961            .unwrap();
962        let id2 = graph
963            .add(CodeBlock::new("b", "p", BlockType::Data, "B"))
964            .unwrap();
965        let id3 = graph
966            .add(CodeBlock::new("c", "p", BlockType::Data, "C"))
967            .unwrap();
968
969        graph.connect(&id1, &id2, ConnectionType::ConnectsTo, 1.0);
970        graph.connect(&id2, &id3, ConnectionType::ConnectsTo, 1.0);
971
972        let traversal = graph.traverse_bfs(&id1, 10);
973        assert_eq!(traversal.len(), 3);
974    }
975
976    #[test]
977    fn test_find_path() {
978        let graph = CodeGraph::new();
979
980        let id1 = graph
981            .add(CodeBlock::new("start", "p", BlockType::Data, ""))
982            .unwrap();
983        let id2 = graph
984            .add(CodeBlock::new("middle", "p", BlockType::Data, ""))
985            .unwrap();
986        let id3 = graph
987            .add(CodeBlock::new("end", "p", BlockType::Data, ""))
988            .unwrap();
989
990        graph.connect(&id1, &id2, ConnectionType::ConnectsTo, 1.0);
991        graph.connect(&id2, &id3, ConnectionType::ConnectsTo, 1.0);
992
993        let path = graph.find_path(&id1, &id3);
994        assert!(path.is_some());
995        assert_eq!(path.unwrap().len(), 3);
996    }
997
998    #[test]
999    fn test_memory_emotion_person() {
1000        let graph = CodeGraph::new();
1001
1002        let mem_id = graph.remember("Fontos emlék", 0.9).unwrap();
1003        let emo_id = graph.feel("joy", 0.8, Some("good news")).unwrap();
1004        let person_id = graph.know_person("Máté", "creator", 1.0).unwrap();
1005
1006        // Connect memory to emotion and person
1007        graph.connect(&mem_id, &emo_id, ConnectionType::TriggeredBy, 0.9);
1008        graph.connect(&mem_id, &person_id, ConnectionType::References, 1.0);
1009
1010        let memories = graph.find_by_type(BlockType::Memory);
1011        assert_eq!(memories.len(), 1);
1012
1013        let emotions = graph.find_by_type(BlockType::Emotion);
1014        assert_eq!(emotions.len(), 1);
1015
1016        let persons = graph.find_by_type(BlockType::Person);
1017        assert_eq!(persons.len(), 1);
1018    }
1019
1020    #[test]
1021    fn test_stats() {
1022        let graph = CodeGraph::new();
1023
1024        graph.remember("m1", 0.5).unwrap();
1025        graph.remember("m2", 0.5).unwrap();
1026        graph.feel("joy", 0.8, None).unwrap();
1027
1028        let stats = graph.stats();
1029        assert_eq!(stats.total_blocks, 3);
1030        assert_eq!(stats.type_counts.get(&BlockType::Memory), Some(&2));
1031        assert_eq!(stats.type_counts.get(&BlockType::Emotion), Some(&1));
1032    }
1033}