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