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