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, &str),
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
142                    on_rule_fired(&rule.name, "facts"); // TODO: truyền id facts thực tế nếu có
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                let field_value = facts
951                    .get_nested(field_name)
952                    .or_else(|| facts.get(field_name));
953
954                if self.config.debug_mode {
955                    println!(
956                        "    🔎 Evaluating field condition: {} {} {:?}",
957                        field_name,
958                        format!("{:?}", condition.operator).to_lowercase(),
959                        condition.value
960                    );
961                    println!("      Field value: {:?}", field_value);
962                }
963
964                if let Some(value) = field_value {
965                    // condition.operator.evaluate(&value, &condition.value)
966                    // If the condition's right-hand value is a string that names another fact,
967                    // try to resolve that fact and use its value for comparison. This allows
968                    // rules like `L1 > L1Min` where the parser may have stored "L1Min"
969                    // as a string literal.
970                    let rhs = match &condition.value {
971                        crate::types::Value::String(s) => {
972                            // Try nested lookup first, then flat lookup
973                            facts
974                                .get_nested(s)
975                                .or_else(|| facts.get(s))
976                                .unwrap_or(crate::types::Value::String(s.clone()))
977                        }
978                        crate::types::Value::Expression(expr) => {
979                            // Try to evaluate expression - could be a variable reference or arithmetic
980                            match crate::expression::evaluate_expression(expr, facts) {
981                                Ok(evaluated) => evaluated,
982                                Err(_) => {
983                                    // If evaluation fails, try as simple variable lookup
984                                    facts
985                                        .get_nested(expr)
986                                        .or_else(|| facts.get(expr))
987                                        .unwrap_or(crate::types::Value::Expression(expr.clone()))
988                                }
989                            }
990                        }
991                        _ => condition.value.clone(),
992                    };
993
994                    if self.config.debug_mode {
995                        println!("      Resolved RHS for comparison: {:?}", rhs);
996                    }
997
998                    condition.operator.evaluate(&value, &rhs)
999                } else {
1000                    false
1001                }
1002            }
1003            ConditionExpression::FunctionCall { name, args } => {
1004                // Function call condition
1005                if self.config.debug_mode {
1006                    println!(
1007                        "    🔎 Evaluating function condition: {}({:?}) {} {:?}",
1008                        name,
1009                        args,
1010                        format!("{:?}", condition.operator).to_lowercase(),
1011                        condition.value
1012                    );
1013                }
1014
1015                if let Some(function) = self.custom_functions.get(name) {
1016                    // Resolve arguments from facts
1017                    let arg_values: Vec<Value> = args
1018                        .iter()
1019                        .map(|arg| {
1020                            facts
1021                                .get_nested(arg)
1022                                .or_else(|| facts.get(arg))
1023                                .unwrap_or(Value::String(arg.clone()))
1024                        })
1025                        .collect();
1026
1027                    // Call the function
1028                    match function(&arg_values, facts) {
1029                        Ok(result_value) => {
1030                            if self.config.debug_mode {
1031                                println!("      Function result: {:?}", result_value);
1032                            }
1033                            condition.operator.evaluate(&result_value, &condition.value)
1034                        }
1035                        Err(e) => {
1036                            if self.config.debug_mode {
1037                                println!("      Function error: {}", e);
1038                            }
1039                            false
1040                        }
1041                    }
1042                } else {
1043                    if self.config.debug_mode {
1044                        println!("      Function '{}' not found", name);
1045                    }
1046                    false
1047                }
1048            }
1049            ConditionExpression::Test { name, args } => {
1050                // Test CE condition - expects boolean result
1051                if self.config.debug_mode {
1052                    println!("    🧪 Evaluating test CE: test({}({:?}))", name, args);
1053                }
1054
1055                // Check if name is a registered custom function
1056                if let Some(function) = self.custom_functions.get(name) {
1057                    // Resolve arguments from facts
1058                    let arg_values: Vec<Value> = args
1059                        .iter()
1060                        .map(|arg| {
1061                            let resolved = facts
1062                                .get_nested(arg)
1063                                .or_else(|| facts.get(arg))
1064                                .unwrap_or(Value::String(arg.clone()));
1065                            if self.config.debug_mode {
1066                                println!("      Resolving arg '{}' -> {:?}", arg, resolved);
1067                            }
1068                            resolved
1069                        })
1070                        .collect();
1071
1072                    // Call the function
1073                    match function(&arg_values, facts) {
1074                        Ok(result_value) => {
1075                            if self.config.debug_mode {
1076                                println!("      Test result: {:?}", result_value);
1077                            }
1078                            // Test CE expects boolean result directly
1079                            match result_value {
1080                                Value::Boolean(b) => b,
1081                                Value::Integer(i) => i != 0,
1082                                Value::Number(f) => f != 0.0,
1083                                Value::String(s) => !s.is_empty(),
1084                                _ => false,
1085                            }
1086                        }
1087                        Err(e) => {
1088                            if self.config.debug_mode {
1089                                println!("      Test function error: {}", e);
1090                            }
1091                            false
1092                        }
1093                    }
1094                } else {
1095                    // Not a custom function - try to evaluate as arithmetic expression
1096                    // Format: "User.Age % 3 == 0" where name is the full expression
1097                    if self.config.debug_mode {
1098                        println!("      Trying to evaluate '{}' as arithmetic expression", name);
1099                    }
1100                    
1101                    // Try to parse and evaluate the expression
1102                    match self.evaluate_arithmetic_condition(name, facts) {
1103                        Ok(result) => {
1104                            if self.config.debug_mode {
1105                                println!("      Arithmetic expression result: {}", result);
1106                            }
1107                            result
1108                        }
1109                        Err(e) => {
1110                            if self.config.debug_mode {
1111                                println!("      Failed to evaluate expression: {}", e);
1112                                println!("      Test function '{}' not found", name);
1113                            }
1114                            false
1115                        }
1116                    }
1117                }
1118            }
1119            ConditionExpression::MultiField { field, operation, variable: _ } => {
1120                // Multi-field operation condition
1121                if self.config.debug_mode {
1122                    println!("    📦 Evaluating multi-field: {}.{}", field, operation);
1123                }
1124
1125                // Get the field value
1126                let field_value = facts.get_nested(field).or_else(|| facts.get(field));
1127
1128                if let Some(value) = field_value {
1129                    match operation.as_str() {
1130                        "empty" => {
1131                            matches!(value, Value::Array(arr) if arr.is_empty())
1132                        }
1133                        "not_empty" => {
1134                            matches!(value, Value::Array(arr) if !arr.is_empty())
1135                        }
1136                        "count" => {
1137                            if let Value::Array(arr) = value {
1138                                let count = Value::Integer(arr.len() as i64);
1139                                condition.operator.evaluate(&count, &condition.value)
1140                            } else {
1141                                false
1142                            }
1143                        }
1144                        "contains" => {
1145                            // Use existing contains operator
1146                            condition.operator.evaluate(&value, &condition.value)
1147                        }
1148                        _ => {
1149                            // Other operations (collect, first, last) not fully supported yet
1150                            // Return true to not block rule evaluation
1151                            if self.config.debug_mode {
1152                                println!("      ⚠️ Operation '{}' not fully implemented yet", operation);
1153                            }
1154                            true
1155                        }
1156                    }
1157                } else {
1158                    false
1159                }
1160            }
1161        };
1162
1163        if self.config.debug_mode {
1164            println!("      Result: {}", result);
1165        }
1166
1167        Ok(result)
1168    }
1169
1170    /// Execute an action
1171    fn execute_action(&mut self, action: &ActionType, facts: &Facts) -> Result<()> {
1172        match action {
1173            ActionType::Set { field, value } => {
1174                // Evaluate expression if value is an Expression
1175                let evaluated_value = match value {
1176                    Value::Expression(expr) => {
1177                        // Evaluate the expression with current facts
1178                        crate::expression::evaluate_expression(expr, facts)?
1179                    }
1180                    _ => value.clone(),
1181                };
1182
1183                // Try nested first, then fall back to flat key setting
1184                if let Err(_) = facts.set_nested(field, evaluated_value.clone()) {
1185                    // If nested fails, use flat key
1186                    facts.set(field, evaluated_value.clone());
1187                }
1188                if self.config.debug_mode {
1189                    println!("  ✅ Set {field} = {evaluated_value:?}");
1190                }
1191            }
1192            ActionType::Log { message } => {
1193                println!("📋 LOG: {}", message);
1194            }
1195            ActionType::MethodCall {
1196                object,
1197                method,
1198                args,
1199            } => {
1200                let result = self.execute_method_call(object, method, args, facts)?;
1201                if self.config.debug_mode {
1202                    println!("  🔧 Called {object}.{method}({args:?}) -> {result}");
1203                }
1204            }
1205            ActionType::Retract { object } => {
1206                if self.config.debug_mode {
1207                    println!("  🗑️ Retracted {object}");
1208                }
1209                // Mark fact as retracted in working memory
1210                facts.set(&format!("_retracted_{}", object), Value::Boolean(true));
1211            }
1212            ActionType::Custom {
1213                action_type,
1214                params,
1215            } => {
1216                if let Some(handler) = self.action_handlers.get(action_type) {
1217                    if self.config.debug_mode {
1218                        println!(
1219                            "  🎯 Executing custom action: {action_type} with params: {params:?}"
1220                        );
1221                    }
1222
1223                    // Resolve parameter values from facts
1224                    let resolved_params = self.resolve_action_parameters(params, facts)?;
1225
1226                    // Execute the registered handler
1227                    handler(&resolved_params, facts)?;
1228                } else {
1229                    if self.config.debug_mode {
1230                        println!("  ⚠️ No handler registered for custom action: {action_type}");
1231                        println!(
1232                            "     Available handlers: {:?}",
1233                            self.action_handlers.keys().collect::<Vec<_>>()
1234                        );
1235                    }
1236
1237                    // Return error if no handler found
1238                    return Err(RuleEngineError::EvaluationError {
1239                        message: format!(
1240                            "No action handler registered for '{action_type}'. Use engine.register_action_handler() to add custom action handlers."
1241                        ),
1242                    });
1243                }
1244            }
1245            // 🔄 Workflow Actions
1246            ActionType::ActivateAgendaGroup { group } => {
1247                if self.config.debug_mode {
1248                    println!("  🎯 Activating agenda group: {}", group);
1249                }
1250                // Sync with both workflow engine and agenda manager immediately
1251                self.workflow_engine.activate_agenda_group(group.clone());
1252                self.agenda_manager.set_focus(group);
1253            }
1254            ActionType::ScheduleRule {
1255                rule_name,
1256                delay_ms,
1257            } => {
1258                if self.config.debug_mode {
1259                    println!(
1260                        "  ⏰ Scheduling rule '{}' to execute in {}ms",
1261                        rule_name, delay_ms
1262                    );
1263                }
1264                self.workflow_engine
1265                    .schedule_rule(rule_name.clone(), *delay_ms, None);
1266            }
1267            ActionType::CompleteWorkflow { workflow_name } => {
1268                if self.config.debug_mode {
1269                    println!("  ✅ Completing workflow: {}", workflow_name);
1270                }
1271                self.workflow_engine
1272                    .complete_workflow(workflow_name.clone());
1273            }
1274            ActionType::SetWorkflowData { key, value } => {
1275                if self.config.debug_mode {
1276                    println!("  💾 Setting workflow data: {} = {:?}", key, value);
1277                }
1278                // For now, we'll use a default workflow ID. Later this could be enhanced
1279                // to track current workflow context
1280                let workflow_id = "default_workflow";
1281                self.workflow_engine
1282                    .set_workflow_data(workflow_id, key.clone(), value.clone());
1283            }
1284        }
1285        Ok(())
1286    }
1287
1288    /// Evaluate arithmetic condition like "User.Age % 3 == 0"
1289    fn evaluate_arithmetic_condition(&self, expr: &str, facts: &Facts) -> Result<bool> {
1290        // Parse expression format: "left_expr operator right_value"
1291        // e.g., "User.Age % 3 == 0" or "User.Price * 2 > 100"
1292        
1293        let operators = [">=", "<=", "==", "!=", ">", "<"];
1294        let mut split_pos = None;
1295        let mut found_op = "";
1296        
1297        for op in &operators {
1298            if let Some(pos) = expr.rfind(op) {
1299                split_pos = Some(pos);
1300                found_op = op;
1301                break;
1302            }
1303        }
1304        
1305        if split_pos.is_none() {
1306            return Err(RuleEngineError::EvaluationError {
1307                message: format!("No comparison operator found in expression: {}", expr),
1308            });
1309        }
1310        
1311        let pos = split_pos.unwrap();
1312        let left_expr = expr[..pos].trim();
1313        let right_value = expr[pos + found_op.len()..].trim();
1314        
1315        // Evaluate left side arithmetic expression
1316        let left_result = crate::expression::evaluate_expression(left_expr, facts)?;
1317        
1318        // Parse right value
1319        let right_val = if let Ok(i) = right_value.parse::<i64>() {
1320            Value::Integer(i)
1321        } else if let Ok(f) = right_value.parse::<f64>() {
1322            Value::Number(f)
1323        } else {
1324            // Try to evaluate as expression or get from facts
1325            match crate::expression::evaluate_expression(right_value, facts) {
1326                Ok(v) => v,
1327                Err(_) => Value::String(right_value.to_string()),
1328            }
1329        };
1330        
1331        // Compare values
1332        let operator = Operator::from_str(found_op).ok_or_else(|| {
1333            RuleEngineError::InvalidOperator {
1334                operator: found_op.to_string(),
1335            }
1336        })?;
1337        
1338        Ok(operator.evaluate(&left_result, &right_val))
1339    }
1340
1341    /// Execute function call
1342    fn execute_function_call(
1343        &self,
1344        function: &str,
1345        args: &[Value],
1346        facts: &Facts,
1347    ) -> Result<String> {
1348        let function_lower = function.to_lowercase();
1349
1350        // Handle built-in utility functions
1351        match function_lower.as_str() {
1352            "log" | "print" | "println" => self.handle_log_function(args),
1353            "update" | "refresh" => self.handle_update_function(args),
1354            "now" | "timestamp" => self.handle_timestamp_function(),
1355            "random" => self.handle_random_function(args),
1356            "format" | "sprintf" => self.handle_format_function(args),
1357            "length" | "size" | "count" => self.handle_length_function(args),
1358            "sum" | "add" => self.handle_sum_function(args),
1359            "max" | "maximum" => self.handle_max_function(args),
1360            "min" | "minimum" => self.handle_min_function(args),
1361            "avg" | "average" => self.handle_average_function(args),
1362            "round" => self.handle_round_function(args),
1363            "floor" => self.handle_floor_function(args),
1364            "ceil" | "ceiling" => self.handle_ceil_function(args),
1365            "abs" | "absolute" => self.handle_abs_function(args),
1366            "contains" | "includes" => self.handle_contains_function(args),
1367            "startswith" | "begins_with" => self.handle_starts_with_function(args),
1368            "endswith" | "ends_with" => self.handle_ends_with_function(args),
1369            "lowercase" | "tolower" => self.handle_lowercase_function(args),
1370            "uppercase" | "toupper" => self.handle_uppercase_function(args),
1371            "trim" | "strip" => self.handle_trim_function(args),
1372            "split" => self.handle_split_function(args),
1373            "join" => self.handle_join_function(args),
1374            _ => {
1375                // Try to call custom user-defined function
1376                self.handle_custom_function(function, args, facts)
1377            }
1378        }
1379    }
1380
1381    /// Handle logging functions (log, print, println)
1382    fn handle_log_function(&self, args: &[Value]) -> Result<String> {
1383        let message = if args.is_empty() {
1384            "".to_string()
1385        } else if args.len() == 1 {
1386            args[0].to_string()
1387        } else {
1388            args.iter()
1389                .map(|v| v.to_string())
1390                .collect::<Vec<_>>()
1391                .join(" ")
1392        };
1393
1394        println!("📋 {}", message);
1395        Ok(message)
1396    }
1397
1398    /// Handle update/refresh functions
1399    fn handle_update_function(&self, args: &[Value]) -> Result<String> {
1400        if let Some(arg) = args.first() {
1401            Ok(format!("Updated: {}", arg.to_string()))
1402        } else {
1403            Ok("Updated".to_string())
1404        }
1405    }
1406
1407    /// Handle timestamp function
1408    fn handle_timestamp_function(&self) -> Result<String> {
1409        use std::time::{SystemTime, UNIX_EPOCH};
1410        let timestamp = SystemTime::now()
1411            .duration_since(UNIX_EPOCH)
1412            .map_err(|e| RuleEngineError::EvaluationError {
1413                message: format!("Failed to get timestamp: {}", e),
1414            })?
1415            .as_secs();
1416        Ok(timestamp.to_string())
1417    }
1418
1419    /// Handle random function
1420    fn handle_random_function(&self, args: &[Value]) -> Result<String> {
1421        use std::collections::hash_map::DefaultHasher;
1422        use std::hash::{Hash, Hasher};
1423
1424        // Simple pseudo-random based on current time (for deterministic behavior in tests)
1425        let mut hasher = DefaultHasher::new();
1426        std::time::SystemTime::now().hash(&mut hasher);
1427        let random_value = hasher.finish();
1428
1429        if args.is_empty() {
1430            Ok((random_value % 100).to_string()) // 0-99
1431        } else if let Some(Value::Number(max)) = args.first() {
1432            let max_val = *max as u64;
1433            Ok((random_value % max_val).to_string())
1434        } else {
1435            Ok(random_value.to_string())
1436        }
1437    }
1438
1439    /// Handle format function (simple sprintf-like)
1440    fn handle_format_function(&self, args: &[Value]) -> Result<String> {
1441        if args.is_empty() {
1442            return Ok("".to_string());
1443        }
1444
1445        let template = args[0].to_string();
1446        let values: Vec<String> = args[1..].iter().map(|v| v.to_string()).collect();
1447
1448        // Simple placeholder replacement: {0}, {1}, etc.
1449        let mut result = template;
1450        for (i, value) in values.iter().enumerate() {
1451            result = result.replace(&format!("{{{}}}", i), value);
1452        }
1453
1454        Ok(result)
1455    }
1456
1457    /// Handle length/size functions
1458    fn handle_length_function(&self, args: &[Value]) -> Result<String> {
1459        if let Some(arg) = args.first() {
1460            match arg {
1461                Value::String(s) => Ok(s.len().to_string()),
1462                Value::Array(arr) => Ok(arr.len().to_string()),
1463                Value::Object(obj) => Ok(obj.len().to_string()),
1464                _ => Ok("1".to_string()), // Single value has length 1
1465            }
1466        } else {
1467            Ok("0".to_string())
1468        }
1469    }
1470
1471    /// Handle sum function
1472    fn handle_sum_function(&self, args: &[Value]) -> Result<String> {
1473        let sum = args.iter().fold(0.0, |acc, val| match val {
1474            Value::Number(n) => acc + n,
1475            Value::Integer(i) => acc + (*i as f64),
1476            _ => acc,
1477        });
1478        Ok(sum.to_string())
1479    }
1480
1481    /// Handle max function
1482    fn handle_max_function(&self, args: &[Value]) -> Result<String> {
1483        let max = args.iter().fold(f64::NEG_INFINITY, |acc, val| match val {
1484            Value::Number(n) => acc.max(*n),
1485            Value::Integer(i) => acc.max(*i as f64),
1486            _ => acc,
1487        });
1488        Ok(max.to_string())
1489    }
1490
1491    /// Handle min function
1492    fn handle_min_function(&self, args: &[Value]) -> Result<String> {
1493        let min = args.iter().fold(f64::INFINITY, |acc, val| match val {
1494            Value::Number(n) => acc.min(*n),
1495            Value::Integer(i) => acc.min(*i as f64),
1496            _ => acc,
1497        });
1498        Ok(min.to_string())
1499    }
1500
1501    /// Handle average function
1502    fn handle_average_function(&self, args: &[Value]) -> Result<String> {
1503        if args.is_empty() {
1504            return Ok("0".to_string());
1505        }
1506
1507        let (sum, count) = args.iter().fold((0.0, 0), |(sum, count), val| match val {
1508            Value::Number(n) => (sum + n, count + 1),
1509            Value::Integer(i) => (sum + (*i as f64), count + 1),
1510            _ => (sum, count),
1511        });
1512
1513        if count > 0 {
1514            Ok((sum / count as f64).to_string())
1515        } else {
1516            Ok("0".to_string())
1517        }
1518    }
1519
1520    /// Handle mathematical functions
1521    fn handle_round_function(&self, args: &[Value]) -> Result<String> {
1522        if let Some(Value::Number(n)) = args.first() {
1523            Ok(n.round().to_string())
1524        } else if let Some(Value::Integer(i)) = args.first() {
1525            Ok(i.to_string())
1526        } else {
1527            Err(RuleEngineError::EvaluationError {
1528                message: "round() requires a numeric argument".to_string(),
1529            })
1530        }
1531    }
1532
1533    fn handle_floor_function(&self, args: &[Value]) -> Result<String> {
1534        if let Some(Value::Number(n)) = args.first() {
1535            Ok(n.floor().to_string())
1536        } else if let Some(Value::Integer(i)) = args.first() {
1537            Ok(i.to_string())
1538        } else {
1539            Err(RuleEngineError::EvaluationError {
1540                message: "floor() requires a numeric argument".to_string(),
1541            })
1542        }
1543    }
1544
1545    fn handle_ceil_function(&self, args: &[Value]) -> Result<String> {
1546        if let Some(Value::Number(n)) = args.first() {
1547            Ok(n.ceil().to_string())
1548        } else if let Some(Value::Integer(i)) = args.first() {
1549            Ok(i.to_string())
1550        } else {
1551            Err(RuleEngineError::EvaluationError {
1552                message: "ceil() requires a numeric argument".to_string(),
1553            })
1554        }
1555    }
1556
1557    fn handle_abs_function(&self, args: &[Value]) -> Result<String> {
1558        if let Some(Value::Number(n)) = args.first() {
1559            Ok(n.abs().to_string())
1560        } else if let Some(Value::Integer(i)) = args.first() {
1561            Ok(i.abs().to_string())
1562        } else {
1563            Err(RuleEngineError::EvaluationError {
1564                message: "abs() requires a numeric argument".to_string(),
1565            })
1566        }
1567    }
1568
1569    /// Handle string functions
1570    fn handle_contains_function(&self, args: &[Value]) -> Result<String> {
1571        if args.len() >= 2 {
1572            let haystack = args[0].to_string();
1573            let needle = args[1].to_string();
1574            Ok(haystack.contains(&needle).to_string())
1575        } else {
1576            Err(RuleEngineError::EvaluationError {
1577                message: "contains() requires 2 arguments".to_string(),
1578            })
1579        }
1580    }
1581
1582    fn handle_starts_with_function(&self, args: &[Value]) -> Result<String> {
1583        if args.len() >= 2 {
1584            let text = args[0].to_string();
1585            let prefix = args[1].to_string();
1586            Ok(text.starts_with(&prefix).to_string())
1587        } else {
1588            Err(RuleEngineError::EvaluationError {
1589                message: "startswith() requires 2 arguments".to_string(),
1590            })
1591        }
1592    }
1593
1594    fn handle_ends_with_function(&self, args: &[Value]) -> Result<String> {
1595        if args.len() >= 2 {
1596            let text = args[0].to_string();
1597            let suffix = args[1].to_string();
1598            Ok(text.ends_with(&suffix).to_string())
1599        } else {
1600            Err(RuleEngineError::EvaluationError {
1601                message: "endswith() requires 2 arguments".to_string(),
1602            })
1603        }
1604    }
1605
1606    fn handle_lowercase_function(&self, args: &[Value]) -> Result<String> {
1607        if let Some(arg) = args.first() {
1608            Ok(arg.to_string().to_lowercase())
1609        } else {
1610            Err(RuleEngineError::EvaluationError {
1611                message: "lowercase() requires 1 argument".to_string(),
1612            })
1613        }
1614    }
1615
1616    fn handle_uppercase_function(&self, args: &[Value]) -> Result<String> {
1617        if let Some(arg) = args.first() {
1618            Ok(arg.to_string().to_uppercase())
1619        } else {
1620            Err(RuleEngineError::EvaluationError {
1621                message: "uppercase() requires 1 argument".to_string(),
1622            })
1623        }
1624    }
1625
1626    fn handle_trim_function(&self, args: &[Value]) -> Result<String> {
1627        if let Some(arg) = args.first() {
1628            Ok(arg.to_string().trim().to_string())
1629        } else {
1630            Err(RuleEngineError::EvaluationError {
1631                message: "trim() requires 1 argument".to_string(),
1632            })
1633        }
1634    }
1635
1636    fn handle_split_function(&self, args: &[Value]) -> Result<String> {
1637        if args.len() >= 2 {
1638            let text = args[0].to_string();
1639            let delimiter = args[1].to_string();
1640            let parts: Vec<String> = text.split(&delimiter).map(|s| s.to_string()).collect();
1641            Ok(format!("{:?}", parts)) // Return as debug string for now
1642        } else {
1643            Err(RuleEngineError::EvaluationError {
1644                message: "split() requires 2 arguments".to_string(),
1645            })
1646        }
1647    }
1648
1649    fn handle_join_function(&self, args: &[Value]) -> Result<String> {
1650        if args.len() >= 2 {
1651            let delimiter = args[0].to_string();
1652            let parts: Vec<String> = args[1..].iter().map(|v| v.to_string()).collect();
1653            Ok(parts.join(&delimiter))
1654        } else {
1655            Err(RuleEngineError::EvaluationError {
1656                message: "join() requires at least 2 arguments".to_string(),
1657            })
1658        }
1659    }
1660
1661    /// Handle custom user-defined functions
1662    fn handle_custom_function(
1663        &self,
1664        function: &str,
1665        args: &[Value],
1666        facts: &Facts,
1667    ) -> Result<String> {
1668        // Check if we have a registered custom function
1669        if let Some(custom_func) = self.custom_functions.get(function) {
1670            if self.config.debug_mode {
1671                println!("🎯 Calling registered function: {}({:?})", function, args);
1672            }
1673
1674            match custom_func(args, facts) {
1675                Ok(result) => Ok(result.to_string()),
1676                Err(e) => Err(e),
1677            }
1678        } else {
1679            // Function not found - return error or placeholder
1680            if self.config.debug_mode {
1681                println!("⚠️ Custom function '{}' not registered", function);
1682            }
1683
1684            Err(RuleEngineError::EvaluationError {
1685                message: format!("Function '{}' is not registered. Use engine.register_function() to add custom functions.", function),
1686            })
1687        }
1688    }
1689
1690    /// Execute method call on object
1691    fn execute_method_call(
1692        &self,
1693        object_name: &str,
1694        method: &str,
1695        args: &[Value],
1696        facts: &Facts,
1697    ) -> Result<String> {
1698        // Get the object from facts
1699        let Some(object_value) = facts.get(object_name) else {
1700            return Err(RuleEngineError::EvaluationError {
1701                message: format!("Object '{}' not found in facts", object_name),
1702            });
1703        };
1704
1705        let method_lower = method.to_lowercase();
1706
1707        // Handle setter methods (set + property name)
1708        if method_lower.starts_with("set") && args.len() == 1 {
1709            return self.handle_setter_method(object_name, method, &args[0], object_value, facts);
1710        }
1711
1712        // Handle getter methods (get + property name)
1713        if method_lower.starts_with("get") && args.is_empty() {
1714            return self.handle_getter_method(object_name, method, &object_value);
1715        }
1716
1717        // Handle built-in methods
1718        match method_lower.as_str() {
1719            "tostring" => Ok(object_value.to_string()),
1720            "update" => {
1721                facts.add_value(object_name, object_value)?;
1722                Ok(format!("Updated {}", object_name))
1723            }
1724            "reset" => self.handle_reset_method(object_name, object_value, facts),
1725            _ => self.handle_property_access_or_fallback(
1726                object_name,
1727                method,
1728                args.len(),
1729                &object_value,
1730            ),
1731        }
1732    }
1733
1734    /// Handle setter method calls (setXxx)
1735    fn handle_setter_method(
1736        &self,
1737        object_name: &str,
1738        method: &str,
1739        new_value: &Value,
1740        mut object_value: Value,
1741        facts: &Facts,
1742    ) -> Result<String> {
1743        let property_name = Self::extract_property_name_from_setter(method);
1744
1745        match object_value {
1746            Value::Object(ref mut obj) => {
1747                obj.insert(property_name.clone(), new_value.clone());
1748                facts.add_value(object_name, object_value)?;
1749                Ok(format!(
1750                    "Set {} to {}",
1751                    property_name,
1752                    new_value.to_string()
1753                ))
1754            }
1755            _ => Err(RuleEngineError::EvaluationError {
1756                message: format!("Cannot call setter on non-object type: {}", object_name),
1757            }),
1758        }
1759    }
1760
1761    /// Handle getter method calls (getXxx)
1762    fn handle_getter_method(
1763        &self,
1764        object_name: &str,
1765        method: &str,
1766        object_value: &Value,
1767    ) -> Result<String> {
1768        let property_name = Self::extract_property_name_from_getter(method);
1769
1770        match object_value {
1771            Value::Object(obj) => {
1772                if let Some(value) = obj.get(&property_name) {
1773                    Ok(value.to_string())
1774                } else {
1775                    Err(RuleEngineError::EvaluationError {
1776                        message: format!(
1777                            "Property '{}' not found on object '{}'",
1778                            property_name, object_name
1779                        ),
1780                    })
1781                }
1782            }
1783            _ => Err(RuleEngineError::EvaluationError {
1784                message: format!("Cannot call getter on non-object type: {}", object_name),
1785            }),
1786        }
1787    }
1788
1789    /// Handle reset method call
1790    fn handle_reset_method(
1791        &self,
1792        object_name: &str,
1793        mut object_value: Value,
1794        facts: &Facts,
1795    ) -> Result<String> {
1796        match object_value {
1797            Value::Object(ref mut obj) => {
1798                obj.clear();
1799                facts.add_value(object_name, object_value)?;
1800                Ok(format!("Reset {}", object_name))
1801            }
1802            _ => Err(RuleEngineError::EvaluationError {
1803                message: format!("Cannot reset non-object type: {}", object_name),
1804            }),
1805        }
1806    }
1807
1808    /// Handle property access or fallback to generic method call
1809    fn handle_property_access_or_fallback(
1810        &self,
1811        object_name: &str,
1812        method: &str,
1813        arg_count: usize,
1814        object_value: &Value,
1815    ) -> Result<String> {
1816        if let Value::Object(obj) = object_value {
1817            // Try exact property name match
1818            if let Some(value) = obj.get(method) {
1819                return Ok(value.to_string());
1820            }
1821
1822            // Try capitalized property name
1823            let capitalized_method = Self::capitalize_first_letter(method);
1824            if let Some(value) = obj.get(&capitalized_method) {
1825                return Ok(value.to_string());
1826            }
1827        }
1828
1829        // Fallback to generic response
1830        Ok(format!(
1831            "Called {}.{} with {} args",
1832            object_name, method, arg_count
1833        ))
1834    }
1835
1836    /// Extract property name from setter method (setXxx -> Xxx)
1837    fn extract_property_name_from_setter(method: &str) -> String {
1838        let property_name = &method[3..]; // Remove "set" prefix
1839        Self::capitalize_first_letter(property_name)
1840    }
1841
1842    /// Extract property name from getter method (getXxx -> Xxx)
1843    fn extract_property_name_from_getter(method: &str) -> String {
1844        let property_name = &method[3..]; // Remove "get" prefix
1845        Self::capitalize_first_letter(property_name)
1846    }
1847
1848    /// Helper function to capitalize first letter of a string
1849    fn capitalize_first_letter(s: &str) -> String {
1850        if s.is_empty() {
1851            return String::new();
1852        }
1853        let mut chars = s.chars();
1854        match chars.next() {
1855            None => String::new(),
1856            Some(first) => first.to_uppercase().collect::<String>() + chars.as_str(),
1857        }
1858    }
1859
1860    /// Resolve action parameters by replacing fact references with actual values
1861    fn resolve_action_parameters(
1862        &self,
1863        params: &HashMap<String, Value>,
1864        facts: &Facts,
1865    ) -> Result<HashMap<String, Value>> {
1866        let mut resolved = HashMap::new();
1867
1868        for (key, value) in params {
1869            let resolved_value = match value {
1870                Value::String(s) => {
1871                    // Check if string looks like a fact reference (contains dot)
1872                    if s.contains('.') {
1873                        // Try to get the value from facts
1874                        if let Some(fact_value) = facts.get_nested(s) {
1875                            fact_value
1876                        } else {
1877                            // If not found, keep original string
1878                            value.clone()
1879                        }
1880                    } else {
1881                        value.clone()
1882                    }
1883                }
1884                _ => value.clone(),
1885            };
1886            resolved.insert(key.clone(), resolved_value);
1887        }
1888
1889        Ok(resolved)
1890    }
1891
1892    // 🔌 Plugin System Methods
1893
1894    /// Load a plugin into the engine
1895    pub fn load_plugin(
1896        &mut self,
1897        plugin: std::sync::Arc<dyn crate::engine::plugin::RulePlugin>,
1898    ) -> Result<()> {
1899        // First register the plugin actions with this engine
1900        plugin.register_actions(self)?;
1901        plugin.register_functions(self)?;
1902
1903        // Then store it in the plugin manager
1904        self.plugin_manager.load_plugin(plugin)
1905    }
1906
1907    /// Unload a plugin from the engine
1908    pub fn unload_plugin(&mut self, name: &str) -> Result<()> {
1909        self.plugin_manager.unload_plugin(name)
1910    }
1911
1912    /// Hot reload a plugin
1913    pub fn hot_reload_plugin(
1914        &mut self,
1915        name: &str,
1916        new_plugin: std::sync::Arc<dyn crate::engine::plugin::RulePlugin>,
1917    ) -> Result<()> {
1918        // Unload old plugin
1919        self.plugin_manager.unload_plugin(name)?;
1920
1921        // Register new plugin actions
1922        new_plugin.register_actions(self)?;
1923        new_plugin.register_functions(self)?;
1924
1925        // Load new plugin
1926        self.plugin_manager.load_plugin(new_plugin)
1927    }
1928
1929    /// Get plugin information
1930    pub fn get_plugin_info(&self, name: &str) -> Option<&crate::engine::plugin::PluginMetadata> {
1931        self.plugin_manager.get_plugin_info(name)
1932    }
1933
1934    /// List all loaded plugins
1935    pub fn list_plugins(&self) -> Vec<PluginInfo> {
1936        self.plugin_manager.list_plugins()
1937    }
1938
1939    /// Get plugin statistics
1940    pub fn get_plugin_stats(&self) -> PluginStats {
1941        self.plugin_manager.get_stats()
1942    }
1943
1944    /// Check health of all plugins
1945    pub fn plugin_health_check(&mut self) -> HashMap<String, crate::engine::plugin::PluginHealth> {
1946        self.plugin_manager.plugin_health_check()
1947    }
1948
1949    /// Configure plugin manager
1950    pub fn configure_plugins(&mut self, config: PluginConfig) {
1951        self.plugin_manager = PluginManager::new(config);
1952    }
1953}