Skip to main content

rust_rule_engine/engine/
engine.rs

1use crate::engine::{
2    agenda::{ActivationGroupManager, AgendaManager},
3    analytics::RuleAnalytics,
4    facts::Facts,
5    knowledge_base::KnowledgeBase,
6    plugin::{PluginConfig, PluginInfo, PluginManager, PluginStats},
7    workflow::WorkflowEngine,
8};
9use crate::errors::{Result, RuleEngineError};
10use crate::types::{ActionType, Operator, Value};
11use chrono::{DateTime, Utc};
12use log::info;
13use std::collections::HashMap;
14use std::time::{Duration, Instant};
15
16/// Type for custom function implementations
17pub type CustomFunction = Box<dyn Fn(&[Value], &Facts) -> Result<Value> + Send + Sync>;
18
19/// Type for custom action handlers
20pub type ActionHandler = Box<dyn Fn(&HashMap<String, Value>, &Facts) -> Result<()> + Send + Sync>;
21
22/// Configuration options for the rule engine
23#[derive(Debug, Clone)]
24pub struct EngineConfig {
25    /// Maximum number of execution cycles
26    pub max_cycles: usize,
27    /// Execution timeout
28    pub timeout: Option<Duration>,
29    /// Enable performance statistics collection
30    pub enable_stats: bool,
31    /// Enable debug mode with verbose logging
32    pub debug_mode: bool,
33}
34
35impl Default for EngineConfig {
36    fn default() -> Self {
37        Self {
38            max_cycles: 100,
39            timeout: Some(Duration::from_secs(30)),
40            enable_stats: true,
41            debug_mode: false,
42        }
43    }
44}
45
46/// Result of rule engine execution
47#[derive(Debug, Clone)]
48pub struct GruleExecutionResult {
49    /// Number of execution cycles
50    pub cycle_count: usize,
51    /// Number of rules evaluated
52    pub rules_evaluated: usize,
53    /// Number of rules that fired
54    pub rules_fired: usize,
55    /// Total execution time
56    pub execution_time: Duration,
57}
58
59/// Rust Rule Engine - High-performance rule execution engine
60pub struct RustRuleEngine {
61    knowledge_base: KnowledgeBase,
62    config: EngineConfig,
63    custom_functions: HashMap<String, CustomFunction>,
64    action_handlers: HashMap<String, ActionHandler>,
65    analytics: Option<RuleAnalytics>,
66    agenda_manager: AgendaManager,
67    activation_group_manager: ActivationGroupManager,
68    /// Track rules that have fired globally (for no-loop support)
69    fired_rules_global: std::collections::HashSet<String>,
70    /// Workflow engine for rule chaining and sequential execution
71    workflow_engine: WorkflowEngine,
72    /// Plugin manager for extensible functionality
73    plugin_manager: PluginManager,
74}
75
76#[allow(dead_code)]
77impl RustRuleEngine {
78    /// Execute all rules and call callback when a rule is fired
79    pub fn execute_with_callback<F>(
80        &mut self,
81        facts: &Facts,
82        mut on_rule_fired: F,
83    ) -> Result<GruleExecutionResult>
84    where
85        F: FnMut(&str, &Facts),
86    {
87        use chrono::Utc;
88        let timestamp = Utc::now();
89        let start_time = std::time::Instant::now();
90        let mut cycle_count = 0;
91        let mut rules_evaluated = 0;
92        let mut rules_fired = 0;
93
94        self.sync_workflow_agenda_activations();
95
96        for cycle in 0..self.config.max_cycles {
97            cycle_count = cycle + 1;
98            let mut any_rule_fired = false;
99            let mut fired_rules_in_cycle = std::collections::HashSet::new();
100            self.activation_group_manager.reset_cycle();
101
102            if let Some(timeout) = self.config.timeout {
103                if start_time.elapsed() > timeout {
104                    return Err(crate::errors::RuleEngineError::EvaluationError {
105                        message: "Execution timeout exceeded".to_string(),
106                    });
107                }
108            }
109
110            let rule_indices = self.knowledge_base.get_rules_by_salience();
111
112            for &rule_index in &rule_indices {
113                if let Some(rule) = self.knowledge_base.get_rule_by_index(rule_index) {
114                    if !rule.enabled {
115                        continue;
116                    }
117                    if !self.agenda_manager.should_evaluate_rule(&rule) {
118                        continue;
119                    }
120                    if !rule.is_active_at(timestamp) {
121                        continue;
122                    }
123                    if !self.agenda_manager.can_fire_rule(&rule) {
124                        continue;
125                    }
126                    if !self.activation_group_manager.can_fire(&rule) {
127                        continue;
128                    }
129                    if rule.no_loop && self.fired_rules_global.contains(&rule.name) {
130                        continue;
131                    }
132                    rules_evaluated += 1;
133                    let condition_result = self.evaluate_conditions(&rule.conditions, facts)?;
134                    if condition_result {
135                        for action in &rule.actions {
136                            self.execute_action(action, facts)?;
137                        }
138                        rules_fired += 1;
139                        any_rule_fired = true;
140                        fired_rules_in_cycle.insert(rule.name.clone());
141                        if rule.no_loop {
142                            self.fired_rules_global.insert(rule.name.clone());
143                        }
144                        self.agenda_manager.mark_rule_fired(&rule);
145                        self.activation_group_manager.mark_fired(&rule);
146                        on_rule_fired(&rule.name, facts);
147                    }
148                }
149            }
150            if !any_rule_fired {
151                break;
152            }
153            self.sync_workflow_agenda_activations();
154        }
155        let execution_time = start_time.elapsed();
156        Ok(crate::engine::GruleExecutionResult {
157            cycle_count,
158            rules_evaluated,
159            rules_fired,
160            execution_time,
161        })
162    }
163    /// Create a new RustRuleEngine with default configuration
164    pub fn new(knowledge_base: KnowledgeBase) -> Self {
165        Self {
166            knowledge_base,
167            config: EngineConfig::default(),
168            custom_functions: HashMap::new(),
169            action_handlers: HashMap::new(),
170            analytics: None,
171            agenda_manager: AgendaManager::new(),
172            activation_group_manager: ActivationGroupManager::new(),
173            fired_rules_global: std::collections::HashSet::new(),
174            workflow_engine: WorkflowEngine::new(),
175            plugin_manager: PluginManager::with_default_config(),
176        }
177    }
178
179    /// Create a new RustRuleEngine with custom configuration
180    pub fn with_config(knowledge_base: KnowledgeBase, config: EngineConfig) -> Self {
181        Self {
182            knowledge_base,
183            config,
184            custom_functions: HashMap::new(),
185            action_handlers: HashMap::new(),
186            analytics: None,
187            agenda_manager: AgendaManager::new(),
188            activation_group_manager: ActivationGroupManager::new(),
189            fired_rules_global: std::collections::HashSet::new(),
190            workflow_engine: WorkflowEngine::new(),
191            plugin_manager: PluginManager::with_default_config(),
192        }
193    }
194
195    /// Register a custom function
196    pub fn register_function<F>(&mut self, name: &str, func: F)
197    where
198        F: Fn(&[Value], &Facts) -> Result<Value> + Send + Sync + 'static,
199    {
200        self.custom_functions
201            .insert(name.to_string(), Box::new(func));
202    }
203
204    /// Register a custom action handler
205    pub fn register_action_handler<F>(&mut self, action_type: &str, handler: F)
206    where
207        F: Fn(&HashMap<String, Value>, &Facts) -> Result<()> + Send + Sync + 'static,
208    {
209        self.action_handlers
210            .insert(action_type.to_string(), Box::new(handler));
211    }
212
213    /// Enable analytics with custom configuration
214    pub fn enable_analytics(&mut self, analytics: RuleAnalytics) {
215        self.analytics = Some(analytics);
216    }
217
218    /// Reset global no-loop tracking (useful for testing or when facts change significantly)
219    pub fn reset_no_loop_tracking(&mut self) {
220        self.fired_rules_global.clear();
221    }
222
223    /// Disable analytics
224    pub fn disable_analytics(&mut self) {
225        self.analytics = None;
226    }
227
228    /// Get reference to analytics data
229    pub fn analytics(&self) -> Option<&RuleAnalytics> {
230        self.analytics.as_ref()
231    }
232
233    /// Enable debug mode for detailed execution logging
234    pub fn set_debug_mode(&mut self, enabled: bool) {
235        self.config.debug_mode = enabled;
236    }
237
238    /// Check if a custom function is registered
239    pub fn has_function(&self, name: &str) -> bool {
240        self.custom_functions.contains_key(name)
241    }
242
243    /// Check if a custom action handler is registered
244    pub fn has_action_handler(&self, action_type: &str) -> bool {
245        self.action_handlers.contains_key(action_type)
246    }
247
248    /// Get ready scheduled tasks
249    pub fn get_ready_tasks(&mut self) -> Vec<crate::engine::workflow::ScheduledTask> {
250        self.workflow_engine.get_ready_tasks()
251    }
252
253    /// Execute scheduled tasks that are ready
254    pub fn execute_scheduled_tasks(&mut self, facts: &Facts) -> Result<()> {
255        let ready_tasks = self.get_ready_tasks();
256        for task in ready_tasks {
257            if let Some(rule) = self.knowledge_base.get_rule(&task.rule_name) {
258                if self.config.debug_mode {
259                    println!("⚡ Executing scheduled task: {}", task.rule_name);
260                }
261
262                // Execute just this one rule if conditions match
263                if self.evaluate_conditions(&rule.conditions, facts)? {
264                    for action in &rule.actions {
265                        self.execute_action(action, facts)?;
266                    }
267                }
268            }
269        }
270        Ok(())
271    }
272
273    /// Activate agenda group
274    pub fn activate_agenda_group(&mut self, group: String) {
275        self.workflow_engine.activate_agenda_group(group.clone());
276        self.agenda_manager.set_focus(&group);
277    }
278
279    /// Get the knowledge base
280    pub fn knowledge_base(&self) -> &KnowledgeBase {
281        &self.knowledge_base
282    }
283
284    /// Get mutable reference to knowledge base
285    pub fn knowledge_base_mut(&mut self) -> &mut KnowledgeBase {
286        &mut self.knowledge_base
287    }
288
289    /// Sync workflow engine agenda activations with agenda manager
290    fn sync_workflow_agenda_activations(&mut self) {
291        // Process any pending agenda activations from workflow engine
292        while let Some(agenda_group) = self.workflow_engine.get_next_pending_agenda_activation() {
293            if self.config.debug_mode {
294                println!("🔄 Syncing workflow agenda activation: {}", agenda_group);
295            }
296            self.agenda_manager.set_focus(&agenda_group);
297        }
298    }
299
300    /// Set focus to a specific agenda group
301    pub fn set_agenda_focus(&mut self, group: &str) {
302        self.agenda_manager.set_focus(group);
303    }
304
305    /// Get the currently active agenda group
306    pub fn get_active_agenda_group(&self) -> &str {
307        self.agenda_manager.get_active_group()
308    }
309
310    /// Pop the agenda focus stack
311    pub fn pop_agenda_focus(&mut self) -> Option<String> {
312        self.agenda_manager.pop_focus()
313    }
314
315    /// Clear all agenda focus and return to MAIN
316    pub fn clear_agenda_focus(&mut self) {
317        self.agenda_manager.clear_focus();
318    }
319
320    /// Get all agenda groups that have rules
321    pub fn get_agenda_groups(&self) -> Vec<String> {
322        self.agenda_manager
323            .get_agenda_groups(&self.knowledge_base.get_rules())
324    }
325
326    /// Get all activation groups that have rules
327    pub fn get_activation_groups(&self) -> Vec<String> {
328        self.activation_group_manager
329            .get_activation_groups(&self.knowledge_base.get_rules())
330    }
331
332    // 🔄 Workflow Engine Methods
333
334    /// Start a new workflow
335    pub fn start_workflow(&mut self, workflow_name: Option<String>) -> String {
336        self.workflow_engine.start_workflow(workflow_name)
337    }
338
339    /// Get workflow statistics
340    pub fn get_workflow_stats(&self) -> crate::engine::workflow::WorkflowStats {
341        self.workflow_engine.get_workflow_stats()
342    }
343
344    /// Get workflow state by ID
345    pub fn get_workflow(
346        &self,
347        workflow_id: &str,
348    ) -> Option<&crate::engine::workflow::WorkflowState> {
349        self.workflow_engine.get_workflow(workflow_id)
350    }
351
352    /// Clean up completed workflows
353    pub fn cleanup_completed_workflows(&mut self, older_than: Duration) {
354        self.workflow_engine.cleanup_completed_workflows(older_than);
355    }
356
357    /// Execute workflow step by activating specific agenda group
358    pub fn execute_workflow_step(
359        &mut self,
360        agenda_group: &str,
361        facts: &Facts,
362    ) -> Result<GruleExecutionResult> {
363        // Set agenda focus to the specific group
364        self.set_agenda_focus(agenda_group);
365
366        // Execute rules in that group
367        let result = self.execute(facts)?;
368
369        // Process any workflow actions that were triggered
370        self.process_workflow_actions(facts)?;
371
372        Ok(result)
373    }
374
375    /// Execute a complete workflow by processing agenda groups sequentially
376    pub fn execute_workflow(
377        &mut self,
378        agenda_groups: Vec<&str>,
379        facts: &Facts,
380    ) -> Result<crate::engine::workflow::WorkflowResult> {
381        let start_time = Instant::now();
382        let mut total_steps = 0;
383
384        if self.config.debug_mode {
385            println!(
386                "🔄 Starting workflow execution with {} steps",
387                agenda_groups.len()
388            );
389        }
390
391        for (i, group) in agenda_groups.iter().enumerate() {
392            if self.config.debug_mode {
393                println!("📋 Executing workflow step {}: {}", i + 1, group);
394            }
395
396            let step_result = self.execute_workflow_step(group, facts)?;
397            total_steps += 1;
398
399            if step_result.rules_fired == 0 {
400                if self.config.debug_mode {
401                    println!("⏸️ No rules fired in step '{}', stopping workflow", group);
402                }
403                break;
404            }
405        }
406
407        let execution_time = start_time.elapsed();
408
409        Ok(crate::engine::workflow::WorkflowResult::success(
410            total_steps,
411            execution_time,
412        ))
413    }
414
415    /// Process workflow-related actions and scheduled tasks
416    fn process_workflow_actions(&mut self, facts: &Facts) -> Result<()> {
417        // Process agenda group activations
418        while let Some(group) = self.workflow_engine.get_next_agenda_group() {
419            self.set_agenda_focus(&group);
420        }
421
422        // Process scheduled tasks
423        let ready_tasks = self.workflow_engine.get_ready_tasks();
424        for task in ready_tasks {
425            if self.config.debug_mode {
426                println!("⚡ Executing scheduled task: {}", task.rule_name);
427            }
428
429            // Find and execute the specific rule
430            if let Some(rule) = self.knowledge_base.get_rule(&task.rule_name) {
431                // Execute just this one rule
432                if self.evaluate_conditions(&rule.conditions, facts)? {
433                    for action in &rule.actions {
434                        self.execute_action(action, facts)?;
435                    }
436                }
437            }
438        }
439
440        Ok(())
441    }
442
443    /// Execute all rules in the knowledge base against the given facts
444    pub fn execute(&mut self, facts: &Facts) -> Result<GruleExecutionResult> {
445        self.execute_at_time(facts, Utc::now())
446    }
447
448    /// Execute all rules at a specific timestamp (for date-effective/expires testing)
449    pub fn execute_at_time(
450        &mut self,
451        facts: &Facts,
452        timestamp: DateTime<Utc>,
453    ) -> Result<GruleExecutionResult> {
454        let start_time = Instant::now();
455        let mut cycle_count = 0;
456        let mut rules_evaluated = 0;
457        let mut rules_fired = 0;
458
459        // Process any pending agenda group activations from workflow engine
460        self.sync_workflow_agenda_activations();
461
462        if self.config.debug_mode {
463            println!(
464                "🚀 Starting rule execution with {} rules (agenda group: {})",
465                self.knowledge_base.rule_count(),
466                self.agenda_manager.get_active_group()
467            );
468        }
469
470        for cycle in 0..self.config.max_cycles {
471            cycle_count = cycle + 1;
472            let mut any_rule_fired = false;
473            let mut fired_rules_in_cycle = std::collections::HashSet::new();
474
475            // Reset activation groups for each cycle
476            self.activation_group_manager.reset_cycle();
477
478            // Check for timeout
479            if let Some(timeout) = self.config.timeout {
480                if start_time.elapsed() > timeout {
481                    return Err(RuleEngineError::EvaluationError {
482                        message: "Execution timeout exceeded".to_string(),
483                    });
484                }
485            }
486
487            // Get rule indices sorted by salience (highest first) - avoids cloning rules
488            let rule_indices = self.knowledge_base.get_rules_by_salience();
489
490            // Process rules by index to avoid cloning
491            for &rule_index in &rule_indices {
492                if let Some(rule) = self.knowledge_base.get_rule_by_index(rule_index) {
493                    if !rule.enabled {
494                        continue;
495                    }
496
497                    if !self.agenda_manager.should_evaluate_rule(&rule) {
498                        continue;
499                    }
500
501                    // Check date effective/expires
502                    if !rule.is_active_at(timestamp) {
503                        continue;
504                    }
505
506                    // Check agenda group constraints (lock-on-active)
507                    if !self.agenda_manager.can_fire_rule(&rule) {
508                        continue;
509                    }
510
511                    // Check activation group constraints (only one rule per group can fire)
512                    if !self.activation_group_manager.can_fire(&rule) {
513                        continue;
514                    }
515
516                    // Check no-loop: skip if already fired in this execution cycle
517                    if rule.no_loop && self.fired_rules_global.contains(&rule.name) {
518                        if self.config.debug_mode {
519                            println!("⛔ Skipping '{}' due to no_loop (already fired)", rule.name);
520                        }
521                        continue;
522                    }
523
524                    // Debug
525                    if self.config.debug_mode {
526                        println!(
527                            "🔍 Checking rule '{}' (no_loop: {})",
528                            rule.name, rule.no_loop
529                        );
530                    }
531
532                    let rule_start = std::time::Instant::now();
533
534                    // Count rule evaluation
535                    rules_evaluated += 1;
536
537                    // Evaluate rule conditions
538                    let condition_result = self.evaluate_conditions(&rule.conditions, facts)?;
539
540                    if self.config.debug_mode {
541                        println!(
542                            "   Rule '{}' condition result: {}",
543                            rule.name, condition_result
544                        );
545                    }
546
547                    // If conditions match, fire the rule
548                    if condition_result {
549                        if self.config.debug_mode {
550                            println!(
551                                "🔥 Firing rule '{}' (salience: {})",
552                                rule.name, rule.salience
553                            );
554                        }
555
556                        // Execute actions
557                        for action in &rule.actions {
558                            self.execute_action(action, facts)?;
559                        }
560
561                        let rule_duration = rule_start.elapsed();
562
563                        // Record analytics if enabled
564                        if let Some(analytics) = &mut self.analytics {
565                            analytics.record_execution(
566                                &rule.name,
567                                rule_duration,
568                                true,
569                                true,
570                                None,
571                                0,
572                            );
573                        }
574
575                        rules_fired += 1;
576                        any_rule_fired = true;
577
578                        // Track that this rule fired in this cycle (for cycle counting)
579                        fired_rules_in_cycle.insert(rule.name.clone());
580
581                        // Track that this rule fired globally (for no-loop support)
582                        if rule.no_loop {
583                            self.fired_rules_global.insert(rule.name.clone());
584                            if self.config.debug_mode {
585                                println!("  🔒 Marked '{}' as fired (no_loop tracking)", rule.name);
586                            }
587                        }
588
589                        // Mark rule as fired for agenda and activation group management
590                        self.agenda_manager.mark_rule_fired(&rule);
591                        self.activation_group_manager.mark_fired(&rule);
592                    } else {
593                        let rule_duration = rule_start.elapsed();
594
595                        // Record analytics for failed rules too
596                        if let Some(analytics) = &mut self.analytics {
597                            analytics.record_execution(
598                                &rule.name,
599                                rule_duration,
600                                false,
601                                false,
602                                None,
603                                0,
604                            );
605                        }
606                    }
607                } // Close if let Some(rule)
608            }
609
610            // If no rules fired in this cycle, we're done
611            if !any_rule_fired {
612                break;
613            }
614
615            // Sync any new workflow agenda activations at the end of each cycle
616            self.sync_workflow_agenda_activations();
617        }
618
619        let execution_time = start_time.elapsed();
620
621        Ok(GruleExecutionResult {
622            cycle_count,
623            rules_evaluated,
624            rules_fired,
625            execution_time,
626        })
627    }
628
629    /// Evaluate conditions against facts
630    fn evaluate_conditions(
631        &self,
632        conditions: &crate::engine::rule::ConditionGroup,
633        facts: &Facts,
634    ) -> Result<bool> {
635        use crate::engine::pattern_matcher::PatternMatcher;
636        use crate::engine::rule::ConditionGroup;
637
638        match conditions {
639            ConditionGroup::Single(condition) => self.evaluate_single_condition(condition, facts),
640            ConditionGroup::Compound {
641                left,
642                operator,
643                right,
644            } => {
645                let left_result = self.evaluate_conditions(left, facts)?;
646                let right_result = self.evaluate_conditions(right, facts)?;
647
648                match operator {
649                    crate::types::LogicalOperator::And => Ok(left_result && right_result),
650                    crate::types::LogicalOperator::Or => Ok(left_result || right_result),
651                    crate::types::LogicalOperator::Not => Err(RuleEngineError::EvaluationError {
652                        message: "NOT operator should not appear in compound conditions"
653                            .to_string(),
654                    }),
655                }
656            }
657            ConditionGroup::Not(condition) => {
658                let result = self.evaluate_conditions(condition, facts)?;
659                Ok(!result)
660            }
661            // Pattern matching conditions
662            ConditionGroup::Exists(condition) => {
663                Ok(PatternMatcher::evaluate_exists(condition, facts))
664            }
665            ConditionGroup::Forall(condition) => {
666                Ok(PatternMatcher::evaluate_forall(condition, facts))
667            }
668            ConditionGroup::Accumulate {
669                result_var,
670                source_pattern,
671                extract_field,
672                source_conditions,
673                function,
674                function_arg,
675            } => {
676                // Evaluate accumulate and inject result into facts
677                self.evaluate_accumulate(
678                    result_var,
679                    source_pattern,
680                    extract_field,
681                    source_conditions,
682                    function,
683                    function_arg,
684                    facts,
685                )?;
686                // After injecting result, return true to continue
687                Ok(true)
688            }
689
690            #[cfg(feature = "streaming")]
691            ConditionGroup::StreamPattern { .. } => {
692                // Stream patterns are handled by the streaming engine, not here
693                // For forward chaining context, return true to allow rule evaluation
694                Ok(true)
695            }
696        }
697    }
698
699    /// Evaluate accumulate condition and inject result into facts
700    #[allow(clippy::too_many_arguments)]
701    fn evaluate_accumulate(
702        &self,
703        _result_var: &str,
704        source_pattern: &str,
705        extract_field: &str,
706        source_conditions: &[String],
707        function: &str,
708        _function_arg: &str,
709        facts: &Facts,
710    ) -> Result<()> {
711        use crate::rete::accumulate::*;
712
713        // 1. Collect all facts matching the source pattern
714        let all_facts = facts.get_all_facts();
715        let mut matching_values = Vec::new();
716
717        // Find all facts that match the pattern (e.g., "Order.amount", "Order.status")
718        let pattern_prefix = format!("{}.", source_pattern);
719
720        // Group facts by instance (e.g., Order.1.amount, Order.1.status) - pre-sized for performance
721        let mut instances: HashMap<String, HashMap<String, Value>> = HashMap::with_capacity(16);
722
723        for (key, value) in &all_facts {
724            if key.starts_with(&pattern_prefix) {
725                // Extract instance ID if present (e.g., "Order.1.amount" -> "1")
726                let parts: Vec<&str> = key
727                    .strip_prefix(&pattern_prefix)
728                    .unwrap()
729                    .split('.')
730                    .collect();
731
732                if parts.len() >= 2 {
733                    // Has instance ID: Order.1.amount
734                    let instance_id = parts[0];
735                    let field_name = parts[1..].join(".");
736
737                    instances
738                        .entry(instance_id.to_string())
739                        .or_default()
740                        .insert(field_name, value.clone());
741                } else if parts.len() == 1 {
742                    // No instance ID: Order.amount (single instance)
743                    instances
744                        .entry("default".to_string())
745                        .or_default()
746                        .insert(parts[0].to_string(), value.clone());
747                }
748            }
749        }
750
751        // 2. Filter instances by source conditions
752        for (_instance_id, instance_facts) in instances {
753            // Check if this instance matches all source conditions
754            let mut matches = true;
755
756            for condition_str in source_conditions {
757                // Parse condition: "status == \"completed\""
758                if !self.evaluate_condition_string(condition_str, &instance_facts) {
759                    matches = false;
760                    break;
761                }
762            }
763
764            if matches {
765                // Extract the field value
766                if let Some(value) = instance_facts.get(extract_field) {
767                    matching_values.push(value.clone());
768                }
769            }
770        }
771
772        // 3. Run accumulate function
773        let result = match function {
774            "sum" => {
775                let mut state = SumFunction.init();
776                for value in &matching_values {
777                    state.accumulate(&self.value_to_fact_value(value));
778                }
779                self.fact_value_to_value(&state.get_result())
780            }
781            "count" => {
782                let mut state = CountFunction.init();
783                for value in &matching_values {
784                    state.accumulate(&self.value_to_fact_value(value));
785                }
786                self.fact_value_to_value(&state.get_result())
787            }
788            "average" | "avg" => {
789                let mut state = AverageFunction.init();
790                for value in &matching_values {
791                    state.accumulate(&self.value_to_fact_value(value));
792                }
793                self.fact_value_to_value(&state.get_result())
794            }
795            "min" => {
796                let mut state = MinFunction.init();
797                for value in &matching_values {
798                    state.accumulate(&self.value_to_fact_value(value));
799                }
800                self.fact_value_to_value(&state.get_result())
801            }
802            "max" => {
803                let mut state = MaxFunction.init();
804                for value in &matching_values {
805                    state.accumulate(&self.value_to_fact_value(value));
806                }
807                self.fact_value_to_value(&state.get_result())
808            }
809            _ => {
810                return Err(RuleEngineError::EvaluationError {
811                    message: format!("Unknown accumulate function: {}", function),
812                });
813            }
814        };
815
816        // 4. Inject result into facts
817        // Use pattern.function as key to avoid collision
818        let result_key = format!("{}.{}", source_pattern, function);
819
820        facts.set(&result_key, result);
821
822        if self.config.debug_mode {
823            println!(
824                "    🧮 Accumulate result: {} = {:?}",
825                result_key,
826                facts.get(&result_key)
827            );
828        }
829
830        Ok(())
831    }
832
833    /// Helper: Convert Value to FactValue
834    fn value_to_fact_value(&self, value: &Value) -> crate::rete::facts::FactValue {
835        use crate::rete::facts::FactValue;
836        match value {
837            Value::Integer(i) => FactValue::Integer(*i),
838            Value::Number(n) => FactValue::Float(*n),
839            Value::String(s) => FactValue::String(s.clone()),
840            Value::Boolean(b) => FactValue::Boolean(*b),
841            _ => FactValue::String(value.to_string()),
842        }
843    }
844
845    /// Helper: Convert FactValue to Value
846    fn fact_value_to_value(&self, fact_value: &crate::rete::facts::FactValue) -> Value {
847        use crate::rete::facts::FactValue;
848        match fact_value {
849            FactValue::Integer(i) => Value::Integer(*i),
850            FactValue::Float(f) => Value::Number(*f),
851            FactValue::String(s) => Value::String(s.clone()),
852            FactValue::Boolean(b) => Value::Boolean(*b),
853            FactValue::Array(_) => Value::String(format!("{:?}", fact_value)),
854            FactValue::Null => Value::String("null".to_string()),
855        }
856    }
857
858    /// Helper: Evaluate a condition string against facts
859    fn evaluate_condition_string(&self, condition: &str, facts: &HashMap<String, Value>) -> bool {
860        // Simple condition parser: "field == value" or "field != value", etc.
861        let condition = condition.trim();
862
863        // Try to parse operator
864        let operators = ["==", "!=", ">=", "<=", ">", "<"];
865
866        for op in &operators {
867            if let Some(pos) = condition.find(op) {
868                let field = condition[..pos].trim();
869                let value_str = condition[pos + op.len()..]
870                    .trim()
871                    .trim_matches('"')
872                    .trim_matches('\'');
873
874                if let Some(field_value) = facts.get(field) {
875                    return self.compare_values(field_value, op, value_str);
876                } else {
877                    return false;
878                }
879            }
880        }
881
882        false
883    }
884
885    /// Helper: Compare values
886    fn compare_values(&self, field_value: &Value, operator: &str, value_str: &str) -> bool {
887        match field_value {
888            Value::String(s) => match operator {
889                "==" => s == value_str,
890                "!=" => s != value_str,
891                _ => false,
892            },
893            Value::Integer(i) => {
894                if let Ok(num) = value_str.parse::<i64>() {
895                    match operator {
896                        "==" => *i == num,
897                        "!=" => *i != num,
898                        ">" => *i > num,
899                        "<" => *i < num,
900                        ">=" => *i >= num,
901                        "<=" => *i <= num,
902                        _ => false,
903                    }
904                } else {
905                    false
906                }
907            }
908            Value::Number(n) => {
909                if let Ok(num) = value_str.parse::<f64>() {
910                    match operator {
911                        "==" => (*n - num).abs() < f64::EPSILON,
912                        "!=" => (*n - num).abs() >= f64::EPSILON,
913                        ">" => *n > num,
914                        "<" => *n < num,
915                        ">=" => *n >= num,
916                        "<=" => *n <= num,
917                        _ => false,
918                    }
919                } else {
920                    false
921                }
922            }
923            Value::Boolean(b) => {
924                if let Ok(bool_val) = value_str.parse::<bool>() {
925                    match operator {
926                        "==" => *b == bool_val,
927                        "!=" => *b != bool_val,
928                        _ => false,
929                    }
930                } else {
931                    false
932                }
933            }
934            _ => false,
935        }
936    }
937
938    /// Evaluate rule conditions - wrapper for evaluate_conditions for compatibility
939    fn evaluate_rule_conditions(
940        &self,
941        rule: &crate::engine::rule::Rule,
942        facts: &Facts,
943    ) -> Result<bool> {
944        self.evaluate_conditions(&rule.conditions, facts)
945    }
946
947    /// Check if a fact object has been retracted
948    fn is_retracted(&self, object_name: &str, facts: &Facts) -> bool {
949        let retract_key = format!("_retracted_{}", object_name);
950        matches!(facts.get(&retract_key), Some(Value::Boolean(true)))
951    }
952
953    /// Evaluate a single condition
954    fn evaluate_single_condition(
955        &self,
956        condition: &crate::engine::rule::Condition,
957        facts: &Facts,
958    ) -> Result<bool> {
959        use crate::engine::rule::ConditionExpression;
960
961        let result = match &condition.expression {
962            ConditionExpression::Field(field_name) => {
963                // Check if the fact object has been retracted
964                // Extract object name from field (e.g., "Session.expired" -> "Session")
965                if let Some(object_name) = field_name.split('.').next() {
966                    if self.is_retracted(object_name, facts) {
967                        if self.config.debug_mode {
968                            println!("    🗑️ Skipping retracted fact: {}", object_name);
969                        }
970                        return Ok(false);
971                    }
972                }
973
974                // Field condition - try nested first, then flat lookup
975                // If field not found, treat as Null for proper null checking
976                let field_value = facts
977                    .get_nested(field_name)
978                    .or_else(|| facts.get(field_name))
979                    .unwrap_or(Value::Null);
980
981                if self.config.debug_mode {
982                    println!(
983                        "    🔎 Evaluating field condition: {} {} {:?}",
984                        field_name,
985                        format!("{:?}", condition.operator).to_lowercase(),
986                        condition.value
987                    );
988                    println!("      Field value: {:?}", field_value);
989                }
990
991                // condition.operator.evaluate(&value, &condition.value)
992                // If the condition's right-hand value is a string that names another fact,
993                // try to resolve that fact and use its value for comparison. This allows
994                // rules like `L1 > L1Min` where the parser may have stored "L1Min"
995                // as a string literal.
996                let rhs = match &condition.value {
997                    crate::types::Value::String(s) => {
998                        // Try nested lookup first, then flat lookup
999                        facts
1000                            .get_nested(s)
1001                            .or_else(|| facts.get(s))
1002                            .unwrap_or(crate::types::Value::String(s.clone()))
1003                    }
1004                    crate::types::Value::Expression(expr) => {
1005                        // Try to evaluate expression - could be a variable reference or arithmetic
1006                        match crate::expression::evaluate_expression(expr, facts) {
1007                            Ok(evaluated) => evaluated,
1008                            Err(_) => {
1009                                // If evaluation fails, try as simple variable lookup
1010                                facts
1011                                    .get_nested(expr)
1012                                    .or_else(|| facts.get(expr))
1013                                    .unwrap_or(crate::types::Value::Expression(expr.clone()))
1014                            }
1015                        }
1016                    }
1017                    _ => condition.value.clone(),
1018                };
1019
1020                if self.config.debug_mode {
1021                    println!("      Resolved RHS for comparison: {:?}", rhs);
1022                }
1023
1024                condition.operator.evaluate(&field_value, &rhs)
1025            }
1026            ConditionExpression::FunctionCall { name, args } => {
1027                // Function call condition
1028                if self.config.debug_mode {
1029                    println!(
1030                        "    🔎 Evaluating function condition: {}({:?}) {} {:?}",
1031                        name,
1032                        args,
1033                        format!("{:?}", condition.operator).to_lowercase(),
1034                        condition.value
1035                    );
1036                }
1037
1038                if let Some(function) = self.custom_functions.get(name) {
1039                    // Resolve arguments from facts
1040                    let arg_values: Vec<Value> = args
1041                        .iter()
1042                        .map(|arg| {
1043                            facts
1044                                .get_nested(arg)
1045                                .or_else(|| facts.get(arg))
1046                                .unwrap_or(Value::String(arg.clone()))
1047                        })
1048                        .collect();
1049
1050                    // Call the function
1051                    match function(&arg_values, facts) {
1052                        Ok(result_value) => {
1053                            if self.config.debug_mode {
1054                                println!("      Function result: {:?}", result_value);
1055                            }
1056                            condition.operator.evaluate(&result_value, &condition.value)
1057                        }
1058                        Err(e) => {
1059                            if self.config.debug_mode {
1060                                println!("      Function error: {}", e);
1061                            }
1062                            false
1063                        }
1064                    }
1065                } else {
1066                    if self.config.debug_mode {
1067                        println!("      Function '{}' not found", name);
1068                    }
1069                    false
1070                }
1071            }
1072            ConditionExpression::Test { name, args } => {
1073                // Test CE condition - expects boolean result
1074                if self.config.debug_mode {
1075                    println!("    🧪 Evaluating test CE: test({}({:?}))", name, args);
1076                }
1077
1078                // Check if name is a registered custom function
1079                if let Some(function) = self.custom_functions.get(name) {
1080                    // Resolve arguments from facts
1081                    let arg_values: Vec<Value> = args
1082                        .iter()
1083                        .map(|arg| {
1084                            let resolved = facts
1085                                .get_nested(arg)
1086                                .or_else(|| facts.get(arg))
1087                                .unwrap_or(Value::String(arg.clone()));
1088                            if self.config.debug_mode {
1089                                println!("      Resolving arg '{}' -> {:?}", arg, resolved);
1090                            }
1091                            resolved
1092                        })
1093                        .collect();
1094
1095                    // Call the function
1096                    match function(&arg_values, facts) {
1097                        Ok(result_value) => {
1098                            if self.config.debug_mode {
1099                                println!("      Test result: {:?}", result_value);
1100                            }
1101                            // Test CE expects boolean result directly
1102                            match result_value {
1103                                Value::Boolean(b) => b,
1104                                Value::Integer(i) => i != 0,
1105                                Value::Number(f) => f != 0.0,
1106                                Value::String(s) => !s.is_empty(),
1107                                _ => false,
1108                            }
1109                        }
1110                        Err(e) => {
1111                            if self.config.debug_mode {
1112                                println!("      Test function error: {}", e);
1113                            }
1114                            false
1115                        }
1116                    }
1117                } else {
1118                    // Not a custom function - try to evaluate as arithmetic expression
1119                    // Format: "User.Age % 3 == 0" where name is the full expression
1120                    if self.config.debug_mode {
1121                        println!(
1122                            "      Trying to evaluate '{}' as arithmetic expression",
1123                            name
1124                        );
1125                    }
1126
1127                    // Try to parse and evaluate the expression
1128                    match self.evaluate_arithmetic_condition(name, facts) {
1129                        Ok(result) => {
1130                            if self.config.debug_mode {
1131                                println!("      Arithmetic expression result: {}", result);
1132                            }
1133                            result
1134                        }
1135                        Err(e) => {
1136                            if self.config.debug_mode {
1137                                println!("      Failed to evaluate expression: {}", e);
1138                                println!("      Test function '{}' not found", name);
1139                            }
1140                            false
1141                        }
1142                    }
1143                }
1144            }
1145            ConditionExpression::MultiField {
1146                field,
1147                operation,
1148                variable: _,
1149            } => {
1150                // Multi-field operation condition
1151                if self.config.debug_mode {
1152                    println!("    📦 Evaluating multi-field: {}.{}", field, operation);
1153                }
1154
1155                // Get the field value
1156                let field_value = facts.get_nested(field).or_else(|| facts.get(field));
1157
1158                if let Some(value) = field_value {
1159                    match operation.as_str() {
1160                        "empty" => {
1161                            matches!(value, Value::Array(arr) if arr.is_empty())
1162                        }
1163                        "not_empty" => {
1164                            matches!(value, Value::Array(arr) if !arr.is_empty())
1165                        }
1166                        "count" => {
1167                            if let Value::Array(arr) = value {
1168                                let count = Value::Integer(arr.len() as i64);
1169                                condition.operator.evaluate(&count, &condition.value)
1170                            } else {
1171                                false
1172                            }
1173                        }
1174                        "contains" => {
1175                            // Use existing contains operator
1176                            condition.operator.evaluate(&value, &condition.value)
1177                        }
1178                        _ => {
1179                            // Other operations (collect, first, last) not fully supported yet
1180                            // Return true to not block rule evaluation
1181                            if self.config.debug_mode {
1182                                println!(
1183                                    "      ⚠️ Operation '{}' not fully implemented yet",
1184                                    operation
1185                                );
1186                            }
1187                            true
1188                        }
1189                    }
1190                } else {
1191                    false
1192                }
1193            }
1194        };
1195
1196        if self.config.debug_mode {
1197            println!("      Result: {}", result);
1198        }
1199
1200        Ok(result)
1201    }
1202
1203    /// Execute an action
1204    fn execute_action(&mut self, action: &ActionType, facts: &Facts) -> Result<()> {
1205        match action {
1206            ActionType::Set { field, value } => {
1207                // Evaluate expression if value is an Expression
1208                let evaluated_value = match value {
1209                    Value::Expression(expr) => {
1210                        // Evaluate the expression with current facts
1211                        crate::expression::evaluate_expression(expr, facts)?
1212                    }
1213                    _ => value.clone(),
1214                };
1215
1216                // Try nested first, then fall back to flat key setting
1217                if facts.set_nested(field, evaluated_value.clone()).is_err() {
1218                    // If nested fails, use flat key
1219                    facts.set(field, evaluated_value.clone());
1220                }
1221                if self.config.debug_mode {
1222                    println!("  ✅ Set {field} = {evaluated_value:?}");
1223                }
1224            }
1225            ActionType::Log { message } => {
1226                println!("📋 LOG: {}", message);
1227            }
1228            ActionType::MethodCall {
1229                object,
1230                method,
1231                args,
1232            } => {
1233                let result = self.execute_method_call(object, method, args, facts)?;
1234                if self.config.debug_mode {
1235                    println!("  🔧 Called {object}.{method}({args:?}) -> {result}");
1236                }
1237            }
1238            ActionType::Retract { object } => {
1239                if self.config.debug_mode {
1240                    println!("  🗑️ Retracted {object}");
1241                }
1242                // Mark fact as retracted in working memory
1243                facts.set(&format!("_retracted_{}", object), Value::Boolean(true));
1244            }
1245            ActionType::Custom {
1246                action_type,
1247                params,
1248            } => {
1249                if let Some(handler) = self.action_handlers.get(action_type) {
1250                    if self.config.debug_mode {
1251                        println!(
1252                            "  🎯 Executing custom action: {action_type} with params: {params:?}"
1253                        );
1254                    }
1255
1256                    // Resolve parameter values from facts
1257                    let resolved_params = self.resolve_action_parameters(params, facts)?;
1258
1259                    // Execute the registered handler
1260                    handler(&resolved_params, facts)?;
1261                } else {
1262                    if self.config.debug_mode {
1263                        println!("  ⚠️ No handler registered for custom action: {action_type}");
1264                        println!(
1265                            "     Available handlers: {:?}",
1266                            self.action_handlers.keys().collect::<Vec<_>>()
1267                        );
1268                    }
1269
1270                    // Return error if no handler found
1271                    return Err(RuleEngineError::EvaluationError {
1272                        message: format!(
1273                            "No action handler registered for '{action_type}'. Use engine.register_action_handler() to add custom action handlers."
1274                        ),
1275                    });
1276                }
1277            }
1278            // 🔄 Workflow Actions
1279            ActionType::ActivateAgendaGroup { group } => {
1280                if self.config.debug_mode {
1281                    println!("  🎯 Activating agenda group: {}", group);
1282                }
1283                // Sync with both workflow engine and agenda manager immediately
1284                self.workflow_engine.activate_agenda_group(group.clone());
1285                self.agenda_manager.set_focus(group);
1286            }
1287            ActionType::ScheduleRule {
1288                rule_name,
1289                delay_ms,
1290            } => {
1291                if self.config.debug_mode {
1292                    println!(
1293                        "  ⏰ Scheduling rule '{}' to execute in {}ms",
1294                        rule_name, delay_ms
1295                    );
1296                }
1297                self.workflow_engine
1298                    .schedule_rule(rule_name.clone(), *delay_ms, None);
1299            }
1300            ActionType::CompleteWorkflow { workflow_name } => {
1301                if self.config.debug_mode {
1302                    println!("  ✅ Completing workflow: {}", workflow_name);
1303                }
1304                self.workflow_engine
1305                    .complete_workflow(workflow_name.clone());
1306            }
1307            ActionType::SetWorkflowData { key, value } => {
1308                if self.config.debug_mode {
1309                    println!("  💾 Setting workflow data: {} = {:?}", key, value);
1310                }
1311                // For now, we'll use a default workflow ID. Later this could be enhanced
1312                // to track current workflow context
1313                let workflow_id = "default_workflow";
1314                self.workflow_engine
1315                    .set_workflow_data(workflow_id, key.clone(), value.clone());
1316            }
1317            ActionType::Append { field, value } => {
1318                // Evaluate expression if value is an Expression
1319                let evaluated_value = match value {
1320                    Value::Expression(expr) => crate::expression::evaluate_expression(expr, facts)?,
1321                    _ => value.clone(),
1322                };
1323
1324                // Get current array or create new one
1325                let current_value = facts.get(field);
1326                let mut array = match current_value {
1327                    Some(Value::Array(arr)) => arr.clone(),
1328                    Some(_) => {
1329                        // Field exists but is not an array, create new array
1330                        if self.config.debug_mode {
1331                            println!("  ⚠️ Field {} is not an array, creating new array", field);
1332                        }
1333                        Vec::new()
1334                    }
1335                    None => Vec::new(),
1336                };
1337
1338                // Append value
1339                array.push(evaluated_value.clone());
1340
1341                // Set the updated array (try nested first, then flat)
1342                if facts
1343                    .set_nested(field, Value::Array(array.clone()))
1344                    .is_err()
1345                {
1346                    facts.set(field, Value::Array(array.clone()));
1347                }
1348
1349                if self.config.debug_mode {
1350                    println!("  ➕ Appended to {}: {:?}", field, evaluated_value);
1351                }
1352            }
1353        }
1354        Ok(())
1355    }
1356
1357    /// Evaluate arithmetic condition like "User.Age % 3 == 0"
1358    fn evaluate_arithmetic_condition(&self, expr: &str, facts: &Facts) -> Result<bool> {
1359        // Parse expression format: "left_expr operator right_value"
1360        // e.g., "User.Age % 3 == 0" or "User.Price * 2 > 100"
1361
1362        let operators = [">=", "<=", "==", "!=", ">", "<"];
1363        let mut split_pos = None;
1364        let mut found_op = "";
1365
1366        for op in &operators {
1367            if let Some(pos) = expr.rfind(op) {
1368                split_pos = Some(pos);
1369                found_op = op;
1370                break;
1371            }
1372        }
1373
1374        if split_pos.is_none() {
1375            return Err(RuleEngineError::EvaluationError {
1376                message: format!("No comparison operator found in expression: {}", expr),
1377            });
1378        }
1379
1380        let pos = split_pos.unwrap();
1381        let left_expr = expr[..pos].trim();
1382        let right_value = expr[pos + found_op.len()..].trim();
1383
1384        // Evaluate left side arithmetic expression
1385        let left_result = crate::expression::evaluate_expression(left_expr, facts)?;
1386
1387        // Parse right value
1388        let right_val = if let Ok(i) = right_value.parse::<i64>() {
1389            Value::Integer(i)
1390        } else if let Ok(f) = right_value.parse::<f64>() {
1391            Value::Number(f)
1392        } else {
1393            // Try to evaluate as expression or get from facts
1394            match crate::expression::evaluate_expression(right_value, facts) {
1395                Ok(v) => v,
1396                Err(_) => Value::String(right_value.to_string()),
1397            }
1398        };
1399
1400        // Compare values
1401        let operator =
1402            Operator::from_str(found_op).ok_or_else(|| RuleEngineError::InvalidOperator {
1403                operator: found_op.to_string(),
1404            })?;
1405
1406        Ok(operator.evaluate(&left_result, &right_val))
1407    }
1408
1409    /// Execute function call
1410    fn execute_function_call(
1411        &self,
1412        function: &str,
1413        args: &[Value],
1414        facts: &Facts,
1415    ) -> Result<String> {
1416        let function_lower = function.to_lowercase();
1417
1418        // Handle built-in utility functions
1419        match function_lower.as_str() {
1420            "log" | "print" | "println" => self.handle_log_function(args),
1421            "update" | "refresh" => self.handle_update_function(args),
1422            "now" | "timestamp" => self.handle_timestamp_function(),
1423            "random" => self.handle_random_function(args),
1424            "format" | "sprintf" => self.handle_format_function(args),
1425            "length" | "size" | "count" => self.handle_length_function(args),
1426            "sum" | "add" => self.handle_sum_function(args),
1427            "max" | "maximum" => self.handle_max_function(args),
1428            "min" | "minimum" => self.handle_min_function(args),
1429            "avg" | "average" => self.handle_average_function(args),
1430            "round" => self.handle_round_function(args),
1431            "floor" => self.handle_floor_function(args),
1432            "ceil" | "ceiling" => self.handle_ceil_function(args),
1433            "abs" | "absolute" => self.handle_abs_function(args),
1434            "contains" | "includes" => self.handle_contains_function(args),
1435            "startswith" | "begins_with" => self.handle_starts_with_function(args),
1436            "endswith" | "ends_with" => self.handle_ends_with_function(args),
1437            "lowercase" | "tolower" => self.handle_lowercase_function(args),
1438            "uppercase" | "toupper" => self.handle_uppercase_function(args),
1439            "trim" | "strip" => self.handle_trim_function(args),
1440            "split" => self.handle_split_function(args),
1441            "join" => self.handle_join_function(args),
1442            _ => {
1443                // Try to call custom user-defined function
1444                self.handle_custom_function(function, args, facts)
1445            }
1446        }
1447    }
1448
1449    /// Handle logging functions (log, print, println)
1450    fn handle_log_function(&self, args: &[Value]) -> Result<String> {
1451        let message = if args.is_empty() {
1452            "".to_string()
1453        } else if args.len() == 1 {
1454            args[0].to_string()
1455        } else {
1456            args.iter()
1457                .map(|v| v.to_string())
1458                .collect::<Vec<_>>()
1459                .join(" ")
1460        };
1461
1462        info!("📋 {}", message);
1463        Ok(message)
1464    }
1465
1466    /// Handle update/refresh functions
1467    fn handle_update_function(&self, args: &[Value]) -> Result<String> {
1468        if let Some(arg) = args.first() {
1469            Ok(format!("Updated: {}", arg.to_string()))
1470        } else {
1471            Ok("Updated".to_string())
1472        }
1473    }
1474
1475    /// Handle timestamp function
1476    fn handle_timestamp_function(&self) -> Result<String> {
1477        use std::time::{SystemTime, UNIX_EPOCH};
1478        let timestamp = SystemTime::now()
1479            .duration_since(UNIX_EPOCH)
1480            .map_err(|e| RuleEngineError::EvaluationError {
1481                message: format!("Failed to get timestamp: {}", e),
1482            })?
1483            .as_secs();
1484        Ok(timestamp.to_string())
1485    }
1486
1487    /// Handle random function
1488    fn handle_random_function(&self, args: &[Value]) -> Result<String> {
1489        use std::collections::hash_map::DefaultHasher;
1490        use std::hash::{Hash, Hasher};
1491
1492        // Simple pseudo-random based on current time (for deterministic behavior in tests)
1493        let mut hasher = DefaultHasher::new();
1494        std::time::SystemTime::now().hash(&mut hasher);
1495        let random_value = hasher.finish();
1496
1497        if args.is_empty() {
1498            Ok((random_value % 100).to_string()) // 0-99
1499        } else if let Some(Value::Number(max)) = args.first() {
1500            let max_val = *max as u64;
1501            Ok((random_value % max_val).to_string())
1502        } else {
1503            Ok(random_value.to_string())
1504        }
1505    }
1506
1507    /// Handle format function (simple sprintf-like)
1508    fn handle_format_function(&self, args: &[Value]) -> Result<String> {
1509        if args.is_empty() {
1510            return Ok("".to_string());
1511        }
1512
1513        let template = args[0].to_string();
1514        let values: Vec<String> = args[1..].iter().map(|v| v.to_string()).collect();
1515
1516        // Simple placeholder replacement: {0}, {1}, etc.
1517        let mut result = template;
1518        for (i, value) in values.iter().enumerate() {
1519            result = result.replace(&format!("{{{}}}", i), value);
1520        }
1521
1522        Ok(result)
1523    }
1524
1525    /// Handle length/size functions
1526    fn handle_length_function(&self, args: &[Value]) -> Result<String> {
1527        if let Some(arg) = args.first() {
1528            match arg {
1529                Value::String(s) => Ok(s.len().to_string()),
1530                Value::Array(arr) => Ok(arr.len().to_string()),
1531                Value::Object(obj) => Ok(obj.len().to_string()),
1532                _ => Ok("1".to_string()), // Single value has length 1
1533            }
1534        } else {
1535            Ok("0".to_string())
1536        }
1537    }
1538
1539    /// Handle sum function
1540    fn handle_sum_function(&self, args: &[Value]) -> Result<String> {
1541        let sum = args.iter().fold(0.0, |acc, val| match val {
1542            Value::Number(n) => acc + n,
1543            Value::Integer(i) => acc + (*i as f64),
1544            _ => acc,
1545        });
1546        Ok(sum.to_string())
1547    }
1548
1549    /// Handle max function
1550    fn handle_max_function(&self, args: &[Value]) -> Result<String> {
1551        let max = args.iter().fold(f64::NEG_INFINITY, |acc, val| match val {
1552            Value::Number(n) => acc.max(*n),
1553            Value::Integer(i) => acc.max(*i as f64),
1554            _ => acc,
1555        });
1556        Ok(max.to_string())
1557    }
1558
1559    /// Handle min function
1560    fn handle_min_function(&self, args: &[Value]) -> Result<String> {
1561        let min = args.iter().fold(f64::INFINITY, |acc, val| match val {
1562            Value::Number(n) => acc.min(*n),
1563            Value::Integer(i) => acc.min(*i as f64),
1564            _ => acc,
1565        });
1566        Ok(min.to_string())
1567    }
1568
1569    /// Handle average function
1570    fn handle_average_function(&self, args: &[Value]) -> Result<String> {
1571        if args.is_empty() {
1572            return Ok("0".to_string());
1573        }
1574
1575        let (sum, count) = args.iter().fold((0.0, 0), |(sum, count), val| match val {
1576            Value::Number(n) => (sum + n, count + 1),
1577            Value::Integer(i) => (sum + (*i as f64), count + 1),
1578            _ => (sum, count),
1579        });
1580
1581        if count > 0 {
1582            Ok((sum / count as f64).to_string())
1583        } else {
1584            Ok("0".to_string())
1585        }
1586    }
1587
1588    /// Handle mathematical functions
1589    fn handle_round_function(&self, args: &[Value]) -> Result<String> {
1590        if let Some(Value::Number(n)) = args.first() {
1591            Ok(n.round().to_string())
1592        } else if let Some(Value::Integer(i)) = args.first() {
1593            Ok(i.to_string())
1594        } else {
1595            Err(RuleEngineError::EvaluationError {
1596                message: "round() requires a numeric argument".to_string(),
1597            })
1598        }
1599    }
1600
1601    fn handle_floor_function(&self, args: &[Value]) -> Result<String> {
1602        if let Some(Value::Number(n)) = args.first() {
1603            Ok(n.floor().to_string())
1604        } else if let Some(Value::Integer(i)) = args.first() {
1605            Ok(i.to_string())
1606        } else {
1607            Err(RuleEngineError::EvaluationError {
1608                message: "floor() requires a numeric argument".to_string(),
1609            })
1610        }
1611    }
1612
1613    fn handle_ceil_function(&self, args: &[Value]) -> Result<String> {
1614        if let Some(Value::Number(n)) = args.first() {
1615            Ok(n.ceil().to_string())
1616        } else if let Some(Value::Integer(i)) = args.first() {
1617            Ok(i.to_string())
1618        } else {
1619            Err(RuleEngineError::EvaluationError {
1620                message: "ceil() requires a numeric argument".to_string(),
1621            })
1622        }
1623    }
1624
1625    fn handle_abs_function(&self, args: &[Value]) -> Result<String> {
1626        if let Some(Value::Number(n)) = args.first() {
1627            Ok(n.abs().to_string())
1628        } else if let Some(Value::Integer(i)) = args.first() {
1629            Ok(i.abs().to_string())
1630        } else {
1631            Err(RuleEngineError::EvaluationError {
1632                message: "abs() requires a numeric argument".to_string(),
1633            })
1634        }
1635    }
1636
1637    /// Handle string functions
1638    fn handle_contains_function(&self, args: &[Value]) -> Result<String> {
1639        if args.len() >= 2 {
1640            let haystack = args[0].to_string();
1641            let needle = args[1].to_string();
1642            Ok(haystack.contains(&needle).to_string())
1643        } else {
1644            Err(RuleEngineError::EvaluationError {
1645                message: "contains() requires 2 arguments".to_string(),
1646            })
1647        }
1648    }
1649
1650    fn handle_starts_with_function(&self, args: &[Value]) -> Result<String> {
1651        if args.len() >= 2 {
1652            let text = args[0].to_string();
1653            let prefix = args[1].to_string();
1654            Ok(text.starts_with(&prefix).to_string())
1655        } else {
1656            Err(RuleEngineError::EvaluationError {
1657                message: "startswith() requires 2 arguments".to_string(),
1658            })
1659        }
1660    }
1661
1662    fn handle_ends_with_function(&self, args: &[Value]) -> Result<String> {
1663        if args.len() >= 2 {
1664            let text = args[0].to_string();
1665            let suffix = args[1].to_string();
1666            Ok(text.ends_with(&suffix).to_string())
1667        } else {
1668            Err(RuleEngineError::EvaluationError {
1669                message: "endswith() requires 2 arguments".to_string(),
1670            })
1671        }
1672    }
1673
1674    fn handle_lowercase_function(&self, args: &[Value]) -> Result<String> {
1675        if let Some(arg) = args.first() {
1676            Ok(arg.to_string().to_lowercase())
1677        } else {
1678            Err(RuleEngineError::EvaluationError {
1679                message: "lowercase() requires 1 argument".to_string(),
1680            })
1681        }
1682    }
1683
1684    fn handle_uppercase_function(&self, args: &[Value]) -> Result<String> {
1685        if let Some(arg) = args.first() {
1686            Ok(arg.to_string().to_uppercase())
1687        } else {
1688            Err(RuleEngineError::EvaluationError {
1689                message: "uppercase() requires 1 argument".to_string(),
1690            })
1691        }
1692    }
1693
1694    fn handle_trim_function(&self, args: &[Value]) -> Result<String> {
1695        if let Some(arg) = args.first() {
1696            Ok(arg.to_string().trim().to_string())
1697        } else {
1698            Err(RuleEngineError::EvaluationError {
1699                message: "trim() requires 1 argument".to_string(),
1700            })
1701        }
1702    }
1703
1704    fn handle_split_function(&self, args: &[Value]) -> Result<String> {
1705        if args.len() >= 2 {
1706            let text = args[0].to_string();
1707            let delimiter = args[1].to_string();
1708            let parts: Vec<String> = text.split(&delimiter).map(|s| s.to_string()).collect();
1709            Ok(format!("{:?}", parts)) // Return as debug string for now
1710        } else {
1711            Err(RuleEngineError::EvaluationError {
1712                message: "split() requires 2 arguments".to_string(),
1713            })
1714        }
1715    }
1716
1717    fn handle_join_function(&self, args: &[Value]) -> Result<String> {
1718        if args.len() >= 2 {
1719            let delimiter = args[0].to_string();
1720            let parts: Vec<String> = args[1..].iter().map(|v| v.to_string()).collect();
1721            Ok(parts.join(&delimiter))
1722        } else {
1723            Err(RuleEngineError::EvaluationError {
1724                message: "join() requires at least 2 arguments".to_string(),
1725            })
1726        }
1727    }
1728
1729    /// Handle custom user-defined functions
1730    fn handle_custom_function(
1731        &self,
1732        function: &str,
1733        args: &[Value],
1734        facts: &Facts,
1735    ) -> Result<String> {
1736        // Check if we have a registered custom function
1737        if let Some(custom_func) = self.custom_functions.get(function) {
1738            if self.config.debug_mode {
1739                println!("🎯 Calling registered function: {}({:?})", function, args);
1740            }
1741
1742            match custom_func(args, facts) {
1743                Ok(result) => Ok(result.to_string()),
1744                Err(e) => Err(e),
1745            }
1746        } else {
1747            // Function not found - return error or placeholder
1748            if self.config.debug_mode {
1749                println!("⚠️ Custom function '{}' not registered", function);
1750            }
1751
1752            Err(RuleEngineError::EvaluationError {
1753                message: format!("Function '{}' is not registered. Use engine.register_function() to add custom functions.", function),
1754            })
1755        }
1756    }
1757
1758    /// Execute method call on object
1759    fn execute_method_call(
1760        &self,
1761        object_name: &str,
1762        method: &str,
1763        args: &[Value],
1764        facts: &Facts,
1765    ) -> Result<String> {
1766        // Get the object from facts
1767        let Some(object_value) = facts.get(object_name) else {
1768            return Err(RuleEngineError::EvaluationError {
1769                message: format!("Object '{}' not found in facts", object_name),
1770            });
1771        };
1772
1773        let method_lower = method.to_lowercase();
1774
1775        // Handle setter methods (set + property name)
1776        if method_lower.starts_with("set") && args.len() == 1 {
1777            return self.handle_setter_method(object_name, method, &args[0], object_value, facts);
1778        }
1779
1780        // Handle getter methods (get + property name)
1781        if method_lower.starts_with("get") && args.is_empty() {
1782            return self.handle_getter_method(object_name, method, &object_value);
1783        }
1784
1785        // Handle built-in methods
1786        match method_lower.as_str() {
1787            "tostring" => Ok(object_value.to_string()),
1788            "update" => {
1789                facts.add_value(object_name, object_value)?;
1790                Ok(format!("Updated {}", object_name))
1791            }
1792            "reset" => self.handle_reset_method(object_name, object_value, facts),
1793            _ => self.handle_property_access_or_fallback(
1794                object_name,
1795                method,
1796                args.len(),
1797                &object_value,
1798            ),
1799        }
1800    }
1801
1802    /// Handle setter method calls (setXxx)
1803    fn handle_setter_method(
1804        &self,
1805        object_name: &str,
1806        method: &str,
1807        new_value: &Value,
1808        mut object_value: Value,
1809        facts: &Facts,
1810    ) -> Result<String> {
1811        let property_name = Self::extract_property_name_from_setter(method);
1812
1813        match object_value {
1814            Value::Object(ref mut obj) => {
1815                obj.insert(property_name.clone(), new_value.clone());
1816                facts.add_value(object_name, object_value)?;
1817                Ok(format!(
1818                    "Set {} to {}",
1819                    property_name,
1820                    new_value.to_string()
1821                ))
1822            }
1823            _ => Err(RuleEngineError::EvaluationError {
1824                message: format!("Cannot call setter on non-object type: {}", object_name),
1825            }),
1826        }
1827    }
1828
1829    /// Handle getter method calls (getXxx)
1830    fn handle_getter_method(
1831        &self,
1832        object_name: &str,
1833        method: &str,
1834        object_value: &Value,
1835    ) -> Result<String> {
1836        let property_name = Self::extract_property_name_from_getter(method);
1837
1838        match object_value {
1839            Value::Object(obj) => {
1840                if let Some(value) = obj.get(&property_name) {
1841                    Ok(value.to_string())
1842                } else {
1843                    Err(RuleEngineError::EvaluationError {
1844                        message: format!(
1845                            "Property '{}' not found on object '{}'",
1846                            property_name, object_name
1847                        ),
1848                    })
1849                }
1850            }
1851            _ => Err(RuleEngineError::EvaluationError {
1852                message: format!("Cannot call getter on non-object type: {}", object_name),
1853            }),
1854        }
1855    }
1856
1857    /// Handle reset method call
1858    fn handle_reset_method(
1859        &self,
1860        object_name: &str,
1861        mut object_value: Value,
1862        facts: &Facts,
1863    ) -> Result<String> {
1864        match object_value {
1865            Value::Object(ref mut obj) => {
1866                obj.clear();
1867                facts.add_value(object_name, object_value)?;
1868                Ok(format!("Reset {}", object_name))
1869            }
1870            _ => Err(RuleEngineError::EvaluationError {
1871                message: format!("Cannot reset non-object type: {}", object_name),
1872            }),
1873        }
1874    }
1875
1876    /// Handle property access or fallback to generic method call
1877    fn handle_property_access_or_fallback(
1878        &self,
1879        object_name: &str,
1880        method: &str,
1881        arg_count: usize,
1882        object_value: &Value,
1883    ) -> Result<String> {
1884        if let Value::Object(obj) = object_value {
1885            // Try exact property name match
1886            if let Some(value) = obj.get(method) {
1887                return Ok(value.to_string());
1888            }
1889
1890            // Try capitalized property name
1891            let capitalized_method = Self::capitalize_first_letter(method);
1892            if let Some(value) = obj.get(&capitalized_method) {
1893                return Ok(value.to_string());
1894            }
1895        }
1896
1897        // Fallback to generic response
1898        Ok(format!(
1899            "Called {}.{} with {} args",
1900            object_name, method, arg_count
1901        ))
1902    }
1903
1904    /// Extract property name from setter method (setXxx -> Xxx)
1905    fn extract_property_name_from_setter(method: &str) -> String {
1906        let property_name = &method[3..]; // Remove "set" prefix
1907        Self::capitalize_first_letter(property_name)
1908    }
1909
1910    /// Extract property name from getter method (getXxx -> Xxx)
1911    fn extract_property_name_from_getter(method: &str) -> String {
1912        let property_name = &method[3..]; // Remove "get" prefix
1913        Self::capitalize_first_letter(property_name)
1914    }
1915
1916    /// Helper function to capitalize first letter of a string
1917    fn capitalize_first_letter(s: &str) -> String {
1918        if s.is_empty() {
1919            return String::new();
1920        }
1921        let mut chars = s.chars();
1922        match chars.next() {
1923            None => String::new(),
1924            Some(first) => first.to_uppercase().collect::<String>() + chars.as_str(),
1925        }
1926    }
1927
1928    /// Resolve action parameters by replacing fact references with actual values
1929    fn resolve_action_parameters(
1930        &self,
1931        params: &HashMap<String, Value>,
1932        facts: &Facts,
1933    ) -> Result<HashMap<String, Value>> {
1934        let mut resolved = HashMap::new();
1935
1936        for (key, value) in params {
1937            let resolved_value = match value {
1938                Value::String(s) => {
1939                    // Check if string looks like a fact reference (contains dot)
1940                    if s.contains('.') {
1941                        // Try to get the value from facts
1942                        if let Some(fact_value) = facts.get_nested(s) {
1943                            fact_value
1944                        } else {
1945                            // If not found, keep original string
1946                            value.clone()
1947                        }
1948                    } else {
1949                        value.clone()
1950                    }
1951                }
1952                _ => value.clone(),
1953            };
1954            resolved.insert(key.clone(), resolved_value);
1955        }
1956
1957        Ok(resolved)
1958    }
1959
1960    // 🔌 Plugin System Methods
1961
1962    /// Load a plugin into the engine
1963    pub fn load_plugin(
1964        &mut self,
1965        plugin: std::sync::Arc<dyn crate::engine::plugin::RulePlugin>,
1966    ) -> Result<()> {
1967        // First register the plugin actions with this engine
1968        plugin.register_actions(self)?;
1969        plugin.register_functions(self)?;
1970
1971        // Then store it in the plugin manager
1972        self.plugin_manager.load_plugin(plugin)
1973    }
1974
1975    /// Unload a plugin from the engine
1976    pub fn unload_plugin(&mut self, name: &str) -> Result<()> {
1977        self.plugin_manager.unload_plugin(name)
1978    }
1979
1980    /// Hot reload a plugin
1981    pub fn hot_reload_plugin(
1982        &mut self,
1983        name: &str,
1984        new_plugin: std::sync::Arc<dyn crate::engine::plugin::RulePlugin>,
1985    ) -> Result<()> {
1986        // Unload old plugin
1987        self.plugin_manager.unload_plugin(name)?;
1988
1989        // Register new plugin actions
1990        new_plugin.register_actions(self)?;
1991        new_plugin.register_functions(self)?;
1992
1993        // Load new plugin
1994        self.plugin_manager.load_plugin(new_plugin)
1995    }
1996
1997    /// Get plugin information
1998    pub fn get_plugin_info(&self, name: &str) -> Option<&crate::engine::plugin::PluginMetadata> {
1999        self.plugin_manager.get_plugin_info(name)
2000    }
2001
2002    /// List all loaded plugins
2003    pub fn list_plugins(&self) -> Vec<PluginInfo> {
2004        self.plugin_manager.list_plugins()
2005    }
2006
2007    /// Get plugin statistics
2008    pub fn get_plugin_stats(&self) -> PluginStats {
2009        self.plugin_manager.get_stats()
2010    }
2011
2012    /// Check health of all plugins
2013    pub fn plugin_health_check(&mut self) -> HashMap<String, crate::engine::plugin::PluginHealth> {
2014        self.plugin_manager.plugin_health_check()
2015    }
2016
2017    /// Configure plugin manager
2018    pub fn configure_plugins(&mut self, config: PluginConfig) {
2019        self.plugin_manager = PluginManager::new(config);
2020    }
2021}