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 log::info;
13use std::collections::HashMap;
14use std::time::{Duration, Instant};
15
16pub type CustomFunction = Box<dyn Fn(&[Value], &Facts) -> Result<Value> + Send + Sync>;
18
19pub type ActionHandler = Box<dyn Fn(&HashMap<String, Value>, &Facts) -> Result<()> + Send + Sync>;
21
22#[derive(Debug, Clone)]
24pub struct EngineConfig {
25 pub max_cycles: usize,
27 pub timeout: Option<Duration>,
29 pub enable_stats: bool,
31 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#[derive(Debug, Clone)]
48pub struct GruleExecutionResult {
49 pub cycle_count: usize,
51 pub rules_evaluated: usize,
53 pub rules_fired: usize,
55 pub execution_time: Duration,
57}
58
59pub 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 fired_rules_global: std::collections::HashSet<String>,
70 workflow_engine: WorkflowEngine,
72 plugin_manager: PluginManager,
74}
75
76#[allow(dead_code)]
77impl RustRuleEngine {
78 pub fn execute_with_callback<F>(
80 &mut self,
81 facts: &Facts,
82 mut on_rule_fired: F,
83 ) -> Result<GruleExecutionResult>
84 where
85 F: FnMut(&str, &Facts),
86 {
87 use chrono::Utc;
88 let timestamp = Utc::now();
89 let start_time = std::time::Instant::now();
90 let mut cycle_count = 0;
91 let mut rules_evaluated = 0;
92 let mut rules_fired = 0;
93
94 self.sync_workflow_agenda_activations();
95
96 for cycle in 0..self.config.max_cycles {
97 cycle_count = cycle + 1;
98 let mut any_rule_fired = false;
99 let mut fired_rules_in_cycle = std::collections::HashSet::new();
100 self.activation_group_manager.reset_cycle();
101
102 if let Some(timeout) = self.config.timeout {
103 if start_time.elapsed() > timeout {
104 return Err(crate::errors::RuleEngineError::EvaluationError {
105 message: "Execution timeout exceeded".to_string(),
106 });
107 }
108 }
109
110 let rule_indices = self.knowledge_base.get_rules_by_salience();
111
112 for &rule_index in &rule_indices {
113 if let Some(rule) = self.knowledge_base.get_rule_by_index(rule_index) {
114 if !rule.enabled {
115 continue;
116 }
117 if !self.agenda_manager.should_evaluate_rule(&rule) {
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 on_rule_fired(&rule.name, facts);
147 }
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 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 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 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 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 pub fn enable_analytics(&mut self, analytics: RuleAnalytics) {
215 self.analytics = Some(analytics);
216 }
217
218 pub fn reset_no_loop_tracking(&mut self) {
220 self.fired_rules_global.clear();
221 }
222
223 pub fn disable_analytics(&mut self) {
225 self.analytics = None;
226 }
227
228 pub fn analytics(&self) -> Option<&RuleAnalytics> {
230 self.analytics.as_ref()
231 }
232
233 pub fn set_debug_mode(&mut self, enabled: bool) {
235 self.config.debug_mode = enabled;
236 }
237
238 pub fn has_function(&self, name: &str) -> bool {
240 self.custom_functions.contains_key(name)
241 }
242
243 pub fn has_action_handler(&self, action_type: &str) -> bool {
245 self.action_handlers.contains_key(action_type)
246 }
247
248 pub fn get_ready_tasks(&mut self) -> Vec<crate::engine::workflow::ScheduledTask> {
250 self.workflow_engine.get_ready_tasks()
251 }
252
253 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.knowledge_base.get_rule(&task.rule_name) {
258 if self.config.debug_mode {
259 println!("⚡ Executing scheduled task: {}", task.rule_name);
260 }
261
262 if self.evaluate_conditions(&rule.conditions, facts)? {
264 for action in &rule.actions {
265 self.execute_action(action, facts)?;
266 }
267 }
268 }
269 }
270 Ok(())
271 }
272
273 pub fn activate_agenda_group(&mut self, group: String) {
275 self.workflow_engine.activate_agenda_group(group.clone());
276 self.agenda_manager.set_focus(&group);
277 }
278
279 pub fn knowledge_base(&self) -> &KnowledgeBase {
281 &self.knowledge_base
282 }
283
284 pub fn knowledge_base_mut(&mut self) -> &mut KnowledgeBase {
286 &mut self.knowledge_base
287 }
288
289 fn sync_workflow_agenda_activations(&mut self) {
291 while let Some(agenda_group) = self.workflow_engine.get_next_pending_agenda_activation() {
293 if self.config.debug_mode {
294 println!("🔄 Syncing workflow agenda activation: {}", agenda_group);
295 }
296 self.agenda_manager.set_focus(&agenda_group);
297 }
298 }
299
300 pub fn set_agenda_focus(&mut self, group: &str) {
302 self.agenda_manager.set_focus(group);
303 }
304
305 pub fn get_active_agenda_group(&self) -> &str {
307 self.agenda_manager.get_active_group()
308 }
309
310 pub fn pop_agenda_focus(&mut self) -> Option<String> {
312 self.agenda_manager.pop_focus()
313 }
314
315 pub fn clear_agenda_focus(&mut self) {
317 self.agenda_manager.clear_focus();
318 }
319
320 pub fn get_agenda_groups(&self) -> Vec<String> {
322 self.agenda_manager
323 .get_agenda_groups(&self.knowledge_base.get_rules())
324 }
325
326 pub fn get_activation_groups(&self) -> Vec<String> {
328 self.activation_group_manager
329 .get_activation_groups(&self.knowledge_base.get_rules())
330 }
331
332 pub fn start_workflow(&mut self, workflow_name: Option<String>) -> String {
336 self.workflow_engine.start_workflow(workflow_name)
337 }
338
339 pub fn get_workflow_stats(&self) -> crate::engine::workflow::WorkflowStats {
341 self.workflow_engine.get_workflow_stats()
342 }
343
344 pub fn get_workflow(
346 &self,
347 workflow_id: &str,
348 ) -> Option<&crate::engine::workflow::WorkflowState> {
349 self.workflow_engine.get_workflow(workflow_id)
350 }
351
352 pub fn cleanup_completed_workflows(&mut self, older_than: Duration) {
354 self.workflow_engine.cleanup_completed_workflows(older_than);
355 }
356
357 pub fn execute_workflow_step(
359 &mut self,
360 agenda_group: &str,
361 facts: &Facts,
362 ) -> Result<GruleExecutionResult> {
363 self.set_agenda_focus(agenda_group);
365
366 let result = self.execute(facts)?;
368
369 self.process_workflow_actions(facts)?;
371
372 Ok(result)
373 }
374
375 pub fn execute_workflow(
377 &mut self,
378 agenda_groups: Vec<&str>,
379 facts: &Facts,
380 ) -> Result<crate::engine::workflow::WorkflowResult> {
381 let start_time = Instant::now();
382 let mut total_steps = 0;
383
384 if self.config.debug_mode {
385 println!(
386 "🔄 Starting workflow execution with {} steps",
387 agenda_groups.len()
388 );
389 }
390
391 for (i, group) in agenda_groups.iter().enumerate() {
392 if self.config.debug_mode {
393 println!("📋 Executing workflow step {}: {}", i + 1, group);
394 }
395
396 let step_result = self.execute_workflow_step(group, facts)?;
397 total_steps += 1;
398
399 if step_result.rules_fired == 0 {
400 if self.config.debug_mode {
401 println!("⏸️ No rules fired in step '{}', stopping workflow", group);
402 }
403 break;
404 }
405 }
406
407 let execution_time = start_time.elapsed();
408
409 Ok(crate::engine::workflow::WorkflowResult::success(
410 total_steps,
411 execution_time,
412 ))
413 }
414
415 fn process_workflow_actions(&mut self, facts: &Facts) -> Result<()> {
417 while let Some(group) = self.workflow_engine.get_next_agenda_group() {
419 self.set_agenda_focus(&group);
420 }
421
422 let ready_tasks = self.workflow_engine.get_ready_tasks();
424 for task in ready_tasks {
425 if self.config.debug_mode {
426 println!("⚡ Executing scheduled task: {}", task.rule_name);
427 }
428
429 if let Some(rule) = self.knowledge_base.get_rule(&task.rule_name) {
431 if self.evaluate_conditions(&rule.conditions, facts)? {
433 for action in &rule.actions {
434 self.execute_action(action, facts)?;
435 }
436 }
437 }
438 }
439
440 Ok(())
441 }
442
443 pub fn execute(&mut self, facts: &Facts) -> Result<GruleExecutionResult> {
445 self.execute_at_time(facts, Utc::now())
446 }
447
448 pub fn execute_at_time(
450 &mut self,
451 facts: &Facts,
452 timestamp: DateTime<Utc>,
453 ) -> Result<GruleExecutionResult> {
454 let start_time = Instant::now();
455 let mut cycle_count = 0;
456 let mut rules_evaluated = 0;
457 let mut rules_fired = 0;
458
459 self.sync_workflow_agenda_activations();
461
462 if self.config.debug_mode {
463 println!(
464 "🚀 Starting rule execution with {} rules (agenda group: {})",
465 self.knowledge_base.rule_count(),
466 self.agenda_manager.get_active_group()
467 );
468 }
469
470 for cycle in 0..self.config.max_cycles {
471 cycle_count = cycle + 1;
472 let mut any_rule_fired = false;
473 let mut fired_rules_in_cycle = std::collections::HashSet::new();
474
475 self.activation_group_manager.reset_cycle();
477
478 if let Some(timeout) = self.config.timeout {
480 if start_time.elapsed() > timeout {
481 return Err(RuleEngineError::EvaluationError {
482 message: "Execution timeout exceeded".to_string(),
483 });
484 }
485 }
486
487 let rule_indices = self.knowledge_base.get_rules_by_salience();
489
490 for &rule_index in &rule_indices {
492 if let Some(rule) = self.knowledge_base.get_rule_by_index(rule_index) {
493 if !rule.enabled {
494 continue;
495 }
496
497 if !self.agenda_manager.should_evaluate_rule(&rule) {
498 continue;
499 }
500
501 if !rule.is_active_at(timestamp) {
503 continue;
504 }
505
506 if !self.agenda_manager.can_fire_rule(&rule) {
508 continue;
509 }
510
511 if !self.activation_group_manager.can_fire(&rule) {
513 continue;
514 }
515
516 if rule.no_loop && self.fired_rules_global.contains(&rule.name) {
518 if self.config.debug_mode {
519 println!("⛔ Skipping '{}' due to no_loop (already fired)", rule.name);
520 }
521 continue;
522 }
523
524 if self.config.debug_mode {
526 println!(
527 "🔍 Checking rule '{}' (no_loop: {})",
528 rule.name, rule.no_loop
529 );
530 }
531
532 let rule_start = std::time::Instant::now();
533
534 rules_evaluated += 1;
536
537 let condition_result = self.evaluate_conditions(&rule.conditions, facts)?;
539
540 if self.config.debug_mode {
541 println!(
542 " Rule '{}' condition result: {}",
543 rule.name, condition_result
544 );
545 }
546
547 if condition_result {
549 if self.config.debug_mode {
550 println!(
551 "🔥 Firing rule '{}' (salience: {})",
552 rule.name, rule.salience
553 );
554 }
555
556 for action in &rule.actions {
558 self.execute_action(action, facts)?;
559 }
560
561 let rule_duration = rule_start.elapsed();
562
563 if let Some(analytics) = &mut self.analytics {
565 analytics.record_execution(
566 &rule.name,
567 rule_duration,
568 true,
569 true,
570 None,
571 0,
572 );
573 }
574
575 rules_fired += 1;
576 any_rule_fired = true;
577
578 fired_rules_in_cycle.insert(rule.name.clone());
580
581 if rule.no_loop {
583 self.fired_rules_global.insert(rule.name.clone());
584 if self.config.debug_mode {
585 println!(" 🔒 Marked '{}' as fired (no_loop tracking)", rule.name);
586 }
587 }
588
589 self.agenda_manager.mark_rule_fired(&rule);
591 self.activation_group_manager.mark_fired(&rule);
592 } else {
593 let rule_duration = rule_start.elapsed();
594
595 if let Some(analytics) = &mut self.analytics {
597 analytics.record_execution(
598 &rule.name,
599 rule_duration,
600 false,
601 false,
602 None,
603 0,
604 );
605 }
606 }
607 } }
609
610 if !any_rule_fired {
612 break;
613 }
614
615 self.sync_workflow_agenda_activations();
617 }
618
619 let execution_time = start_time.elapsed();
620
621 Ok(GruleExecutionResult {
622 cycle_count,
623 rules_evaluated,
624 rules_fired,
625 execution_time,
626 })
627 }
628
629 fn evaluate_conditions(
631 &self,
632 conditions: &crate::engine::rule::ConditionGroup,
633 facts: &Facts,
634 ) -> Result<bool> {
635 use crate::engine::pattern_matcher::PatternMatcher;
636 use crate::engine::rule::ConditionGroup;
637
638 match conditions {
639 ConditionGroup::Single(condition) => self.evaluate_single_condition(condition, facts),
640 ConditionGroup::Compound {
641 left,
642 operator,
643 right,
644 } => {
645 let left_result = self.evaluate_conditions(left, facts)?;
646 let right_result = self.evaluate_conditions(right, facts)?;
647
648 match operator {
649 crate::types::LogicalOperator::And => Ok(left_result && right_result),
650 crate::types::LogicalOperator::Or => Ok(left_result || right_result),
651 crate::types::LogicalOperator::Not => Err(RuleEngineError::EvaluationError {
652 message: "NOT operator should not appear in compound conditions"
653 .to_string(),
654 }),
655 }
656 }
657 ConditionGroup::Not(condition) => {
658 let result = self.evaluate_conditions(condition, facts)?;
659 Ok(!result)
660 }
661 ConditionGroup::Exists(condition) => {
663 Ok(PatternMatcher::evaluate_exists(condition, facts))
664 }
665 ConditionGroup::Forall(condition) => {
666 Ok(PatternMatcher::evaluate_forall(condition, facts))
667 }
668 ConditionGroup::Accumulate {
669 result_var,
670 source_pattern,
671 extract_field,
672 source_conditions,
673 function,
674 function_arg,
675 } => {
676 self.evaluate_accumulate(
678 result_var,
679 source_pattern,
680 extract_field,
681 source_conditions,
682 function,
683 function_arg,
684 facts,
685 )?;
686 Ok(true)
688 }
689
690 #[cfg(feature = "streaming")]
691 ConditionGroup::StreamPattern { .. } => {
692 Ok(true)
695 }
696 }
697 }
698
699 #[allow(clippy::too_many_arguments)]
701 fn evaluate_accumulate(
702 &self,
703 _result_var: &str,
704 source_pattern: &str,
705 extract_field: &str,
706 source_conditions: &[String],
707 function: &str,
708 _function_arg: &str,
709 facts: &Facts,
710 ) -> Result<()> {
711 use crate::rete::accumulate::*;
712
713 let all_facts = facts.get_all_facts();
715 let mut matching_values = Vec::new();
716
717 let pattern_prefix = format!("{}.", source_pattern);
719
720 let mut instances: HashMap<String, HashMap<String, Value>> = HashMap::with_capacity(16);
722
723 for (key, value) in &all_facts {
724 if key.starts_with(&pattern_prefix) {
725 let parts: Vec<&str> = key
727 .strip_prefix(&pattern_prefix)
728 .unwrap()
729 .split('.')
730 .collect();
731
732 if parts.len() >= 2 {
733 let instance_id = parts[0];
735 let field_name = parts[1..].join(".");
736
737 instances
738 .entry(instance_id.to_string())
739 .or_default()
740 .insert(field_name, value.clone());
741 } else if parts.len() == 1 {
742 instances
744 .entry("default".to_string())
745 .or_default()
746 .insert(parts[0].to_string(), value.clone());
747 }
748 }
749 }
750
751 for (_instance_id, instance_facts) in instances {
753 let mut matches = true;
755
756 for condition_str in source_conditions {
757 if !self.evaluate_condition_string(condition_str, &instance_facts) {
759 matches = false;
760 break;
761 }
762 }
763
764 if matches {
765 if let Some(value) = instance_facts.get(extract_field) {
767 matching_values.push(value.clone());
768 }
769 }
770 }
771
772 let result = match function {
774 "sum" => {
775 let mut state = SumFunction.init();
776 for value in &matching_values {
777 state.accumulate(&self.value_to_fact_value(value));
778 }
779 self.fact_value_to_value(&state.get_result())
780 }
781 "count" => {
782 let mut state = CountFunction.init();
783 for value in &matching_values {
784 state.accumulate(&self.value_to_fact_value(value));
785 }
786 self.fact_value_to_value(&state.get_result())
787 }
788 "average" | "avg" => {
789 let mut state = AverageFunction.init();
790 for value in &matching_values {
791 state.accumulate(&self.value_to_fact_value(value));
792 }
793 self.fact_value_to_value(&state.get_result())
794 }
795 "min" => {
796 let mut state = MinFunction.init();
797 for value in &matching_values {
798 state.accumulate(&self.value_to_fact_value(value));
799 }
800 self.fact_value_to_value(&state.get_result())
801 }
802 "max" => {
803 let mut state = MaxFunction.init();
804 for value in &matching_values {
805 state.accumulate(&self.value_to_fact_value(value));
806 }
807 self.fact_value_to_value(&state.get_result())
808 }
809 _ => {
810 return Err(RuleEngineError::EvaluationError {
811 message: format!("Unknown accumulate function: {}", function),
812 });
813 }
814 };
815
816 let result_key = format!("{}.{}", source_pattern, function);
819
820 facts.set(&result_key, result);
821
822 if self.config.debug_mode {
823 println!(
824 " 🧮 Accumulate result: {} = {:?}",
825 result_key,
826 facts.get(&result_key)
827 );
828 }
829
830 Ok(())
831 }
832
833 fn value_to_fact_value(&self, value: &Value) -> crate::rete::facts::FactValue {
835 use crate::rete::facts::FactValue;
836 match value {
837 Value::Integer(i) => FactValue::Integer(*i),
838 Value::Number(n) => FactValue::Float(*n),
839 Value::String(s) => FactValue::String(s.clone()),
840 Value::Boolean(b) => FactValue::Boolean(*b),
841 _ => FactValue::String(value.to_string()),
842 }
843 }
844
845 fn fact_value_to_value(&self, fact_value: &crate::rete::facts::FactValue) -> Value {
847 use crate::rete::facts::FactValue;
848 match fact_value {
849 FactValue::Integer(i) => Value::Integer(*i),
850 FactValue::Float(f) => Value::Number(*f),
851 FactValue::String(s) => Value::String(s.clone()),
852 FactValue::Boolean(b) => Value::Boolean(*b),
853 FactValue::Array(_) => Value::String(format!("{:?}", fact_value)),
854 FactValue::Null => Value::String("null".to_string()),
855 }
856 }
857
858 fn evaluate_condition_string(&self, condition: &str, facts: &HashMap<String, Value>) -> bool {
860 let condition = condition.trim();
862
863 let operators = ["==", "!=", ">=", "<=", ">", "<"];
865
866 for op in &operators {
867 if let Some(pos) = condition.find(op) {
868 let field = condition[..pos].trim();
869 let value_str = condition[pos + op.len()..]
870 .trim()
871 .trim_matches('"')
872 .trim_matches('\'');
873
874 if let Some(field_value) = facts.get(field) {
875 return self.compare_values(field_value, op, value_str);
876 } else {
877 return false;
878 }
879 }
880 }
881
882 false
883 }
884
885 fn compare_values(&self, field_value: &Value, operator: &str, value_str: &str) -> bool {
887 match field_value {
888 Value::String(s) => match operator {
889 "==" => s == value_str,
890 "!=" => s != value_str,
891 _ => false,
892 },
893 Value::Integer(i) => {
894 if let Ok(num) = value_str.parse::<i64>() {
895 match operator {
896 "==" => *i == num,
897 "!=" => *i != num,
898 ">" => *i > num,
899 "<" => *i < num,
900 ">=" => *i >= num,
901 "<=" => *i <= num,
902 _ => false,
903 }
904 } else {
905 false
906 }
907 }
908 Value::Number(n) => {
909 if let Ok(num) = value_str.parse::<f64>() {
910 match operator {
911 "==" => (*n - num).abs() < f64::EPSILON,
912 "!=" => (*n - num).abs() >= f64::EPSILON,
913 ">" => *n > num,
914 "<" => *n < num,
915 ">=" => *n >= num,
916 "<=" => *n <= num,
917 _ => false,
918 }
919 } else {
920 false
921 }
922 }
923 Value::Boolean(b) => {
924 if let Ok(bool_val) = value_str.parse::<bool>() {
925 match operator {
926 "==" => *b == bool_val,
927 "!=" => *b != bool_val,
928 _ => false,
929 }
930 } else {
931 false
932 }
933 }
934 _ => false,
935 }
936 }
937
938 fn evaluate_rule_conditions(
940 &self,
941 rule: &crate::engine::rule::Rule,
942 facts: &Facts,
943 ) -> Result<bool> {
944 self.evaluate_conditions(&rule.conditions, facts)
945 }
946
947 fn is_retracted(&self, object_name: &str, facts: &Facts) -> bool {
949 let retract_key = format!("_retracted_{}", object_name);
950 matches!(facts.get(&retract_key), Some(Value::Boolean(true)))
951 }
952
953 fn evaluate_single_condition(
955 &self,
956 condition: &crate::engine::rule::Condition,
957 facts: &Facts,
958 ) -> Result<bool> {
959 use crate::engine::rule::ConditionExpression;
960
961 let result = match &condition.expression {
962 ConditionExpression::Field(field_name) => {
963 if let Some(object_name) = field_name.split('.').next() {
966 if self.is_retracted(object_name, facts) {
967 if self.config.debug_mode {
968 println!(" 🗑️ Skipping retracted fact: {}", object_name);
969 }
970 return Ok(false);
971 }
972 }
973
974 let field_value = facts
977 .get_nested(field_name)
978 .or_else(|| facts.get(field_name))
979 .unwrap_or(Value::Null);
980
981 if self.config.debug_mode {
982 println!(
983 " 🔎 Evaluating field condition: {} {} {:?}",
984 field_name,
985 format!("{:?}", condition.operator).to_lowercase(),
986 condition.value
987 );
988 println!(" Field value: {:?}", field_value);
989 }
990
991 let rhs = match &condition.value {
997 crate::types::Value::String(s) => {
998 facts
1000 .get_nested(s)
1001 .or_else(|| facts.get(s))
1002 .unwrap_or(crate::types::Value::String(s.clone()))
1003 }
1004 crate::types::Value::Expression(expr) => {
1005 match crate::expression::evaluate_expression(expr, facts) {
1007 Ok(evaluated) => evaluated,
1008 Err(_) => {
1009 facts
1011 .get_nested(expr)
1012 .or_else(|| facts.get(expr))
1013 .unwrap_or(crate::types::Value::Expression(expr.clone()))
1014 }
1015 }
1016 }
1017 _ => condition.value.clone(),
1018 };
1019
1020 if self.config.debug_mode {
1021 println!(" Resolved RHS for comparison: {:?}", rhs);
1022 }
1023
1024 condition.operator.evaluate(&field_value, &rhs)
1025 }
1026 ConditionExpression::FunctionCall { name, args } => {
1027 if self.config.debug_mode {
1029 println!(
1030 " 🔎 Evaluating function condition: {}({:?}) {} {:?}",
1031 name,
1032 args,
1033 format!("{:?}", condition.operator).to_lowercase(),
1034 condition.value
1035 );
1036 }
1037
1038 if let Some(function) = self.custom_functions.get(name) {
1039 let arg_values: Vec<Value> = args
1041 .iter()
1042 .map(|arg| {
1043 facts
1044 .get_nested(arg)
1045 .or_else(|| facts.get(arg))
1046 .unwrap_or(Value::String(arg.clone()))
1047 })
1048 .collect();
1049
1050 match function(&arg_values, facts) {
1052 Ok(result_value) => {
1053 if self.config.debug_mode {
1054 println!(" Function result: {:?}", result_value);
1055 }
1056 condition.operator.evaluate(&result_value, &condition.value)
1057 }
1058 Err(e) => {
1059 if self.config.debug_mode {
1060 println!(" Function error: {}", e);
1061 }
1062 false
1063 }
1064 }
1065 } else {
1066 if self.config.debug_mode {
1067 println!(" Function '{}' not found", name);
1068 }
1069 false
1070 }
1071 }
1072 ConditionExpression::Test { name, args } => {
1073 if self.config.debug_mode {
1075 println!(" 🧪 Evaluating test CE: test({}({:?}))", name, args);
1076 }
1077
1078 if let Some(function) = self.custom_functions.get(name) {
1080 let arg_values: Vec<Value> = args
1082 .iter()
1083 .map(|arg| {
1084 let resolved = facts
1085 .get_nested(arg)
1086 .or_else(|| facts.get(arg))
1087 .unwrap_or(Value::String(arg.clone()));
1088 if self.config.debug_mode {
1089 println!(" Resolving arg '{}' -> {:?}", arg, resolved);
1090 }
1091 resolved
1092 })
1093 .collect();
1094
1095 match function(&arg_values, facts) {
1097 Ok(result_value) => {
1098 if self.config.debug_mode {
1099 println!(" Test result: {:?}", result_value);
1100 }
1101 match result_value {
1103 Value::Boolean(b) => b,
1104 Value::Integer(i) => i != 0,
1105 Value::Number(f) => f != 0.0,
1106 Value::String(s) => !s.is_empty(),
1107 _ => false,
1108 }
1109 }
1110 Err(e) => {
1111 if self.config.debug_mode {
1112 println!(" Test function error: {}", e);
1113 }
1114 false
1115 }
1116 }
1117 } else {
1118 if self.config.debug_mode {
1121 println!(
1122 " Trying to evaluate '{}' as arithmetic expression",
1123 name
1124 );
1125 }
1126
1127 match self.evaluate_arithmetic_condition(name, facts) {
1129 Ok(result) => {
1130 if self.config.debug_mode {
1131 println!(" Arithmetic expression result: {}", result);
1132 }
1133 result
1134 }
1135 Err(e) => {
1136 if self.config.debug_mode {
1137 println!(" Failed to evaluate expression: {}", e);
1138 println!(" Test function '{}' not found", name);
1139 }
1140 false
1141 }
1142 }
1143 }
1144 }
1145 ConditionExpression::MultiField {
1146 field,
1147 operation,
1148 variable: _,
1149 } => {
1150 if self.config.debug_mode {
1152 println!(" 📦 Evaluating multi-field: {}.{}", field, operation);
1153 }
1154
1155 let field_value = facts.get_nested(field).or_else(|| facts.get(field));
1157
1158 if let Some(value) = field_value {
1159 match operation.as_str() {
1160 "empty" => {
1161 matches!(value, Value::Array(arr) if arr.is_empty())
1162 }
1163 "not_empty" => {
1164 matches!(value, Value::Array(arr) if !arr.is_empty())
1165 }
1166 "count" => {
1167 if let Value::Array(arr) = value {
1168 let count = Value::Integer(arr.len() as i64);
1169 condition.operator.evaluate(&count, &condition.value)
1170 } else {
1171 false
1172 }
1173 }
1174 "contains" => {
1175 condition.operator.evaluate(&value, &condition.value)
1177 }
1178 _ => {
1179 if self.config.debug_mode {
1182 println!(
1183 " ⚠️ Operation '{}' not fully implemented yet",
1184 operation
1185 );
1186 }
1187 true
1188 }
1189 }
1190 } else {
1191 false
1192 }
1193 }
1194 };
1195
1196 if self.config.debug_mode {
1197 println!(" Result: {}", result);
1198 }
1199
1200 Ok(result)
1201 }
1202
1203 fn execute_action(&mut self, action: &ActionType, facts: &Facts) -> Result<()> {
1205 match action {
1206 ActionType::Set { field, value } => {
1207 let evaluated_value = match value {
1209 Value::Expression(expr) => {
1210 crate::expression::evaluate_expression(expr, facts)?
1212 }
1213 _ => value.clone(),
1214 };
1215
1216 if facts.set_nested(field, evaluated_value.clone()).is_err() {
1218 facts.set(field, evaluated_value.clone());
1220 }
1221 if self.config.debug_mode {
1222 println!(" ✅ Set {field} = {evaluated_value:?}");
1223 }
1224 }
1225 ActionType::Log { message } => {
1226 println!("📋 LOG: {}", message);
1227 }
1228 ActionType::MethodCall {
1229 object,
1230 method,
1231 args,
1232 } => {
1233 let result = self.execute_method_call(object, method, args, facts)?;
1234 if self.config.debug_mode {
1235 println!(" 🔧 Called {object}.{method}({args:?}) -> {result}");
1236 }
1237 }
1238 ActionType::Retract { object } => {
1239 if self.config.debug_mode {
1240 println!(" 🗑️ Retracted {object}");
1241 }
1242 facts.set(&format!("_retracted_{}", object), Value::Boolean(true));
1244 }
1245 ActionType::Custom {
1246 action_type,
1247 params,
1248 } => {
1249 if let Some(handler) = self.action_handlers.get(action_type) {
1250 if self.config.debug_mode {
1251 println!(
1252 " 🎯 Executing custom action: {action_type} with params: {params:?}"
1253 );
1254 }
1255
1256 let resolved_params = self.resolve_action_parameters(params, facts)?;
1258
1259 handler(&resolved_params, facts)?;
1261 } else {
1262 if self.config.debug_mode {
1263 println!(" ⚠️ No handler registered for custom action: {action_type}");
1264 println!(
1265 " Available handlers: {:?}",
1266 self.action_handlers.keys().collect::<Vec<_>>()
1267 );
1268 }
1269
1270 return Err(RuleEngineError::EvaluationError {
1272 message: format!(
1273 "No action handler registered for '{action_type}'. Use engine.register_action_handler() to add custom action handlers."
1274 ),
1275 });
1276 }
1277 }
1278 ActionType::ActivateAgendaGroup { group } => {
1280 if self.config.debug_mode {
1281 println!(" 🎯 Activating agenda group: {}", group);
1282 }
1283 self.workflow_engine.activate_agenda_group(group.clone());
1285 self.agenda_manager.set_focus(group);
1286 }
1287 ActionType::ScheduleRule {
1288 rule_name,
1289 delay_ms,
1290 } => {
1291 if self.config.debug_mode {
1292 println!(
1293 " ⏰ Scheduling rule '{}' to execute in {}ms",
1294 rule_name, delay_ms
1295 );
1296 }
1297 self.workflow_engine
1298 .schedule_rule(rule_name.clone(), *delay_ms, None);
1299 }
1300 ActionType::CompleteWorkflow { workflow_name } => {
1301 if self.config.debug_mode {
1302 println!(" ✅ Completing workflow: {}", workflow_name);
1303 }
1304 self.workflow_engine
1305 .complete_workflow(workflow_name.clone());
1306 }
1307 ActionType::SetWorkflowData { key, value } => {
1308 if self.config.debug_mode {
1309 println!(" 💾 Setting workflow data: {} = {:?}", key, value);
1310 }
1311 let workflow_id = "default_workflow";
1314 self.workflow_engine
1315 .set_workflow_data(workflow_id, key.clone(), value.clone());
1316 }
1317 ActionType::Append { field, value } => {
1318 let evaluated_value = match value {
1320 Value::Expression(expr) => crate::expression::evaluate_expression(expr, facts)?,
1321 _ => value.clone(),
1322 };
1323
1324 let current_value = facts.get(field);
1326 let mut array = match current_value {
1327 Some(Value::Array(arr)) => arr.clone(),
1328 Some(_) => {
1329 if self.config.debug_mode {
1331 println!(" ⚠️ Field {} is not an array, creating new array", field);
1332 }
1333 Vec::new()
1334 }
1335 None => Vec::new(),
1336 };
1337
1338 array.push(evaluated_value.clone());
1340
1341 if facts
1343 .set_nested(field, Value::Array(array.clone()))
1344 .is_err()
1345 {
1346 facts.set(field, Value::Array(array.clone()));
1347 }
1348
1349 if self.config.debug_mode {
1350 println!(" ➕ Appended to {}: {:?}", field, evaluated_value);
1351 }
1352 }
1353 }
1354 Ok(())
1355 }
1356
1357 fn evaluate_arithmetic_condition(&self, expr: &str, facts: &Facts) -> Result<bool> {
1359 let operators = [">=", "<=", "==", "!=", ">", "<"];
1363 let mut split_pos = None;
1364 let mut found_op = "";
1365
1366 for op in &operators {
1367 if let Some(pos) = expr.rfind(op) {
1368 split_pos = Some(pos);
1369 found_op = op;
1370 break;
1371 }
1372 }
1373
1374 if split_pos.is_none() {
1375 return Err(RuleEngineError::EvaluationError {
1376 message: format!("No comparison operator found in expression: {}", expr),
1377 });
1378 }
1379
1380 let pos = split_pos.unwrap();
1381 let left_expr = expr[..pos].trim();
1382 let right_value = expr[pos + found_op.len()..].trim();
1383
1384 let left_result = crate::expression::evaluate_expression(left_expr, facts)?;
1386
1387 let right_val = if let Ok(i) = right_value.parse::<i64>() {
1389 Value::Integer(i)
1390 } else if let Ok(f) = right_value.parse::<f64>() {
1391 Value::Number(f)
1392 } else {
1393 match crate::expression::evaluate_expression(right_value, facts) {
1395 Ok(v) => v,
1396 Err(_) => Value::String(right_value.to_string()),
1397 }
1398 };
1399
1400 let operator =
1402 Operator::from_str(found_op).ok_or_else(|| RuleEngineError::InvalidOperator {
1403 operator: found_op.to_string(),
1404 })?;
1405
1406 Ok(operator.evaluate(&left_result, &right_val))
1407 }
1408
1409 fn execute_function_call(
1411 &self,
1412 function: &str,
1413 args: &[Value],
1414 facts: &Facts,
1415 ) -> Result<String> {
1416 let function_lower = function.to_lowercase();
1417
1418 match function_lower.as_str() {
1420 "log" | "print" | "println" => self.handle_log_function(args),
1421 "update" | "refresh" => self.handle_update_function(args),
1422 "now" | "timestamp" => self.handle_timestamp_function(),
1423 "random" => self.handle_random_function(args),
1424 "format" | "sprintf" => self.handle_format_function(args),
1425 "length" | "size" | "count" => self.handle_length_function(args),
1426 "sum" | "add" => self.handle_sum_function(args),
1427 "max" | "maximum" => self.handle_max_function(args),
1428 "min" | "minimum" => self.handle_min_function(args),
1429 "avg" | "average" => self.handle_average_function(args),
1430 "round" => self.handle_round_function(args),
1431 "floor" => self.handle_floor_function(args),
1432 "ceil" | "ceiling" => self.handle_ceil_function(args),
1433 "abs" | "absolute" => self.handle_abs_function(args),
1434 "contains" | "includes" => self.handle_contains_function(args),
1435 "startswith" | "begins_with" => self.handle_starts_with_function(args),
1436 "endswith" | "ends_with" => self.handle_ends_with_function(args),
1437 "lowercase" | "tolower" => self.handle_lowercase_function(args),
1438 "uppercase" | "toupper" => self.handle_uppercase_function(args),
1439 "trim" | "strip" => self.handle_trim_function(args),
1440 "split" => self.handle_split_function(args),
1441 "join" => self.handle_join_function(args),
1442 _ => {
1443 self.handle_custom_function(function, args, facts)
1445 }
1446 }
1447 }
1448
1449 fn handle_log_function(&self, args: &[Value]) -> Result<String> {
1451 let message = if args.is_empty() {
1452 "".to_string()
1453 } else if args.len() == 1 {
1454 args[0].to_string()
1455 } else {
1456 args.iter()
1457 .map(|v| v.to_string())
1458 .collect::<Vec<_>>()
1459 .join(" ")
1460 };
1461
1462 info!("📋 {}", message);
1463 Ok(message)
1464 }
1465
1466 fn handle_update_function(&self, args: &[Value]) -> Result<String> {
1468 if let Some(arg) = args.first() {
1469 Ok(format!("Updated: {}", arg.to_string()))
1470 } else {
1471 Ok("Updated".to_string())
1472 }
1473 }
1474
1475 fn handle_timestamp_function(&self) -> Result<String> {
1477 use std::time::{SystemTime, UNIX_EPOCH};
1478 let timestamp = SystemTime::now()
1479 .duration_since(UNIX_EPOCH)
1480 .map_err(|e| RuleEngineError::EvaluationError {
1481 message: format!("Failed to get timestamp: {}", e),
1482 })?
1483 .as_secs();
1484 Ok(timestamp.to_string())
1485 }
1486
1487 fn handle_random_function(&self, args: &[Value]) -> Result<String> {
1489 use std::collections::hash_map::DefaultHasher;
1490 use std::hash::{Hash, Hasher};
1491
1492 let mut hasher = DefaultHasher::new();
1494 std::time::SystemTime::now().hash(&mut hasher);
1495 let random_value = hasher.finish();
1496
1497 if args.is_empty() {
1498 Ok((random_value % 100).to_string()) } else if let Some(Value::Number(max)) = args.first() {
1500 let max_val = *max as u64;
1501 Ok((random_value % max_val).to_string())
1502 } else {
1503 Ok(random_value.to_string())
1504 }
1505 }
1506
1507 fn handle_format_function(&self, args: &[Value]) -> Result<String> {
1509 if args.is_empty() {
1510 return Ok("".to_string());
1511 }
1512
1513 let template = args[0].to_string();
1514 let values: Vec<String> = args[1..].iter().map(|v| v.to_string()).collect();
1515
1516 let mut result = template;
1518 for (i, value) in values.iter().enumerate() {
1519 result = result.replace(&format!("{{{}}}", i), value);
1520 }
1521
1522 Ok(result)
1523 }
1524
1525 fn handle_length_function(&self, args: &[Value]) -> Result<String> {
1527 if let Some(arg) = args.first() {
1528 match arg {
1529 Value::String(s) => Ok(s.len().to_string()),
1530 Value::Array(arr) => Ok(arr.len().to_string()),
1531 Value::Object(obj) => Ok(obj.len().to_string()),
1532 _ => Ok("1".to_string()), }
1534 } else {
1535 Ok("0".to_string())
1536 }
1537 }
1538
1539 fn handle_sum_function(&self, args: &[Value]) -> Result<String> {
1541 let sum = args.iter().fold(0.0, |acc, val| match val {
1542 Value::Number(n) => acc + n,
1543 Value::Integer(i) => acc + (*i as f64),
1544 _ => acc,
1545 });
1546 Ok(sum.to_string())
1547 }
1548
1549 fn handle_max_function(&self, args: &[Value]) -> Result<String> {
1551 let max = args.iter().fold(f64::NEG_INFINITY, |acc, val| match val {
1552 Value::Number(n) => acc.max(*n),
1553 Value::Integer(i) => acc.max(*i as f64),
1554 _ => acc,
1555 });
1556 Ok(max.to_string())
1557 }
1558
1559 fn handle_min_function(&self, args: &[Value]) -> Result<String> {
1561 let min = args.iter().fold(f64::INFINITY, |acc, val| match val {
1562 Value::Number(n) => acc.min(*n),
1563 Value::Integer(i) => acc.min(*i as f64),
1564 _ => acc,
1565 });
1566 Ok(min.to_string())
1567 }
1568
1569 fn handle_average_function(&self, args: &[Value]) -> Result<String> {
1571 if args.is_empty() {
1572 return Ok("0".to_string());
1573 }
1574
1575 let (sum, count) = args.iter().fold((0.0, 0), |(sum, count), val| match val {
1576 Value::Number(n) => (sum + n, count + 1),
1577 Value::Integer(i) => (sum + (*i as f64), count + 1),
1578 _ => (sum, count),
1579 });
1580
1581 if count > 0 {
1582 Ok((sum / count as f64).to_string())
1583 } else {
1584 Ok("0".to_string())
1585 }
1586 }
1587
1588 fn handle_round_function(&self, args: &[Value]) -> Result<String> {
1590 if let Some(Value::Number(n)) = args.first() {
1591 Ok(n.round().to_string())
1592 } else if let Some(Value::Integer(i)) = args.first() {
1593 Ok(i.to_string())
1594 } else {
1595 Err(RuleEngineError::EvaluationError {
1596 message: "round() requires a numeric argument".to_string(),
1597 })
1598 }
1599 }
1600
1601 fn handle_floor_function(&self, args: &[Value]) -> Result<String> {
1602 if let Some(Value::Number(n)) = args.first() {
1603 Ok(n.floor().to_string())
1604 } else if let Some(Value::Integer(i)) = args.first() {
1605 Ok(i.to_string())
1606 } else {
1607 Err(RuleEngineError::EvaluationError {
1608 message: "floor() requires a numeric argument".to_string(),
1609 })
1610 }
1611 }
1612
1613 fn handle_ceil_function(&self, args: &[Value]) -> Result<String> {
1614 if let Some(Value::Number(n)) = args.first() {
1615 Ok(n.ceil().to_string())
1616 } else if let Some(Value::Integer(i)) = args.first() {
1617 Ok(i.to_string())
1618 } else {
1619 Err(RuleEngineError::EvaluationError {
1620 message: "ceil() requires a numeric argument".to_string(),
1621 })
1622 }
1623 }
1624
1625 fn handle_abs_function(&self, args: &[Value]) -> Result<String> {
1626 if let Some(Value::Number(n)) = args.first() {
1627 Ok(n.abs().to_string())
1628 } else if let Some(Value::Integer(i)) = args.first() {
1629 Ok(i.abs().to_string())
1630 } else {
1631 Err(RuleEngineError::EvaluationError {
1632 message: "abs() requires a numeric argument".to_string(),
1633 })
1634 }
1635 }
1636
1637 fn handle_contains_function(&self, args: &[Value]) -> Result<String> {
1639 if args.len() >= 2 {
1640 let haystack = args[0].to_string();
1641 let needle = args[1].to_string();
1642 Ok(haystack.contains(&needle).to_string())
1643 } else {
1644 Err(RuleEngineError::EvaluationError {
1645 message: "contains() requires 2 arguments".to_string(),
1646 })
1647 }
1648 }
1649
1650 fn handle_starts_with_function(&self, args: &[Value]) -> Result<String> {
1651 if args.len() >= 2 {
1652 let text = args[0].to_string();
1653 let prefix = args[1].to_string();
1654 Ok(text.starts_with(&prefix).to_string())
1655 } else {
1656 Err(RuleEngineError::EvaluationError {
1657 message: "startswith() requires 2 arguments".to_string(),
1658 })
1659 }
1660 }
1661
1662 fn handle_ends_with_function(&self, args: &[Value]) -> Result<String> {
1663 if args.len() >= 2 {
1664 let text = args[0].to_string();
1665 let suffix = args[1].to_string();
1666 Ok(text.ends_with(&suffix).to_string())
1667 } else {
1668 Err(RuleEngineError::EvaluationError {
1669 message: "endswith() requires 2 arguments".to_string(),
1670 })
1671 }
1672 }
1673
1674 fn handle_lowercase_function(&self, args: &[Value]) -> Result<String> {
1675 if let Some(arg) = args.first() {
1676 Ok(arg.to_string().to_lowercase())
1677 } else {
1678 Err(RuleEngineError::EvaluationError {
1679 message: "lowercase() requires 1 argument".to_string(),
1680 })
1681 }
1682 }
1683
1684 fn handle_uppercase_function(&self, args: &[Value]) -> Result<String> {
1685 if let Some(arg) = args.first() {
1686 Ok(arg.to_string().to_uppercase())
1687 } else {
1688 Err(RuleEngineError::EvaluationError {
1689 message: "uppercase() requires 1 argument".to_string(),
1690 })
1691 }
1692 }
1693
1694 fn handle_trim_function(&self, args: &[Value]) -> Result<String> {
1695 if let Some(arg) = args.first() {
1696 Ok(arg.to_string().trim().to_string())
1697 } else {
1698 Err(RuleEngineError::EvaluationError {
1699 message: "trim() requires 1 argument".to_string(),
1700 })
1701 }
1702 }
1703
1704 fn handle_split_function(&self, args: &[Value]) -> Result<String> {
1705 if args.len() >= 2 {
1706 let text = args[0].to_string();
1707 let delimiter = args[1].to_string();
1708 let parts: Vec<String> = text.split(&delimiter).map(|s| s.to_string()).collect();
1709 Ok(format!("{:?}", parts)) } else {
1711 Err(RuleEngineError::EvaluationError {
1712 message: "split() requires 2 arguments".to_string(),
1713 })
1714 }
1715 }
1716
1717 fn handle_join_function(&self, args: &[Value]) -> Result<String> {
1718 if args.len() >= 2 {
1719 let delimiter = args[0].to_string();
1720 let parts: Vec<String> = args[1..].iter().map(|v| v.to_string()).collect();
1721 Ok(parts.join(&delimiter))
1722 } else {
1723 Err(RuleEngineError::EvaluationError {
1724 message: "join() requires at least 2 arguments".to_string(),
1725 })
1726 }
1727 }
1728
1729 fn handle_custom_function(
1731 &self,
1732 function: &str,
1733 args: &[Value],
1734 facts: &Facts,
1735 ) -> Result<String> {
1736 if let Some(custom_func) = self.custom_functions.get(function) {
1738 if self.config.debug_mode {
1739 println!("🎯 Calling registered function: {}({:?})", function, args);
1740 }
1741
1742 match custom_func(args, facts) {
1743 Ok(result) => Ok(result.to_string()),
1744 Err(e) => Err(e),
1745 }
1746 } else {
1747 if self.config.debug_mode {
1749 println!("⚠️ Custom function '{}' not registered", function);
1750 }
1751
1752 Err(RuleEngineError::EvaluationError {
1753 message: format!("Function '{}' is not registered. Use engine.register_function() to add custom functions.", function),
1754 })
1755 }
1756 }
1757
1758 fn execute_method_call(
1760 &self,
1761 object_name: &str,
1762 method: &str,
1763 args: &[Value],
1764 facts: &Facts,
1765 ) -> Result<String> {
1766 let Some(object_value) = facts.get(object_name) else {
1768 return Err(RuleEngineError::EvaluationError {
1769 message: format!("Object '{}' not found in facts", object_name),
1770 });
1771 };
1772
1773 let method_lower = method.to_lowercase();
1774
1775 if method_lower.starts_with("set") && args.len() == 1 {
1777 return self.handle_setter_method(object_name, method, &args[0], object_value, facts);
1778 }
1779
1780 if method_lower.starts_with("get") && args.is_empty() {
1782 return self.handle_getter_method(object_name, method, &object_value);
1783 }
1784
1785 match method_lower.as_str() {
1787 "tostring" => Ok(object_value.to_string()),
1788 "update" => {
1789 facts.add_value(object_name, object_value)?;
1790 Ok(format!("Updated {}", object_name))
1791 }
1792 "reset" => self.handle_reset_method(object_name, object_value, facts),
1793 _ => self.handle_property_access_or_fallback(
1794 object_name,
1795 method,
1796 args.len(),
1797 &object_value,
1798 ),
1799 }
1800 }
1801
1802 fn handle_setter_method(
1804 &self,
1805 object_name: &str,
1806 method: &str,
1807 new_value: &Value,
1808 mut object_value: Value,
1809 facts: &Facts,
1810 ) -> Result<String> {
1811 let property_name = Self::extract_property_name_from_setter(method);
1812
1813 match object_value {
1814 Value::Object(ref mut obj) => {
1815 obj.insert(property_name.clone(), new_value.clone());
1816 facts.add_value(object_name, object_value)?;
1817 Ok(format!(
1818 "Set {} to {}",
1819 property_name,
1820 new_value.to_string()
1821 ))
1822 }
1823 _ => Err(RuleEngineError::EvaluationError {
1824 message: format!("Cannot call setter on non-object type: {}", object_name),
1825 }),
1826 }
1827 }
1828
1829 fn handle_getter_method(
1831 &self,
1832 object_name: &str,
1833 method: &str,
1834 object_value: &Value,
1835 ) -> Result<String> {
1836 let property_name = Self::extract_property_name_from_getter(method);
1837
1838 match object_value {
1839 Value::Object(obj) => {
1840 if let Some(value) = obj.get(&property_name) {
1841 Ok(value.to_string())
1842 } else {
1843 Err(RuleEngineError::EvaluationError {
1844 message: format!(
1845 "Property '{}' not found on object '{}'",
1846 property_name, object_name
1847 ),
1848 })
1849 }
1850 }
1851 _ => Err(RuleEngineError::EvaluationError {
1852 message: format!("Cannot call getter on non-object type: {}", object_name),
1853 }),
1854 }
1855 }
1856
1857 fn handle_reset_method(
1859 &self,
1860 object_name: &str,
1861 mut object_value: Value,
1862 facts: &Facts,
1863 ) -> Result<String> {
1864 match object_value {
1865 Value::Object(ref mut obj) => {
1866 obj.clear();
1867 facts.add_value(object_name, object_value)?;
1868 Ok(format!("Reset {}", object_name))
1869 }
1870 _ => Err(RuleEngineError::EvaluationError {
1871 message: format!("Cannot reset non-object type: {}", object_name),
1872 }),
1873 }
1874 }
1875
1876 fn handle_property_access_or_fallback(
1878 &self,
1879 object_name: &str,
1880 method: &str,
1881 arg_count: usize,
1882 object_value: &Value,
1883 ) -> Result<String> {
1884 if let Value::Object(obj) = object_value {
1885 if let Some(value) = obj.get(method) {
1887 return Ok(value.to_string());
1888 }
1889
1890 let capitalized_method = Self::capitalize_first_letter(method);
1892 if let Some(value) = obj.get(&capitalized_method) {
1893 return Ok(value.to_string());
1894 }
1895 }
1896
1897 Ok(format!(
1899 "Called {}.{} with {} args",
1900 object_name, method, arg_count
1901 ))
1902 }
1903
1904 fn extract_property_name_from_setter(method: &str) -> String {
1906 let property_name = &method[3..]; Self::capitalize_first_letter(property_name)
1908 }
1909
1910 fn extract_property_name_from_getter(method: &str) -> String {
1912 let property_name = &method[3..]; Self::capitalize_first_letter(property_name)
1914 }
1915
1916 fn capitalize_first_letter(s: &str) -> String {
1918 if s.is_empty() {
1919 return String::new();
1920 }
1921 let mut chars = s.chars();
1922 match chars.next() {
1923 None => String::new(),
1924 Some(first) => first.to_uppercase().collect::<String>() + chars.as_str(),
1925 }
1926 }
1927
1928 fn resolve_action_parameters(
1930 &self,
1931 params: &HashMap<String, Value>,
1932 facts: &Facts,
1933 ) -> Result<HashMap<String, Value>> {
1934 let mut resolved = HashMap::new();
1935
1936 for (key, value) in params {
1937 let resolved_value = match value {
1938 Value::String(s) => {
1939 if s.contains('.') {
1941 if let Some(fact_value) = facts.get_nested(s) {
1943 fact_value
1944 } else {
1945 value.clone()
1947 }
1948 } else {
1949 value.clone()
1950 }
1951 }
1952 _ => value.clone(),
1953 };
1954 resolved.insert(key.clone(), resolved_value);
1955 }
1956
1957 Ok(resolved)
1958 }
1959
1960 pub fn load_plugin(
1964 &mut self,
1965 plugin: std::sync::Arc<dyn crate::engine::plugin::RulePlugin>,
1966 ) -> Result<()> {
1967 plugin.register_actions(self)?;
1969 plugin.register_functions(self)?;
1970
1971 self.plugin_manager.load_plugin(plugin)
1973 }
1974
1975 pub fn unload_plugin(&mut self, name: &str) -> Result<()> {
1977 self.plugin_manager.unload_plugin(name)
1978 }
1979
1980 pub fn hot_reload_plugin(
1982 &mut self,
1983 name: &str,
1984 new_plugin: std::sync::Arc<dyn crate::engine::plugin::RulePlugin>,
1985 ) -> Result<()> {
1986 self.plugin_manager.unload_plugin(name)?;
1988
1989 new_plugin.register_actions(self)?;
1991 new_plugin.register_functions(self)?;
1992
1993 self.plugin_manager.load_plugin(new_plugin)
1995 }
1996
1997 pub fn get_plugin_info(&self, name: &str) -> Option<&crate::engine::plugin::PluginMetadata> {
1999 self.plugin_manager.get_plugin_info(name)
2000 }
2001
2002 pub fn list_plugins(&self) -> Vec<PluginInfo> {
2004 self.plugin_manager.list_plugins()
2005 }
2006
2007 pub fn get_plugin_stats(&self) -> PluginStats {
2009 self.plugin_manager.get_stats()
2010 }
2011
2012 pub fn plugin_health_check(&mut self) -> HashMap<String, crate::engine::plugin::PluginHealth> {
2014 self.plugin_manager.plugin_health_check()
2015 }
2016
2017 pub fn configure_plugins(&mut self, config: PluginConfig) {
2019 self.plugin_manager = PluginManager::new(config);
2020 }
2021}