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