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        }
649    }
650
651    /// Evaluate rule conditions - wrapper for evaluate_conditions for compatibility
652    fn evaluate_rule_conditions(
653        &self,
654        rule: &crate::engine::rule::Rule,
655        facts: &Facts,
656    ) -> Result<bool> {
657        self.evaluate_conditions(&rule.conditions, facts)
658    }
659
660    /// Evaluate a single condition
661    fn evaluate_single_condition(
662        &self,
663        condition: &crate::engine::rule::Condition,
664        facts: &Facts,
665    ) -> Result<bool> {
666        use crate::engine::rule::ConditionExpression;
667
668        let result = match &condition.expression {
669            ConditionExpression::Field(field_name) => {
670                // Field condition - try nested first, then flat lookup
671                let field_value = facts
672                    .get_nested(field_name)
673                    .or_else(|| facts.get(field_name));
674
675                if self.config.debug_mode {
676                    println!(
677                        "    🔎 Evaluating field condition: {} {} {:?}",
678                        field_name,
679                        format!("{:?}", condition.operator).to_lowercase(),
680                        condition.value
681                    );
682                    println!("      Field value: {:?}", field_value);
683                }
684
685                if let Some(value) = field_value {
686                    condition.operator.evaluate(&value, &condition.value)
687                } else {
688                    false
689                }
690            }
691            ConditionExpression::FunctionCall { name, args } => {
692                // Function call condition
693                if self.config.debug_mode {
694                    println!(
695                        "    🔎 Evaluating function condition: {}({:?}) {} {:?}",
696                        name,
697                        args,
698                        format!("{:?}", condition.operator).to_lowercase(),
699                        condition.value
700                    );
701                }
702
703                if let Some(function) = self.custom_functions.get(name) {
704                    // Resolve arguments from facts
705                    let arg_values: Vec<Value> = args
706                        .iter()
707                        .map(|arg| {
708                            facts
709                                .get_nested(arg)
710                                .or_else(|| facts.get(arg))
711                                .unwrap_or(Value::String(arg.clone()))
712                        })
713                        .collect();
714
715                    // Call the function
716                    match function(&arg_values, facts) {
717                        Ok(result_value) => {
718                            if self.config.debug_mode {
719                                println!("      Function result: {:?}", result_value);
720                            }
721                            condition.operator.evaluate(&result_value, &condition.value)
722                        }
723                        Err(e) => {
724                            if self.config.debug_mode {
725                                println!("      Function error: {}", e);
726                            }
727                            false
728                        }
729                    }
730                } else {
731                    if self.config.debug_mode {
732                        println!("      Function '{}' not found", name);
733                    }
734                    false
735                }
736            }
737        };
738
739        if self.config.debug_mode {
740            println!("      Result: {}", result);
741        }
742
743        Ok(result)
744    }
745
746    /// Execute an action
747    fn execute_action(&mut self, action: &ActionType, facts: &Facts) -> Result<()> {
748        match action {
749            ActionType::Set { field, value } => {
750                // Try nested first, then fall back to flat key setting
751                if let Err(_) = facts.set_nested(field, value.clone()) {
752                    // If nested fails, use flat key
753                    facts.set(field, value.clone());
754                }
755                if self.config.debug_mode {
756                    println!("  ✅ Set {field} = {value:?}");
757                }
758            }
759            ActionType::Log { message } => {
760                println!("📋 LOG: {}", message);
761            }
762            ActionType::Call { function, args } => {
763                let result = self.execute_function_call(function, args, facts)?;
764                if self.config.debug_mode {
765                    println!("  📞 Called {function}({args:?}) -> {result}");
766                }
767            }
768            ActionType::MethodCall {
769                object,
770                method,
771                args,
772            } => {
773                let result = self.execute_method_call(object, method, args, facts)?;
774                if self.config.debug_mode {
775                    println!("  🔧 Called {object}.{method}({args:?}) -> {result}");
776                }
777            }
778            ActionType::Update { object } => {
779                if self.config.debug_mode {
780                    println!("  🔄 Updated {object}");
781                }
782                // Update action is mainly for working memory management
783                // In this implementation, it's mostly a no-op since we update in place
784            }
785            ActionType::Custom {
786                action_type,
787                params,
788            } => {
789                if let Some(handler) = self.action_handlers.get(action_type) {
790                    if self.config.debug_mode {
791                        println!(
792                            "  🎯 Executing custom action: {action_type} with params: {params:?}"
793                        );
794                    }
795
796                    // Resolve parameter values from facts
797                    let resolved_params = self.resolve_action_parameters(params, facts)?;
798
799                    // Execute the registered handler
800                    handler(&resolved_params, facts)?;
801                } else {
802                    if self.config.debug_mode {
803                        println!("  ⚠️ No handler registered for custom action: {action_type}");
804                        println!(
805                            "     Available handlers: {:?}",
806                            self.action_handlers.keys().collect::<Vec<_>>()
807                        );
808                    }
809
810                    // Return error if no handler found
811                    return Err(RuleEngineError::EvaluationError {
812                        message: format!(
813                            "No action handler registered for '{action_type}'. Use engine.register_action_handler() to add custom action handlers."
814                        ),
815                    });
816                }
817            }
818            // 🔄 Workflow Actions
819            ActionType::ActivateAgendaGroup { group } => {
820                if self.config.debug_mode {
821                    println!("  🎯 Activating agenda group: {}", group);
822                }
823                // Sync with both workflow engine and agenda manager immediately
824                self.workflow_engine.activate_agenda_group(group.clone());
825                self.agenda_manager.set_focus(group);
826            }
827            ActionType::ScheduleRule {
828                rule_name,
829                delay_ms,
830            } => {
831                if self.config.debug_mode {
832                    println!(
833                        "  ⏰ Scheduling rule '{}' to execute in {}ms",
834                        rule_name, delay_ms
835                    );
836                }
837                self.workflow_engine
838                    .schedule_rule(rule_name.clone(), *delay_ms, None);
839            }
840            ActionType::CompleteWorkflow { workflow_name } => {
841                if self.config.debug_mode {
842                    println!("  ✅ Completing workflow: {}", workflow_name);
843                }
844                self.workflow_engine
845                    .complete_workflow(workflow_name.clone());
846            }
847            ActionType::SetWorkflowData { key, value } => {
848                if self.config.debug_mode {
849                    println!("  💾 Setting workflow data: {} = {:?}", key, value);
850                }
851                // For now, we'll use a default workflow ID. Later this could be enhanced
852                // to track current workflow context
853                let workflow_id = "default_workflow";
854                self.workflow_engine
855                    .set_workflow_data(workflow_id, key.clone(), value.clone());
856            }
857        }
858        Ok(())
859    }
860
861    /// Execute function call
862    fn execute_function_call(
863        &self,
864        function: &str,
865        args: &[Value],
866        facts: &Facts,
867    ) -> Result<String> {
868        let function_lower = function.to_lowercase();
869
870        // Handle built-in utility functions
871        match function_lower.as_str() {
872            "log" | "print" | "println" => self.handle_log_function(args),
873            "update" | "refresh" => self.handle_update_function(args),
874            "now" | "timestamp" => self.handle_timestamp_function(),
875            "random" => self.handle_random_function(args),
876            "format" | "sprintf" => self.handle_format_function(args),
877            "length" | "size" | "count" => self.handle_length_function(args),
878            "sum" | "add" => self.handle_sum_function(args),
879            "max" | "maximum" => self.handle_max_function(args),
880            "min" | "minimum" => self.handle_min_function(args),
881            "avg" | "average" => self.handle_average_function(args),
882            "round" => self.handle_round_function(args),
883            "floor" => self.handle_floor_function(args),
884            "ceil" | "ceiling" => self.handle_ceil_function(args),
885            "abs" | "absolute" => self.handle_abs_function(args),
886            "contains" | "includes" => self.handle_contains_function(args),
887            "startswith" | "begins_with" => self.handle_starts_with_function(args),
888            "endswith" | "ends_with" => self.handle_ends_with_function(args),
889            "lowercase" | "tolower" => self.handle_lowercase_function(args),
890            "uppercase" | "toupper" => self.handle_uppercase_function(args),
891            "trim" | "strip" => self.handle_trim_function(args),
892            "split" => self.handle_split_function(args),
893            "join" => self.handle_join_function(args),
894            _ => {
895                // Try to call custom user-defined function
896                self.handle_custom_function(function, args, facts)
897            }
898        }
899    }
900
901    /// Handle logging functions (log, print, println)
902    fn handle_log_function(&self, args: &[Value]) -> Result<String> {
903        let message = if args.is_empty() {
904            "".to_string()
905        } else if args.len() == 1 {
906            args[0].to_string()
907        } else {
908            args.iter()
909                .map(|v| v.to_string())
910                .collect::<Vec<_>>()
911                .join(" ")
912        };
913
914        println!("📋 {}", message);
915        Ok(message)
916    }
917
918    /// Handle update/refresh functions
919    fn handle_update_function(&self, args: &[Value]) -> Result<String> {
920        if let Some(arg) = args.first() {
921            Ok(format!("Updated: {}", arg.to_string()))
922        } else {
923            Ok("Updated".to_string())
924        }
925    }
926
927    /// Handle timestamp function
928    fn handle_timestamp_function(&self) -> Result<String> {
929        use std::time::{SystemTime, UNIX_EPOCH};
930        let timestamp = SystemTime::now()
931            .duration_since(UNIX_EPOCH)
932            .map_err(|e| RuleEngineError::EvaluationError {
933                message: format!("Failed to get timestamp: {}", e),
934            })?
935            .as_secs();
936        Ok(timestamp.to_string())
937    }
938
939    /// Handle random function
940    fn handle_random_function(&self, args: &[Value]) -> Result<String> {
941        use std::collections::hash_map::DefaultHasher;
942        use std::hash::{Hash, Hasher};
943
944        // Simple pseudo-random based on current time (for deterministic behavior in tests)
945        let mut hasher = DefaultHasher::new();
946        std::time::SystemTime::now().hash(&mut hasher);
947        let random_value = hasher.finish();
948
949        if args.is_empty() {
950            Ok((random_value % 100).to_string()) // 0-99
951        } else if let Some(Value::Number(max)) = args.first() {
952            let max_val = *max as u64;
953            Ok((random_value % max_val).to_string())
954        } else {
955            Ok(random_value.to_string())
956        }
957    }
958
959    /// Handle format function (simple sprintf-like)
960    fn handle_format_function(&self, args: &[Value]) -> Result<String> {
961        if args.is_empty() {
962            return Ok("".to_string());
963        }
964
965        let template = args[0].to_string();
966        let values: Vec<String> = args[1..].iter().map(|v| v.to_string()).collect();
967
968        // Simple placeholder replacement: {0}, {1}, etc.
969        let mut result = template;
970        for (i, value) in values.iter().enumerate() {
971            result = result.replace(&format!("{{{}}}", i), value);
972        }
973
974        Ok(result)
975    }
976
977    /// Handle length/size functions
978    fn handle_length_function(&self, args: &[Value]) -> Result<String> {
979        if let Some(arg) = args.first() {
980            match arg {
981                Value::String(s) => Ok(s.len().to_string()),
982                Value::Array(arr) => Ok(arr.len().to_string()),
983                Value::Object(obj) => Ok(obj.len().to_string()),
984                _ => Ok("1".to_string()), // Single value has length 1
985            }
986        } else {
987            Ok("0".to_string())
988        }
989    }
990
991    /// Handle sum function
992    fn handle_sum_function(&self, args: &[Value]) -> Result<String> {
993        let sum = args.iter().fold(0.0, |acc, val| match val {
994            Value::Number(n) => acc + n,
995            Value::Integer(i) => acc + (*i as f64),
996            _ => acc,
997        });
998        Ok(sum.to_string())
999    }
1000
1001    /// Handle max function
1002    fn handle_max_function(&self, args: &[Value]) -> Result<String> {
1003        let max = args.iter().fold(f64::NEG_INFINITY, |acc, val| match val {
1004            Value::Number(n) => acc.max(*n),
1005            Value::Integer(i) => acc.max(*i as f64),
1006            _ => acc,
1007        });
1008        Ok(max.to_string())
1009    }
1010
1011    /// Handle min function
1012    fn handle_min_function(&self, args: &[Value]) -> Result<String> {
1013        let min = args.iter().fold(f64::INFINITY, |acc, val| match val {
1014            Value::Number(n) => acc.min(*n),
1015            Value::Integer(i) => acc.min(*i as f64),
1016            _ => acc,
1017        });
1018        Ok(min.to_string())
1019    }
1020
1021    /// Handle average function
1022    fn handle_average_function(&self, args: &[Value]) -> Result<String> {
1023        if args.is_empty() {
1024            return Ok("0".to_string());
1025        }
1026
1027        let (sum, count) = args.iter().fold((0.0, 0), |(sum, count), val| match val {
1028            Value::Number(n) => (sum + n, count + 1),
1029            Value::Integer(i) => (sum + (*i as f64), count + 1),
1030            _ => (sum, count),
1031        });
1032
1033        if count > 0 {
1034            Ok((sum / count as f64).to_string())
1035        } else {
1036            Ok("0".to_string())
1037        }
1038    }
1039
1040    /// Handle mathematical functions
1041    fn handle_round_function(&self, args: &[Value]) -> Result<String> {
1042        if let Some(Value::Number(n)) = args.first() {
1043            Ok(n.round().to_string())
1044        } else if let Some(Value::Integer(i)) = args.first() {
1045            Ok(i.to_string())
1046        } else {
1047            Err(RuleEngineError::EvaluationError {
1048                message: "round() requires a numeric argument".to_string(),
1049            })
1050        }
1051    }
1052
1053    fn handle_floor_function(&self, args: &[Value]) -> Result<String> {
1054        if let Some(Value::Number(n)) = args.first() {
1055            Ok(n.floor().to_string())
1056        } else if let Some(Value::Integer(i)) = args.first() {
1057            Ok(i.to_string())
1058        } else {
1059            Err(RuleEngineError::EvaluationError {
1060                message: "floor() requires a numeric argument".to_string(),
1061            })
1062        }
1063    }
1064
1065    fn handle_ceil_function(&self, args: &[Value]) -> Result<String> {
1066        if let Some(Value::Number(n)) = args.first() {
1067            Ok(n.ceil().to_string())
1068        } else if let Some(Value::Integer(i)) = args.first() {
1069            Ok(i.to_string())
1070        } else {
1071            Err(RuleEngineError::EvaluationError {
1072                message: "ceil() requires a numeric argument".to_string(),
1073            })
1074        }
1075    }
1076
1077    fn handle_abs_function(&self, args: &[Value]) -> Result<String> {
1078        if let Some(Value::Number(n)) = args.first() {
1079            Ok(n.abs().to_string())
1080        } else if let Some(Value::Integer(i)) = args.first() {
1081            Ok(i.abs().to_string())
1082        } else {
1083            Err(RuleEngineError::EvaluationError {
1084                message: "abs() requires a numeric argument".to_string(),
1085            })
1086        }
1087    }
1088
1089    /// Handle string functions
1090    fn handle_contains_function(&self, args: &[Value]) -> Result<String> {
1091        if args.len() >= 2 {
1092            let haystack = args[0].to_string();
1093            let needle = args[1].to_string();
1094            Ok(haystack.contains(&needle).to_string())
1095        } else {
1096            Err(RuleEngineError::EvaluationError {
1097                message: "contains() requires 2 arguments".to_string(),
1098            })
1099        }
1100    }
1101
1102    fn handle_starts_with_function(&self, args: &[Value]) -> Result<String> {
1103        if args.len() >= 2 {
1104            let text = args[0].to_string();
1105            let prefix = args[1].to_string();
1106            Ok(text.starts_with(&prefix).to_string())
1107        } else {
1108            Err(RuleEngineError::EvaluationError {
1109                message: "startswith() requires 2 arguments".to_string(),
1110            })
1111        }
1112    }
1113
1114    fn handle_ends_with_function(&self, args: &[Value]) -> Result<String> {
1115        if args.len() >= 2 {
1116            let text = args[0].to_string();
1117            let suffix = args[1].to_string();
1118            Ok(text.ends_with(&suffix).to_string())
1119        } else {
1120            Err(RuleEngineError::EvaluationError {
1121                message: "endswith() requires 2 arguments".to_string(),
1122            })
1123        }
1124    }
1125
1126    fn handle_lowercase_function(&self, args: &[Value]) -> Result<String> {
1127        if let Some(arg) = args.first() {
1128            Ok(arg.to_string().to_lowercase())
1129        } else {
1130            Err(RuleEngineError::EvaluationError {
1131                message: "lowercase() requires 1 argument".to_string(),
1132            })
1133        }
1134    }
1135
1136    fn handle_uppercase_function(&self, args: &[Value]) -> Result<String> {
1137        if let Some(arg) = args.first() {
1138            Ok(arg.to_string().to_uppercase())
1139        } else {
1140            Err(RuleEngineError::EvaluationError {
1141                message: "uppercase() requires 1 argument".to_string(),
1142            })
1143        }
1144    }
1145
1146    fn handle_trim_function(&self, args: &[Value]) -> Result<String> {
1147        if let Some(arg) = args.first() {
1148            Ok(arg.to_string().trim().to_string())
1149        } else {
1150            Err(RuleEngineError::EvaluationError {
1151                message: "trim() requires 1 argument".to_string(),
1152            })
1153        }
1154    }
1155
1156    fn handle_split_function(&self, args: &[Value]) -> Result<String> {
1157        if args.len() >= 2 {
1158            let text = args[0].to_string();
1159            let delimiter = args[1].to_string();
1160            let parts: Vec<String> = text.split(&delimiter).map(|s| s.to_string()).collect();
1161            Ok(format!("{:?}", parts)) // Return as debug string for now
1162        } else {
1163            Err(RuleEngineError::EvaluationError {
1164                message: "split() requires 2 arguments".to_string(),
1165            })
1166        }
1167    }
1168
1169    fn handle_join_function(&self, args: &[Value]) -> Result<String> {
1170        if args.len() >= 2 {
1171            let delimiter = args[0].to_string();
1172            let parts: Vec<String> = args[1..].iter().map(|v| v.to_string()).collect();
1173            Ok(parts.join(&delimiter))
1174        } else {
1175            Err(RuleEngineError::EvaluationError {
1176                message: "join() requires at least 2 arguments".to_string(),
1177            })
1178        }
1179    }
1180
1181    /// Handle custom user-defined functions
1182    fn handle_custom_function(
1183        &self,
1184        function: &str,
1185        args: &[Value],
1186        facts: &Facts,
1187    ) -> Result<String> {
1188        // Check if we have a registered custom function
1189        if let Some(custom_func) = self.custom_functions.get(function) {
1190            if self.config.debug_mode {
1191                println!("🎯 Calling registered function: {}({:?})", function, args);
1192            }
1193
1194            match custom_func(args, facts) {
1195                Ok(result) => Ok(result.to_string()),
1196                Err(e) => Err(e),
1197            }
1198        } else {
1199            // Function not found - return error or placeholder
1200            if self.config.debug_mode {
1201                println!("⚠️ Custom function '{}' not registered", function);
1202            }
1203
1204            Err(RuleEngineError::EvaluationError {
1205                message: format!("Function '{}' is not registered. Use engine.register_function() to add custom functions.", function),
1206            })
1207        }
1208    }
1209
1210    /// Execute method call on object
1211    fn execute_method_call(
1212        &self,
1213        object_name: &str,
1214        method: &str,
1215        args: &[Value],
1216        facts: &Facts,
1217    ) -> Result<String> {
1218        // Get the object from facts
1219        let Some(object_value) = facts.get(object_name) else {
1220            return Err(RuleEngineError::EvaluationError {
1221                message: format!("Object '{}' not found in facts", object_name),
1222            });
1223        };
1224
1225        let method_lower = method.to_lowercase();
1226
1227        // Handle setter methods (set + property name)
1228        if method_lower.starts_with("set") && args.len() == 1 {
1229            return self.handle_setter_method(object_name, method, &args[0], object_value, facts);
1230        }
1231
1232        // Handle getter methods (get + property name)
1233        if method_lower.starts_with("get") && args.is_empty() {
1234            return self.handle_getter_method(object_name, method, &object_value);
1235        }
1236
1237        // Handle built-in methods
1238        match method_lower.as_str() {
1239            "tostring" => Ok(object_value.to_string()),
1240            "update" => {
1241                facts.add_value(object_name, object_value)?;
1242                Ok(format!("Updated {}", object_name))
1243            }
1244            "reset" => self.handle_reset_method(object_name, object_value, facts),
1245            _ => self.handle_property_access_or_fallback(
1246                object_name,
1247                method,
1248                args.len(),
1249                &object_value,
1250            ),
1251        }
1252    }
1253
1254    /// Handle setter method calls (setXxx)
1255    fn handle_setter_method(
1256        &self,
1257        object_name: &str,
1258        method: &str,
1259        new_value: &Value,
1260        mut object_value: Value,
1261        facts: &Facts,
1262    ) -> Result<String> {
1263        let property_name = Self::extract_property_name_from_setter(method);
1264
1265        match object_value {
1266            Value::Object(ref mut obj) => {
1267                obj.insert(property_name.clone(), new_value.clone());
1268                facts.add_value(object_name, object_value)?;
1269                Ok(format!(
1270                    "Set {} to {}",
1271                    property_name,
1272                    new_value.to_string()
1273                ))
1274            }
1275            _ => Err(RuleEngineError::EvaluationError {
1276                message: format!("Cannot call setter on non-object type: {}", object_name),
1277            }),
1278        }
1279    }
1280
1281    /// Handle getter method calls (getXxx)
1282    fn handle_getter_method(
1283        &self,
1284        object_name: &str,
1285        method: &str,
1286        object_value: &Value,
1287    ) -> Result<String> {
1288        let property_name = Self::extract_property_name_from_getter(method);
1289
1290        match object_value {
1291            Value::Object(obj) => {
1292                if let Some(value) = obj.get(&property_name) {
1293                    Ok(value.to_string())
1294                } else {
1295                    Err(RuleEngineError::EvaluationError {
1296                        message: format!(
1297                            "Property '{}' not found on object '{}'",
1298                            property_name, object_name
1299                        ),
1300                    })
1301                }
1302            }
1303            _ => Err(RuleEngineError::EvaluationError {
1304                message: format!("Cannot call getter on non-object type: {}", object_name),
1305            }),
1306        }
1307    }
1308
1309    /// Handle reset method call
1310    fn handle_reset_method(
1311        &self,
1312        object_name: &str,
1313        mut object_value: Value,
1314        facts: &Facts,
1315    ) -> Result<String> {
1316        match object_value {
1317            Value::Object(ref mut obj) => {
1318                obj.clear();
1319                facts.add_value(object_name, object_value)?;
1320                Ok(format!("Reset {}", object_name))
1321            }
1322            _ => Err(RuleEngineError::EvaluationError {
1323                message: format!("Cannot reset non-object type: {}", object_name),
1324            }),
1325        }
1326    }
1327
1328    /// Handle property access or fallback to generic method call
1329    fn handle_property_access_or_fallback(
1330        &self,
1331        object_name: &str,
1332        method: &str,
1333        arg_count: usize,
1334        object_value: &Value,
1335    ) -> Result<String> {
1336        if let Value::Object(obj) = object_value {
1337            // Try exact property name match
1338            if let Some(value) = obj.get(method) {
1339                return Ok(value.to_string());
1340            }
1341
1342            // Try capitalized property name
1343            let capitalized_method = Self::capitalize_first_letter(method);
1344            if let Some(value) = obj.get(&capitalized_method) {
1345                return Ok(value.to_string());
1346            }
1347        }
1348
1349        // Fallback to generic response
1350        Ok(format!(
1351            "Called {}.{} with {} args",
1352            object_name, method, arg_count
1353        ))
1354    }
1355
1356    /// Extract property name from setter method (setXxx -> Xxx)
1357    fn extract_property_name_from_setter(method: &str) -> String {
1358        let property_name = &method[3..]; // Remove "set" prefix
1359        Self::capitalize_first_letter(property_name)
1360    }
1361
1362    /// Extract property name from getter method (getXxx -> Xxx)
1363    fn extract_property_name_from_getter(method: &str) -> String {
1364        let property_name = &method[3..]; // Remove "get" prefix
1365        Self::capitalize_first_letter(property_name)
1366    }
1367
1368    /// Helper function to capitalize first letter of a string
1369    fn capitalize_first_letter(s: &str) -> String {
1370        if s.is_empty() {
1371            return String::new();
1372        }
1373        let mut chars = s.chars();
1374        match chars.next() {
1375            None => String::new(),
1376            Some(first) => first.to_uppercase().collect::<String>() + chars.as_str(),
1377        }
1378    }
1379
1380    /// Resolve action parameters by replacing fact references with actual values
1381    fn resolve_action_parameters(
1382        &self,
1383        params: &HashMap<String, Value>,
1384        facts: &Facts,
1385    ) -> Result<HashMap<String, Value>> {
1386        let mut resolved = HashMap::new();
1387
1388        for (key, value) in params {
1389            let resolved_value = match value {
1390                Value::String(s) => {
1391                    // Check if string looks like a fact reference (contains dot)
1392                    if s.contains('.') {
1393                        // Try to get the value from facts
1394                        if let Some(fact_value) = facts.get_nested(s) {
1395                            fact_value
1396                        } else {
1397                            // If not found, keep original string
1398                            value.clone()
1399                        }
1400                    } else {
1401                        value.clone()
1402                    }
1403                }
1404                _ => value.clone(),
1405            };
1406            resolved.insert(key.clone(), resolved_value);
1407        }
1408
1409        Ok(resolved)
1410    }
1411
1412    // 🔌 Plugin System Methods
1413
1414    /// Load a plugin into the engine
1415    pub fn load_plugin(
1416        &mut self,
1417        plugin: std::sync::Arc<dyn crate::engine::plugin::RulePlugin>,
1418    ) -> Result<()> {
1419        // First register the plugin actions with this engine
1420        plugin.register_actions(self)?;
1421        plugin.register_functions(self)?;
1422
1423        // Then store it in the plugin manager
1424        self.plugin_manager.load_plugin(plugin)
1425    }
1426
1427    /// Unload a plugin from the engine
1428    pub fn unload_plugin(&mut self, name: &str) -> Result<()> {
1429        self.plugin_manager.unload_plugin(name)
1430    }
1431
1432    /// Hot reload a plugin
1433    pub fn hot_reload_plugin(
1434        &mut self,
1435        name: &str,
1436        new_plugin: std::sync::Arc<dyn crate::engine::plugin::RulePlugin>,
1437    ) -> Result<()> {
1438        // Unload old plugin
1439        self.plugin_manager.unload_plugin(name)?;
1440
1441        // Register new plugin actions
1442        new_plugin.register_actions(self)?;
1443        new_plugin.register_functions(self)?;
1444
1445        // Load new plugin
1446        self.plugin_manager.load_plugin(new_plugin)
1447    }
1448
1449    /// Get plugin information
1450    pub fn get_plugin_info(&self, name: &str) -> Option<&crate::engine::plugin::PluginMetadata> {
1451        self.plugin_manager.get_plugin_info(name)
1452    }
1453
1454    /// List all loaded plugins
1455    pub fn list_plugins(&self) -> Vec<PluginInfo> {
1456        self.plugin_manager.list_plugins()
1457    }
1458
1459    /// Get plugin statistics
1460    pub fn get_plugin_stats(&self) -> PluginStats {
1461        self.plugin_manager.get_stats()
1462    }
1463
1464    /// Check health of all plugins
1465    pub fn plugin_health_check(&mut self) -> HashMap<String, crate::engine::plugin::PluginHealth> {
1466        self.plugin_manager.plugin_health_check()
1467    }
1468
1469    /// Configure plugin manager
1470    pub fn configure_plugins(&mut self, config: PluginConfig) {
1471        self.plugin_manager = PluginManager::new(config);
1472    }
1473}