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 println!("⛔ Skipping '{}' due to no_loop (already fired)", rule.name);
519 continue;
520 }
521
522 if self.config.debug_mode {
524 println!(
525 "🔍 Checking rule '{}' (no_loop: {})",
526 rule.name, rule.no_loop
527 );
528 }
529
530 let rule_start = std::time::Instant::now();
531
532 rules_evaluated += 1;
534
535 let condition_result = self.evaluate_conditions(&rule.conditions, facts)?;
537
538 if self.config.debug_mode {
539 println!(
540 " Rule '{}' condition result: {}",
541 rule.name, condition_result
542 );
543 }
544
545 if condition_result {
547 if self.config.debug_mode {
548 println!(
549 "🔥 Firing rule '{}' (salience: {})",
550 rule.name, rule.salience
551 );
552 }
553
554 for action in &rule.actions {
556 self.execute_action(action, facts)?;
557 }
558
559 let rule_duration = rule_start.elapsed();
560
561 if let Some(analytics) = &mut self.analytics {
563 analytics.record_execution(
564 &rule.name,
565 rule_duration,
566 true,
567 true,
568 None,
569 0,
570 );
571 }
572
573 rules_fired += 1;
574 any_rule_fired = true;
575
576 fired_rules_in_cycle.insert(rule.name.clone());
578
579 if rule.no_loop {
581 self.fired_rules_global.insert(rule.name.clone());
582 if self.config.debug_mode {
583 println!(" 🔒 Marked '{}' as fired (no_loop tracking)", rule.name);
584 }
585 }
586
587 self.agenda_manager.mark_rule_fired(&rule);
589 self.activation_group_manager.mark_fired(&rule);
590 } else {
591 let rule_duration = rule_start.elapsed();
592
593 if let Some(analytics) = &mut self.analytics {
595 analytics.record_execution(
596 &rule.name,
597 rule_duration,
598 false,
599 false,
600 None,
601 0,
602 );
603 }
604 }
605 } }
607
608 if !any_rule_fired {
610 break;
611 }
612
613 self.sync_workflow_agenda_activations();
615 }
616
617 let execution_time = start_time.elapsed();
618
619 Ok(GruleExecutionResult {
620 cycle_count,
621 rules_evaluated,
622 rules_fired,
623 execution_time,
624 })
625 }
626
627 fn evaluate_conditions(
629 &self,
630 conditions: &crate::engine::rule::ConditionGroup,
631 facts: &Facts,
632 ) -> Result<bool> {
633 use crate::engine::pattern_matcher::PatternMatcher;
634 use crate::engine::rule::ConditionGroup;
635
636 match conditions {
637 ConditionGroup::Single(condition) => self.evaluate_single_condition(condition, facts),
638 ConditionGroup::Compound {
639 left,
640 operator,
641 right,
642 } => {
643 let left_result = self.evaluate_conditions(left, facts)?;
644 let right_result = self.evaluate_conditions(right, facts)?;
645
646 match operator {
647 crate::types::LogicalOperator::And => Ok(left_result && right_result),
648 crate::types::LogicalOperator::Or => Ok(left_result || right_result),
649 crate::types::LogicalOperator::Not => Err(RuleEngineError::EvaluationError {
650 message: "NOT operator should not appear in compound conditions"
651 .to_string(),
652 }),
653 }
654 }
655 ConditionGroup::Not(condition) => {
656 let result = self.evaluate_conditions(condition, facts)?;
657 Ok(!result)
658 }
659 ConditionGroup::Exists(condition) => {
661 Ok(PatternMatcher::evaluate_exists(condition, facts))
662 }
663 ConditionGroup::Forall(condition) => {
664 Ok(PatternMatcher::evaluate_forall(condition, facts))
665 }
666 ConditionGroup::Accumulate {
667 result_var,
668 source_pattern,
669 extract_field,
670 source_conditions,
671 function,
672 function_arg,
673 } => {
674 self.evaluate_accumulate(
676 result_var,
677 source_pattern,
678 extract_field,
679 source_conditions,
680 function,
681 function_arg,
682 facts,
683 )?;
684 Ok(true)
686 }
687
688 #[cfg(feature = "streaming")]
689 ConditionGroup::StreamPattern { .. } => {
690 Ok(true)
693 }
694 }
695 }
696
697 #[allow(clippy::too_many_arguments)]
699 fn evaluate_accumulate(
700 &self,
701 _result_var: &str,
702 source_pattern: &str,
703 extract_field: &str,
704 source_conditions: &[String],
705 function: &str,
706 _function_arg: &str,
707 facts: &Facts,
708 ) -> Result<()> {
709 use crate::rete::accumulate::*;
710
711 let all_facts = facts.get_all_facts();
713 let mut matching_values = Vec::new();
714
715 let pattern_prefix = format!("{}.", source_pattern);
717
718 let mut instances: HashMap<String, HashMap<String, Value>> = HashMap::with_capacity(16);
720
721 for (key, value) in &all_facts {
722 if key.starts_with(&pattern_prefix) {
723 let parts: Vec<&str> = key
725 .strip_prefix(&pattern_prefix)
726 .unwrap()
727 .split('.')
728 .collect();
729
730 if parts.len() >= 2 {
731 let instance_id = parts[0];
733 let field_name = parts[1..].join(".");
734
735 instances
736 .entry(instance_id.to_string())
737 .or_default()
738 .insert(field_name, value.clone());
739 } else if parts.len() == 1 {
740 instances
742 .entry("default".to_string())
743 .or_default()
744 .insert(parts[0].to_string(), value.clone());
745 }
746 }
747 }
748
749 for (_instance_id, instance_facts) in instances {
751 let mut matches = true;
753
754 for condition_str in source_conditions {
755 if !self.evaluate_condition_string(condition_str, &instance_facts) {
757 matches = false;
758 break;
759 }
760 }
761
762 if matches {
763 if let Some(value) = instance_facts.get(extract_field) {
765 matching_values.push(value.clone());
766 }
767 }
768 }
769
770 let result = match function {
772 "sum" => {
773 let mut state = SumFunction.init();
774 for value in &matching_values {
775 state.accumulate(&self.value_to_fact_value(value));
776 }
777 self.fact_value_to_value(&state.get_result())
778 }
779 "count" => {
780 let mut state = CountFunction.init();
781 for value in &matching_values {
782 state.accumulate(&self.value_to_fact_value(value));
783 }
784 self.fact_value_to_value(&state.get_result())
785 }
786 "average" | "avg" => {
787 let mut state = AverageFunction.init();
788 for value in &matching_values {
789 state.accumulate(&self.value_to_fact_value(value));
790 }
791 self.fact_value_to_value(&state.get_result())
792 }
793 "min" => {
794 let mut state = MinFunction.init();
795 for value in &matching_values {
796 state.accumulate(&self.value_to_fact_value(value));
797 }
798 self.fact_value_to_value(&state.get_result())
799 }
800 "max" => {
801 let mut state = MaxFunction.init();
802 for value in &matching_values {
803 state.accumulate(&self.value_to_fact_value(value));
804 }
805 self.fact_value_to_value(&state.get_result())
806 }
807 _ => {
808 return Err(RuleEngineError::EvaluationError {
809 message: format!("Unknown accumulate function: {}", function),
810 });
811 }
812 };
813
814 let result_key = format!("{}.{}", source_pattern, function);
817
818 facts.set(&result_key, result);
819
820 if self.config.debug_mode {
821 println!(
822 " 🧮 Accumulate result: {} = {:?}",
823 result_key,
824 facts.get(&result_key)
825 );
826 }
827
828 Ok(())
829 }
830
831 fn value_to_fact_value(&self, value: &Value) -> crate::rete::facts::FactValue {
833 use crate::rete::facts::FactValue;
834 match value {
835 Value::Integer(i) => FactValue::Integer(*i),
836 Value::Number(n) => FactValue::Float(*n),
837 Value::String(s) => FactValue::String(s.clone()),
838 Value::Boolean(b) => FactValue::Boolean(*b),
839 _ => FactValue::String(value.to_string()),
840 }
841 }
842
843 fn fact_value_to_value(&self, fact_value: &crate::rete::facts::FactValue) -> Value {
845 use crate::rete::facts::FactValue;
846 match fact_value {
847 FactValue::Integer(i) => Value::Integer(*i),
848 FactValue::Float(f) => Value::Number(*f),
849 FactValue::String(s) => Value::String(s.clone()),
850 FactValue::Boolean(b) => Value::Boolean(*b),
851 FactValue::Array(_) => Value::String(format!("{:?}", fact_value)),
852 FactValue::Null => Value::String("null".to_string()),
853 }
854 }
855
856 fn evaluate_condition_string(&self, condition: &str, facts: &HashMap<String, Value>) -> bool {
858 let condition = condition.trim();
860
861 let operators = ["==", "!=", ">=", "<=", ">", "<"];
863
864 for op in &operators {
865 if let Some(pos) = condition.find(op) {
866 let field = condition[..pos].trim();
867 let value_str = condition[pos + op.len()..]
868 .trim()
869 .trim_matches('"')
870 .trim_matches('\'');
871
872 if let Some(field_value) = facts.get(field) {
873 return self.compare_values(field_value, op, value_str);
874 } else {
875 return false;
876 }
877 }
878 }
879
880 false
881 }
882
883 fn compare_values(&self, field_value: &Value, operator: &str, value_str: &str) -> bool {
885 match field_value {
886 Value::String(s) => match operator {
887 "==" => s == value_str,
888 "!=" => s != value_str,
889 _ => false,
890 },
891 Value::Integer(i) => {
892 if let Ok(num) = value_str.parse::<i64>() {
893 match operator {
894 "==" => *i == num,
895 "!=" => *i != num,
896 ">" => *i > num,
897 "<" => *i < num,
898 ">=" => *i >= num,
899 "<=" => *i <= num,
900 _ => false,
901 }
902 } else {
903 false
904 }
905 }
906 Value::Number(n) => {
907 if let Ok(num) = value_str.parse::<f64>() {
908 match operator {
909 "==" => (*n - num).abs() < f64::EPSILON,
910 "!=" => (*n - num).abs() >= f64::EPSILON,
911 ">" => *n > num,
912 "<" => *n < num,
913 ">=" => *n >= num,
914 "<=" => *n <= num,
915 _ => false,
916 }
917 } else {
918 false
919 }
920 }
921 Value::Boolean(b) => {
922 if let Ok(bool_val) = value_str.parse::<bool>() {
923 match operator {
924 "==" => *b == bool_val,
925 "!=" => *b != bool_val,
926 _ => false,
927 }
928 } else {
929 false
930 }
931 }
932 _ => false,
933 }
934 }
935
936 fn evaluate_rule_conditions(
938 &self,
939 rule: &crate::engine::rule::Rule,
940 facts: &Facts,
941 ) -> Result<bool> {
942 self.evaluate_conditions(&rule.conditions, facts)
943 }
944
945 fn is_retracted(&self, object_name: &str, facts: &Facts) -> bool {
947 let retract_key = format!("_retracted_{}", object_name);
948 matches!(facts.get(&retract_key), Some(Value::Boolean(true)))
949 }
950
951 fn evaluate_single_condition(
953 &self,
954 condition: &crate::engine::rule::Condition,
955 facts: &Facts,
956 ) -> Result<bool> {
957 use crate::engine::rule::ConditionExpression;
958
959 let result = match &condition.expression {
960 ConditionExpression::Field(field_name) => {
961 if let Some(object_name) = field_name.split('.').next() {
964 if self.is_retracted(object_name, facts) {
965 if self.config.debug_mode {
966 println!(" 🗑️ Skipping retracted fact: {}", object_name);
967 }
968 return Ok(false);
969 }
970 }
971
972 let field_value = facts
975 .get_nested(field_name)
976 .or_else(|| facts.get(field_name))
977 .unwrap_or(Value::Null);
978
979 if self.config.debug_mode {
980 println!(
981 " 🔎 Evaluating field condition: {} {} {:?}",
982 field_name,
983 format!("{:?}", condition.operator).to_lowercase(),
984 condition.value
985 );
986 println!(" Field value: {:?}", field_value);
987 }
988
989 let rhs = match &condition.value {
995 crate::types::Value::String(s) => {
996 facts
998 .get_nested(s)
999 .or_else(|| facts.get(s))
1000 .unwrap_or(crate::types::Value::String(s.clone()))
1001 }
1002 crate::types::Value::Expression(expr) => {
1003 match crate::expression::evaluate_expression(expr, facts) {
1005 Ok(evaluated) => evaluated,
1006 Err(_) => {
1007 facts
1009 .get_nested(expr)
1010 .or_else(|| facts.get(expr))
1011 .unwrap_or(crate::types::Value::Expression(expr.clone()))
1012 }
1013 }
1014 }
1015 _ => condition.value.clone(),
1016 };
1017
1018 if self.config.debug_mode {
1019 println!(" Resolved RHS for comparison: {:?}", rhs);
1020 }
1021
1022 condition.operator.evaluate(&field_value, &rhs)
1023 }
1024 ConditionExpression::FunctionCall { name, args } => {
1025 if self.config.debug_mode {
1027 println!(
1028 " 🔎 Evaluating function condition: {}({:?}) {} {:?}",
1029 name,
1030 args,
1031 format!("{:?}", condition.operator).to_lowercase(),
1032 condition.value
1033 );
1034 }
1035
1036 if let Some(function) = self.custom_functions.get(name) {
1037 let arg_values: Vec<Value> = args
1039 .iter()
1040 .map(|arg| {
1041 facts
1042 .get_nested(arg)
1043 .or_else(|| facts.get(arg))
1044 .unwrap_or(Value::String(arg.clone()))
1045 })
1046 .collect();
1047
1048 match function(&arg_values, facts) {
1050 Ok(result_value) => {
1051 if self.config.debug_mode {
1052 println!(" Function result: {:?}", result_value);
1053 }
1054 condition.operator.evaluate(&result_value, &condition.value)
1055 }
1056 Err(e) => {
1057 if self.config.debug_mode {
1058 println!(" Function error: {}", e);
1059 }
1060 false
1061 }
1062 }
1063 } else {
1064 if self.config.debug_mode {
1065 println!(" Function '{}' not found", name);
1066 }
1067 false
1068 }
1069 }
1070 ConditionExpression::Test { name, args } => {
1071 if self.config.debug_mode {
1073 println!(" 🧪 Evaluating test CE: test({}({:?}))", name, args);
1074 }
1075
1076 if let Some(function) = self.custom_functions.get(name) {
1078 let arg_values: Vec<Value> = args
1080 .iter()
1081 .map(|arg| {
1082 let resolved = facts
1083 .get_nested(arg)
1084 .or_else(|| facts.get(arg))
1085 .unwrap_or(Value::String(arg.clone()));
1086 if self.config.debug_mode {
1087 println!(" Resolving arg '{}' -> {:?}", arg, resolved);
1088 }
1089 resolved
1090 })
1091 .collect();
1092
1093 match function(&arg_values, facts) {
1095 Ok(result_value) => {
1096 if self.config.debug_mode {
1097 println!(" Test result: {:?}", result_value);
1098 }
1099 match result_value {
1101 Value::Boolean(b) => b,
1102 Value::Integer(i) => i != 0,
1103 Value::Number(f) => f != 0.0,
1104 Value::String(s) => !s.is_empty(),
1105 _ => false,
1106 }
1107 }
1108 Err(e) => {
1109 if self.config.debug_mode {
1110 println!(" Test function error: {}", e);
1111 }
1112 false
1113 }
1114 }
1115 } else {
1116 if self.config.debug_mode {
1119 println!(
1120 " Trying to evaluate '{}' as arithmetic expression",
1121 name
1122 );
1123 }
1124
1125 match self.evaluate_arithmetic_condition(name, facts) {
1127 Ok(result) => {
1128 if self.config.debug_mode {
1129 println!(" Arithmetic expression result: {}", result);
1130 }
1131 result
1132 }
1133 Err(e) => {
1134 if self.config.debug_mode {
1135 println!(" Failed to evaluate expression: {}", e);
1136 println!(" Test function '{}' not found", name);
1137 }
1138 false
1139 }
1140 }
1141 }
1142 }
1143 ConditionExpression::MultiField {
1144 field,
1145 operation,
1146 variable: _,
1147 } => {
1148 if self.config.debug_mode {
1150 println!(" 📦 Evaluating multi-field: {}.{}", field, operation);
1151 }
1152
1153 let field_value = facts.get_nested(field).or_else(|| facts.get(field));
1155
1156 if let Some(value) = field_value {
1157 match operation.as_str() {
1158 "empty" => {
1159 matches!(value, Value::Array(arr) if arr.is_empty())
1160 }
1161 "not_empty" => {
1162 matches!(value, Value::Array(arr) if !arr.is_empty())
1163 }
1164 "count" => {
1165 if let Value::Array(arr) = value {
1166 let count = Value::Integer(arr.len() as i64);
1167 condition.operator.evaluate(&count, &condition.value)
1168 } else {
1169 false
1170 }
1171 }
1172 "contains" => {
1173 condition.operator.evaluate(&value, &condition.value)
1175 }
1176 _ => {
1177 if self.config.debug_mode {
1180 println!(
1181 " ⚠️ Operation '{}' not fully implemented yet",
1182 operation
1183 );
1184 }
1185 true
1186 }
1187 }
1188 } else {
1189 false
1190 }
1191 }
1192 };
1193
1194 if self.config.debug_mode {
1195 println!(" Result: {}", result);
1196 }
1197
1198 Ok(result)
1199 }
1200
1201 fn execute_action(&mut self, action: &ActionType, facts: &Facts) -> Result<()> {
1203 match action {
1204 ActionType::Set { field, value } => {
1205 let evaluated_value = match value {
1207 Value::Expression(expr) => {
1208 crate::expression::evaluate_expression(expr, facts)?
1210 }
1211 _ => value.clone(),
1212 };
1213
1214 if facts.set_nested(field, evaluated_value.clone()).is_err() {
1216 facts.set(field, evaluated_value.clone());
1218 }
1219 if self.config.debug_mode {
1220 println!(" ✅ Set {field} = {evaluated_value:?}");
1221 }
1222 }
1223 ActionType::Log { message } => {
1224 println!("📋 LOG: {}", message);
1225 }
1226 ActionType::MethodCall {
1227 object,
1228 method,
1229 args,
1230 } => {
1231 let result = self.execute_method_call(object, method, args, facts)?;
1232 if self.config.debug_mode {
1233 println!(" 🔧 Called {object}.{method}({args:?}) -> {result}");
1234 }
1235 }
1236 ActionType::Retract { object } => {
1237 if self.config.debug_mode {
1238 println!(" 🗑️ Retracted {object}");
1239 }
1240 facts.set(&format!("_retracted_{}", object), Value::Boolean(true));
1242 }
1243 ActionType::Custom {
1244 action_type,
1245 params,
1246 } => {
1247 if let Some(handler) = self.action_handlers.get(action_type) {
1248 if self.config.debug_mode {
1249 println!(
1250 " 🎯 Executing custom action: {action_type} with params: {params:?}"
1251 );
1252 }
1253
1254 let resolved_params = self.resolve_action_parameters(params, facts)?;
1256
1257 handler(&resolved_params, facts)?;
1259 } else {
1260 if self.config.debug_mode {
1261 println!(" ⚠️ No handler registered for custom action: {action_type}");
1262 println!(
1263 " Available handlers: {:?}",
1264 self.action_handlers.keys().collect::<Vec<_>>()
1265 );
1266 }
1267
1268 return Err(RuleEngineError::EvaluationError {
1270 message: format!(
1271 "No action handler registered for '{action_type}'. Use engine.register_action_handler() to add custom action handlers."
1272 ),
1273 });
1274 }
1275 }
1276 ActionType::ActivateAgendaGroup { group } => {
1278 if self.config.debug_mode {
1279 println!(" 🎯 Activating agenda group: {}", group);
1280 }
1281 self.workflow_engine.activate_agenda_group(group.clone());
1283 self.agenda_manager.set_focus(group);
1284 }
1285 ActionType::ScheduleRule {
1286 rule_name,
1287 delay_ms,
1288 } => {
1289 if self.config.debug_mode {
1290 println!(
1291 " ⏰ Scheduling rule '{}' to execute in {}ms",
1292 rule_name, delay_ms
1293 );
1294 }
1295 self.workflow_engine
1296 .schedule_rule(rule_name.clone(), *delay_ms, None);
1297 }
1298 ActionType::CompleteWorkflow { workflow_name } => {
1299 if self.config.debug_mode {
1300 println!(" ✅ Completing workflow: {}", workflow_name);
1301 }
1302 self.workflow_engine
1303 .complete_workflow(workflow_name.clone());
1304 }
1305 ActionType::SetWorkflowData { key, value } => {
1306 if self.config.debug_mode {
1307 println!(" 💾 Setting workflow data: {} = {:?}", key, value);
1308 }
1309 let workflow_id = "default_workflow";
1312 self.workflow_engine
1313 .set_workflow_data(workflow_id, key.clone(), value.clone());
1314 }
1315 ActionType::Append { field, value } => {
1316 let evaluated_value = match value {
1318 Value::Expression(expr) => crate::expression::evaluate_expression(expr, facts)?,
1319 _ => value.clone(),
1320 };
1321
1322 let current_value = facts.get(field);
1324 let mut array = match current_value {
1325 Some(Value::Array(arr)) => arr.clone(),
1326 Some(_) => {
1327 if self.config.debug_mode {
1329 println!(" ⚠️ Field {} is not an array, creating new array", field);
1330 }
1331 Vec::new()
1332 }
1333 None => Vec::new(),
1334 };
1335
1336 array.push(evaluated_value.clone());
1338
1339 if facts
1341 .set_nested(field, Value::Array(array.clone()))
1342 .is_err()
1343 {
1344 facts.set(field, Value::Array(array.clone()));
1345 }
1346
1347 if self.config.debug_mode {
1348 println!(" ➕ Appended to {}: {:?}", field, evaluated_value);
1349 }
1350 }
1351 }
1352 Ok(())
1353 }
1354
1355 fn evaluate_arithmetic_condition(&self, expr: &str, facts: &Facts) -> Result<bool> {
1357 let operators = [">=", "<=", "==", "!=", ">", "<"];
1361 let mut split_pos = None;
1362 let mut found_op = "";
1363
1364 for op in &operators {
1365 if let Some(pos) = expr.rfind(op) {
1366 split_pos = Some(pos);
1367 found_op = op;
1368 break;
1369 }
1370 }
1371
1372 if split_pos.is_none() {
1373 return Err(RuleEngineError::EvaluationError {
1374 message: format!("No comparison operator found in expression: {}", expr),
1375 });
1376 }
1377
1378 let pos = split_pos.unwrap();
1379 let left_expr = expr[..pos].trim();
1380 let right_value = expr[pos + found_op.len()..].trim();
1381
1382 let left_result = crate::expression::evaluate_expression(left_expr, facts)?;
1384
1385 let right_val = if let Ok(i) = right_value.parse::<i64>() {
1387 Value::Integer(i)
1388 } else if let Ok(f) = right_value.parse::<f64>() {
1389 Value::Number(f)
1390 } else {
1391 match crate::expression::evaluate_expression(right_value, facts) {
1393 Ok(v) => v,
1394 Err(_) => Value::String(right_value.to_string()),
1395 }
1396 };
1397
1398 let operator =
1400 Operator::from_str(found_op).ok_or_else(|| RuleEngineError::InvalidOperator {
1401 operator: found_op.to_string(),
1402 })?;
1403
1404 Ok(operator.evaluate(&left_result, &right_val))
1405 }
1406
1407 fn execute_function_call(
1409 &self,
1410 function: &str,
1411 args: &[Value],
1412 facts: &Facts,
1413 ) -> Result<String> {
1414 let function_lower = function.to_lowercase();
1415
1416 match function_lower.as_str() {
1418 "log" | "print" | "println" => self.handle_log_function(args),
1419 "update" | "refresh" => self.handle_update_function(args),
1420 "now" | "timestamp" => self.handle_timestamp_function(),
1421 "random" => self.handle_random_function(args),
1422 "format" | "sprintf" => self.handle_format_function(args),
1423 "length" | "size" | "count" => self.handle_length_function(args),
1424 "sum" | "add" => self.handle_sum_function(args),
1425 "max" | "maximum" => self.handle_max_function(args),
1426 "min" | "minimum" => self.handle_min_function(args),
1427 "avg" | "average" => self.handle_average_function(args),
1428 "round" => self.handle_round_function(args),
1429 "floor" => self.handle_floor_function(args),
1430 "ceil" | "ceiling" => self.handle_ceil_function(args),
1431 "abs" | "absolute" => self.handle_abs_function(args),
1432 "contains" | "includes" => self.handle_contains_function(args),
1433 "startswith" | "begins_with" => self.handle_starts_with_function(args),
1434 "endswith" | "ends_with" => self.handle_ends_with_function(args),
1435 "lowercase" | "tolower" => self.handle_lowercase_function(args),
1436 "uppercase" | "toupper" => self.handle_uppercase_function(args),
1437 "trim" | "strip" => self.handle_trim_function(args),
1438 "split" => self.handle_split_function(args),
1439 "join" => self.handle_join_function(args),
1440 _ => {
1441 self.handle_custom_function(function, args, facts)
1443 }
1444 }
1445 }
1446
1447 fn handle_log_function(&self, args: &[Value]) -> Result<String> {
1449 let message = if args.is_empty() {
1450 "".to_string()
1451 } else if args.len() == 1 {
1452 args[0].to_string()
1453 } else {
1454 args.iter()
1455 .map(|v| v.to_string())
1456 .collect::<Vec<_>>()
1457 .join(" ")
1458 };
1459
1460 info!("📋 {}", message);
1461 Ok(message)
1462 }
1463
1464 fn handle_update_function(&self, args: &[Value]) -> Result<String> {
1466 if let Some(arg) = args.first() {
1467 Ok(format!("Updated: {}", arg.to_string()))
1468 } else {
1469 Ok("Updated".to_string())
1470 }
1471 }
1472
1473 fn handle_timestamp_function(&self) -> Result<String> {
1475 use std::time::{SystemTime, UNIX_EPOCH};
1476 let timestamp = SystemTime::now()
1477 .duration_since(UNIX_EPOCH)
1478 .map_err(|e| RuleEngineError::EvaluationError {
1479 message: format!("Failed to get timestamp: {}", e),
1480 })?
1481 .as_secs();
1482 Ok(timestamp.to_string())
1483 }
1484
1485 fn handle_random_function(&self, args: &[Value]) -> Result<String> {
1487 use std::collections::hash_map::DefaultHasher;
1488 use std::hash::{Hash, Hasher};
1489
1490 let mut hasher = DefaultHasher::new();
1492 std::time::SystemTime::now().hash(&mut hasher);
1493 let random_value = hasher.finish();
1494
1495 if args.is_empty() {
1496 Ok((random_value % 100).to_string()) } else if let Some(Value::Number(max)) = args.first() {
1498 let max_val = *max as u64;
1499 Ok((random_value % max_val).to_string())
1500 } else {
1501 Ok(random_value.to_string())
1502 }
1503 }
1504
1505 fn handle_format_function(&self, args: &[Value]) -> Result<String> {
1507 if args.is_empty() {
1508 return Ok("".to_string());
1509 }
1510
1511 let template = args[0].to_string();
1512 let values: Vec<String> = args[1..].iter().map(|v| v.to_string()).collect();
1513
1514 let mut result = template;
1516 for (i, value) in values.iter().enumerate() {
1517 result = result.replace(&format!("{{{}}}", i), value);
1518 }
1519
1520 Ok(result)
1521 }
1522
1523 fn handle_length_function(&self, args: &[Value]) -> Result<String> {
1525 if let Some(arg) = args.first() {
1526 match arg {
1527 Value::String(s) => Ok(s.len().to_string()),
1528 Value::Array(arr) => Ok(arr.len().to_string()),
1529 Value::Object(obj) => Ok(obj.len().to_string()),
1530 _ => Ok("1".to_string()), }
1532 } else {
1533 Ok("0".to_string())
1534 }
1535 }
1536
1537 fn handle_sum_function(&self, args: &[Value]) -> Result<String> {
1539 let sum = args.iter().fold(0.0, |acc, val| match val {
1540 Value::Number(n) => acc + n,
1541 Value::Integer(i) => acc + (*i as f64),
1542 _ => acc,
1543 });
1544 Ok(sum.to_string())
1545 }
1546
1547 fn handle_max_function(&self, args: &[Value]) -> Result<String> {
1549 let max = args.iter().fold(f64::NEG_INFINITY, |acc, val| match val {
1550 Value::Number(n) => acc.max(*n),
1551 Value::Integer(i) => acc.max(*i as f64),
1552 _ => acc,
1553 });
1554 Ok(max.to_string())
1555 }
1556
1557 fn handle_min_function(&self, args: &[Value]) -> Result<String> {
1559 let min = args.iter().fold(f64::INFINITY, |acc, val| match val {
1560 Value::Number(n) => acc.min(*n),
1561 Value::Integer(i) => acc.min(*i as f64),
1562 _ => acc,
1563 });
1564 Ok(min.to_string())
1565 }
1566
1567 fn handle_average_function(&self, args: &[Value]) -> Result<String> {
1569 if args.is_empty() {
1570 return Ok("0".to_string());
1571 }
1572
1573 let (sum, count) = args.iter().fold((0.0, 0), |(sum, count), val| match val {
1574 Value::Number(n) => (sum + n, count + 1),
1575 Value::Integer(i) => (sum + (*i as f64), count + 1),
1576 _ => (sum, count),
1577 });
1578
1579 if count > 0 {
1580 Ok((sum / count as f64).to_string())
1581 } else {
1582 Ok("0".to_string())
1583 }
1584 }
1585
1586 fn handle_round_function(&self, args: &[Value]) -> Result<String> {
1588 if let Some(Value::Number(n)) = args.first() {
1589 Ok(n.round().to_string())
1590 } else if let Some(Value::Integer(i)) = args.first() {
1591 Ok(i.to_string())
1592 } else {
1593 Err(RuleEngineError::EvaluationError {
1594 message: "round() requires a numeric argument".to_string(),
1595 })
1596 }
1597 }
1598
1599 fn handle_floor_function(&self, args: &[Value]) -> Result<String> {
1600 if let Some(Value::Number(n)) = args.first() {
1601 Ok(n.floor().to_string())
1602 } else if let Some(Value::Integer(i)) = args.first() {
1603 Ok(i.to_string())
1604 } else {
1605 Err(RuleEngineError::EvaluationError {
1606 message: "floor() requires a numeric argument".to_string(),
1607 })
1608 }
1609 }
1610
1611 fn handle_ceil_function(&self, args: &[Value]) -> Result<String> {
1612 if let Some(Value::Number(n)) = args.first() {
1613 Ok(n.ceil().to_string())
1614 } else if let Some(Value::Integer(i)) = args.first() {
1615 Ok(i.to_string())
1616 } else {
1617 Err(RuleEngineError::EvaluationError {
1618 message: "ceil() requires a numeric argument".to_string(),
1619 })
1620 }
1621 }
1622
1623 fn handle_abs_function(&self, args: &[Value]) -> Result<String> {
1624 if let Some(Value::Number(n)) = args.first() {
1625 Ok(n.abs().to_string())
1626 } else if let Some(Value::Integer(i)) = args.first() {
1627 Ok(i.abs().to_string())
1628 } else {
1629 Err(RuleEngineError::EvaluationError {
1630 message: "abs() requires a numeric argument".to_string(),
1631 })
1632 }
1633 }
1634
1635 fn handle_contains_function(&self, args: &[Value]) -> Result<String> {
1637 if args.len() >= 2 {
1638 let haystack = args[0].to_string();
1639 let needle = args[1].to_string();
1640 Ok(haystack.contains(&needle).to_string())
1641 } else {
1642 Err(RuleEngineError::EvaluationError {
1643 message: "contains() requires 2 arguments".to_string(),
1644 })
1645 }
1646 }
1647
1648 fn handle_starts_with_function(&self, args: &[Value]) -> Result<String> {
1649 if args.len() >= 2 {
1650 let text = args[0].to_string();
1651 let prefix = args[1].to_string();
1652 Ok(text.starts_with(&prefix).to_string())
1653 } else {
1654 Err(RuleEngineError::EvaluationError {
1655 message: "startswith() requires 2 arguments".to_string(),
1656 })
1657 }
1658 }
1659
1660 fn handle_ends_with_function(&self, args: &[Value]) -> Result<String> {
1661 if args.len() >= 2 {
1662 let text = args[0].to_string();
1663 let suffix = args[1].to_string();
1664 Ok(text.ends_with(&suffix).to_string())
1665 } else {
1666 Err(RuleEngineError::EvaluationError {
1667 message: "endswith() requires 2 arguments".to_string(),
1668 })
1669 }
1670 }
1671
1672 fn handle_lowercase_function(&self, args: &[Value]) -> Result<String> {
1673 if let Some(arg) = args.first() {
1674 Ok(arg.to_string().to_lowercase())
1675 } else {
1676 Err(RuleEngineError::EvaluationError {
1677 message: "lowercase() requires 1 argument".to_string(),
1678 })
1679 }
1680 }
1681
1682 fn handle_uppercase_function(&self, args: &[Value]) -> Result<String> {
1683 if let Some(arg) = args.first() {
1684 Ok(arg.to_string().to_uppercase())
1685 } else {
1686 Err(RuleEngineError::EvaluationError {
1687 message: "uppercase() requires 1 argument".to_string(),
1688 })
1689 }
1690 }
1691
1692 fn handle_trim_function(&self, args: &[Value]) -> Result<String> {
1693 if let Some(arg) = args.first() {
1694 Ok(arg.to_string().trim().to_string())
1695 } else {
1696 Err(RuleEngineError::EvaluationError {
1697 message: "trim() requires 1 argument".to_string(),
1698 })
1699 }
1700 }
1701
1702 fn handle_split_function(&self, args: &[Value]) -> Result<String> {
1703 if args.len() >= 2 {
1704 let text = args[0].to_string();
1705 let delimiter = args[1].to_string();
1706 let parts: Vec<String> = text.split(&delimiter).map(|s| s.to_string()).collect();
1707 Ok(format!("{:?}", parts)) } else {
1709 Err(RuleEngineError::EvaluationError {
1710 message: "split() requires 2 arguments".to_string(),
1711 })
1712 }
1713 }
1714
1715 fn handle_join_function(&self, args: &[Value]) -> Result<String> {
1716 if args.len() >= 2 {
1717 let delimiter = args[0].to_string();
1718 let parts: Vec<String> = args[1..].iter().map(|v| v.to_string()).collect();
1719 Ok(parts.join(&delimiter))
1720 } else {
1721 Err(RuleEngineError::EvaluationError {
1722 message: "join() requires at least 2 arguments".to_string(),
1723 })
1724 }
1725 }
1726
1727 fn handle_custom_function(
1729 &self,
1730 function: &str,
1731 args: &[Value],
1732 facts: &Facts,
1733 ) -> Result<String> {
1734 if let Some(custom_func) = self.custom_functions.get(function) {
1736 if self.config.debug_mode {
1737 println!("🎯 Calling registered function: {}({:?})", function, args);
1738 }
1739
1740 match custom_func(args, facts) {
1741 Ok(result) => Ok(result.to_string()),
1742 Err(e) => Err(e),
1743 }
1744 } else {
1745 if self.config.debug_mode {
1747 println!("⚠️ Custom function '{}' not registered", function);
1748 }
1749
1750 Err(RuleEngineError::EvaluationError {
1751 message: format!("Function '{}' is not registered. Use engine.register_function() to add custom functions.", function),
1752 })
1753 }
1754 }
1755
1756 fn execute_method_call(
1758 &self,
1759 object_name: &str,
1760 method: &str,
1761 args: &[Value],
1762 facts: &Facts,
1763 ) -> Result<String> {
1764 let Some(object_value) = facts.get(object_name) else {
1766 return Err(RuleEngineError::EvaluationError {
1767 message: format!("Object '{}' not found in facts", object_name),
1768 });
1769 };
1770
1771 let method_lower = method.to_lowercase();
1772
1773 if method_lower.starts_with("set") && args.len() == 1 {
1775 return self.handle_setter_method(object_name, method, &args[0], object_value, facts);
1776 }
1777
1778 if method_lower.starts_with("get") && args.is_empty() {
1780 return self.handle_getter_method(object_name, method, &object_value);
1781 }
1782
1783 match method_lower.as_str() {
1785 "tostring" => Ok(object_value.to_string()),
1786 "update" => {
1787 facts.add_value(object_name, object_value)?;
1788 Ok(format!("Updated {}", object_name))
1789 }
1790 "reset" => self.handle_reset_method(object_name, object_value, facts),
1791 _ => self.handle_property_access_or_fallback(
1792 object_name,
1793 method,
1794 args.len(),
1795 &object_value,
1796 ),
1797 }
1798 }
1799
1800 fn handle_setter_method(
1802 &self,
1803 object_name: &str,
1804 method: &str,
1805 new_value: &Value,
1806 mut object_value: Value,
1807 facts: &Facts,
1808 ) -> Result<String> {
1809 let property_name = Self::extract_property_name_from_setter(method);
1810
1811 match object_value {
1812 Value::Object(ref mut obj) => {
1813 obj.insert(property_name.clone(), new_value.clone());
1814 facts.add_value(object_name, object_value)?;
1815 Ok(format!(
1816 "Set {} to {}",
1817 property_name,
1818 new_value.to_string()
1819 ))
1820 }
1821 _ => Err(RuleEngineError::EvaluationError {
1822 message: format!("Cannot call setter on non-object type: {}", object_name),
1823 }),
1824 }
1825 }
1826
1827 fn handle_getter_method(
1829 &self,
1830 object_name: &str,
1831 method: &str,
1832 object_value: &Value,
1833 ) -> Result<String> {
1834 let property_name = Self::extract_property_name_from_getter(method);
1835
1836 match object_value {
1837 Value::Object(obj) => {
1838 if let Some(value) = obj.get(&property_name) {
1839 Ok(value.to_string())
1840 } else {
1841 Err(RuleEngineError::EvaluationError {
1842 message: format!(
1843 "Property '{}' not found on object '{}'",
1844 property_name, object_name
1845 ),
1846 })
1847 }
1848 }
1849 _ => Err(RuleEngineError::EvaluationError {
1850 message: format!("Cannot call getter on non-object type: {}", object_name),
1851 }),
1852 }
1853 }
1854
1855 fn handle_reset_method(
1857 &self,
1858 object_name: &str,
1859 mut object_value: Value,
1860 facts: &Facts,
1861 ) -> Result<String> {
1862 match object_value {
1863 Value::Object(ref mut obj) => {
1864 obj.clear();
1865 facts.add_value(object_name, object_value)?;
1866 Ok(format!("Reset {}", object_name))
1867 }
1868 _ => Err(RuleEngineError::EvaluationError {
1869 message: format!("Cannot reset non-object type: {}", object_name),
1870 }),
1871 }
1872 }
1873
1874 fn handle_property_access_or_fallback(
1876 &self,
1877 object_name: &str,
1878 method: &str,
1879 arg_count: usize,
1880 object_value: &Value,
1881 ) -> Result<String> {
1882 if let Value::Object(obj) = object_value {
1883 if let Some(value) = obj.get(method) {
1885 return Ok(value.to_string());
1886 }
1887
1888 let capitalized_method = Self::capitalize_first_letter(method);
1890 if let Some(value) = obj.get(&capitalized_method) {
1891 return Ok(value.to_string());
1892 }
1893 }
1894
1895 Ok(format!(
1897 "Called {}.{} with {} args",
1898 object_name, method, arg_count
1899 ))
1900 }
1901
1902 fn extract_property_name_from_setter(method: &str) -> String {
1904 let property_name = &method[3..]; Self::capitalize_first_letter(property_name)
1906 }
1907
1908 fn extract_property_name_from_getter(method: &str) -> String {
1910 let property_name = &method[3..]; Self::capitalize_first_letter(property_name)
1912 }
1913
1914 fn capitalize_first_letter(s: &str) -> String {
1916 if s.is_empty() {
1917 return String::new();
1918 }
1919 let mut chars = s.chars();
1920 match chars.next() {
1921 None => String::new(),
1922 Some(first) => first.to_uppercase().collect::<String>() + chars.as_str(),
1923 }
1924 }
1925
1926 fn resolve_action_parameters(
1928 &self,
1929 params: &HashMap<String, Value>,
1930 facts: &Facts,
1931 ) -> Result<HashMap<String, Value>> {
1932 let mut resolved = HashMap::new();
1933
1934 for (key, value) in params {
1935 let resolved_value = match value {
1936 Value::String(s) => {
1937 if s.contains('.') {
1939 if let Some(fact_value) = facts.get_nested(s) {
1941 fact_value
1942 } else {
1943 value.clone()
1945 }
1946 } else {
1947 value.clone()
1948 }
1949 }
1950 _ => value.clone(),
1951 };
1952 resolved.insert(key.clone(), resolved_value);
1953 }
1954
1955 Ok(resolved)
1956 }
1957
1958 pub fn load_plugin(
1962 &mut self,
1963 plugin: std::sync::Arc<dyn crate::engine::plugin::RulePlugin>,
1964 ) -> Result<()> {
1965 plugin.register_actions(self)?;
1967 plugin.register_functions(self)?;
1968
1969 self.plugin_manager.load_plugin(plugin)
1971 }
1972
1973 pub fn unload_plugin(&mut self, name: &str) -> Result<()> {
1975 self.plugin_manager.unload_plugin(name)
1976 }
1977
1978 pub fn hot_reload_plugin(
1980 &mut self,
1981 name: &str,
1982 new_plugin: std::sync::Arc<dyn crate::engine::plugin::RulePlugin>,
1983 ) -> Result<()> {
1984 self.plugin_manager.unload_plugin(name)?;
1986
1987 new_plugin.register_actions(self)?;
1989 new_plugin.register_functions(self)?;
1990
1991 self.plugin_manager.load_plugin(new_plugin)
1993 }
1994
1995 pub fn get_plugin_info(&self, name: &str) -> Option<&crate::engine::plugin::PluginMetadata> {
1997 self.plugin_manager.get_plugin_info(name)
1998 }
1999
2000 pub fn list_plugins(&self) -> Vec<PluginInfo> {
2002 self.plugin_manager.list_plugins()
2003 }
2004
2005 pub fn get_plugin_stats(&self) -> PluginStats {
2007 self.plugin_manager.get_stats()
2008 }
2009
2010 pub fn plugin_health_check(&mut self) -> HashMap<String, crate::engine::plugin::PluginHealth> {
2012 self.plugin_manager.plugin_health_check()
2013 }
2014
2015 pub fn configure_plugins(&mut self, config: PluginConfig) {
2017 self.plugin_manager = PluginManager::new(config);
2018 }
2019}