1use crate::engine::{
2 agenda::{ActivationGroupManager, AgendaManager},
3 analytics::RuleAnalytics,
4 facts::Facts,
5 knowledge_base::KnowledgeBase,
6 plugin::{PluginConfig, PluginInfo, PluginManager, PluginStats},
7 workflow::WorkflowEngine,
8};
9use crate::errors::{Result, RuleEngineError};
10use crate::types::{ActionType, Operator, Value};
11use chrono::{DateTime, Utc};
12use std::collections::HashMap;
13use std::time::{Duration, Instant};
14
15pub type CustomFunction = Box<dyn Fn(&[Value], &Facts) -> Result<Value> + Send + Sync>;
17
18pub type ActionHandler = Box<dyn Fn(&HashMap<String, Value>, &Facts) -> Result<()> + Send + Sync>;
20
21#[derive(Debug, Clone)]
23pub struct EngineConfig {
24 pub max_cycles: usize,
26 pub timeout: Option<Duration>,
28 pub enable_stats: bool,
30 pub debug_mode: bool,
32}
33
34impl Default for EngineConfig {
35 fn default() -> Self {
36 Self {
37 max_cycles: 100,
38 timeout: Some(Duration::from_secs(30)),
39 enable_stats: true,
40 debug_mode: false,
41 }
42 }
43}
44
45#[derive(Debug, Clone)]
47pub struct GruleExecutionResult {
48 pub cycle_count: usize,
50 pub rules_evaluated: usize,
52 pub rules_fired: usize,
54 pub execution_time: Duration,
56}
57
58pub struct RustRuleEngine {
60 knowledge_base: KnowledgeBase,
61 config: EngineConfig,
62 custom_functions: HashMap<String, CustomFunction>,
63 action_handlers: HashMap<String, ActionHandler>,
64 analytics: Option<RuleAnalytics>,
65 agenda_manager: AgendaManager,
66 activation_group_manager: ActivationGroupManager,
67 fired_rules_global: std::collections::HashSet<String>,
69 workflow_engine: WorkflowEngine,
71 plugin_manager: PluginManager,
73}
74
75#[allow(dead_code)]
76impl RustRuleEngine {
77 pub fn execute_with_callback<F>(
79 &mut self,
80 facts: &Facts,
81 mut on_rule_fired: F,
82 ) -> Result<GruleExecutionResult>
83 where
84 F: FnMut(&str, &Facts),
85 {
86 use chrono::Utc;
87 let timestamp = Utc::now();
88 let start_time = std::time::Instant::now();
89 let mut cycle_count = 0;
90 let mut rules_evaluated = 0;
91 let mut rules_fired = 0;
92
93 self.sync_workflow_agenda_activations();
94
95 for cycle in 0..self.config.max_cycles {
96 cycle_count = cycle + 1;
97 let mut any_rule_fired = false;
98 let mut fired_rules_in_cycle = std::collections::HashSet::new();
99 self.activation_group_manager.reset_cycle();
100
101 if let Some(timeout) = self.config.timeout {
102 if start_time.elapsed() > timeout {
103 return Err(crate::errors::RuleEngineError::EvaluationError {
104 message: "Execution timeout exceeded".to_string(),
105 });
106 }
107 }
108
109 let mut rules = self.knowledge_base.get_rules().clone();
110 rules.sort_by(|a, b| b.salience.cmp(&a.salience));
111 let rules: Vec<_> = rules
112 .iter()
113 .filter(|rule| self.agenda_manager.should_evaluate_rule(rule))
114 .collect();
115
116 for rule in &rules {
117 if !rule.enabled {
118 continue;
119 }
120 if !rule.is_active_at(timestamp) {
121 continue;
122 }
123 if !self.agenda_manager.can_fire_rule(rule) {
124 continue;
125 }
126 if !self.activation_group_manager.can_fire(rule) {
127 continue;
128 }
129 if rule.no_loop && self.fired_rules_global.contains(&rule.name) {
130 continue;
131 }
132 rules_evaluated += 1;
133 let condition_result = self.evaluate_conditions(&rule.conditions, facts)?;
134 if condition_result {
135 for action in &rule.actions {
136 self.execute_action(action, facts)?;
137 }
138 rules_fired += 1;
139 any_rule_fired = true;
140 fired_rules_in_cycle.insert(rule.name.clone());
141 if rule.no_loop {
142 self.fired_rules_global.insert(rule.name.clone());
143 }
144 self.agenda_manager.mark_rule_fired(rule);
145 self.activation_group_manager.mark_fired(rule);
146 on_rule_fired(&rule.name, facts);
148 }
149 }
150 if !any_rule_fired {
151 break;
152 }
153 self.sync_workflow_agenda_activations();
154 }
155 let execution_time = start_time.elapsed();
156 Ok(crate::engine::GruleExecutionResult {
157 cycle_count,
158 rules_evaluated,
159 rules_fired,
160 execution_time,
161 })
162 }
163 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
258 .knowledge_base
259 .get_rules()
260 .iter()
261 .find(|r| r.name == task.rule_name)
262 {
263 if self.config.debug_mode {
264 println!("⚡ Executing scheduled task: {}", task.rule_name);
265 }
266
267 if self.evaluate_conditions(&rule.conditions, facts)? {
269 for action in &rule.actions {
270 self.execute_action(action, facts)?;
271 }
272 }
273 }
274 }
275 Ok(())
276 }
277
278 pub fn activate_agenda_group(&mut self, group: String) {
280 self.workflow_engine.activate_agenda_group(group.clone());
281 self.agenda_manager.set_focus(&group);
282 }
283
284 pub fn knowledge_base(&self) -> &KnowledgeBase {
286 &self.knowledge_base
287 }
288
289 pub fn knowledge_base_mut(&mut self) -> &mut KnowledgeBase {
291 &mut self.knowledge_base
292 }
293
294 fn sync_workflow_agenda_activations(&mut self) {
296 while let Some(agenda_group) = self.workflow_engine.get_next_pending_agenda_activation() {
298 if self.config.debug_mode {
299 println!("🔄 Syncing workflow agenda activation: {}", agenda_group);
300 }
301 self.agenda_manager.set_focus(&agenda_group);
302 }
303 }
304
305 pub fn set_agenda_focus(&mut self, group: &str) {
307 self.agenda_manager.set_focus(group);
308 }
309
310 pub fn get_active_agenda_group(&self) -> &str {
312 self.agenda_manager.get_active_group()
313 }
314
315 pub fn pop_agenda_focus(&mut self) -> Option<String> {
317 self.agenda_manager.pop_focus()
318 }
319
320 pub fn clear_agenda_focus(&mut self) {
322 self.agenda_manager.clear_focus();
323 }
324
325 pub fn get_agenda_groups(&self) -> Vec<String> {
327 self.agenda_manager
328 .get_agenda_groups(&self.knowledge_base.get_rules())
329 }
330
331 pub fn get_activation_groups(&self) -> Vec<String> {
333 self.activation_group_manager
334 .get_activation_groups(&self.knowledge_base.get_rules())
335 }
336
337 pub fn start_workflow(&mut self, workflow_name: Option<String>) -> String {
341 self.workflow_engine.start_workflow(workflow_name)
342 }
343
344 pub fn get_workflow_stats(&self) -> crate::engine::workflow::WorkflowStats {
346 self.workflow_engine.get_workflow_stats()
347 }
348
349 pub fn get_workflow(
351 &self,
352 workflow_id: &str,
353 ) -> Option<&crate::engine::workflow::WorkflowState> {
354 self.workflow_engine.get_workflow(workflow_id)
355 }
356
357 pub fn cleanup_completed_workflows(&mut self, older_than: Duration) {
359 self.workflow_engine.cleanup_completed_workflows(older_than);
360 }
361
362 pub fn execute_workflow_step(
364 &mut self,
365 agenda_group: &str,
366 facts: &Facts,
367 ) -> Result<GruleExecutionResult> {
368 self.set_agenda_focus(agenda_group);
370
371 let result = self.execute(facts)?;
373
374 self.process_workflow_actions(facts)?;
376
377 Ok(result)
378 }
379
380 pub fn execute_workflow(
382 &mut self,
383 agenda_groups: Vec<&str>,
384 facts: &Facts,
385 ) -> Result<crate::engine::workflow::WorkflowResult> {
386 let start_time = Instant::now();
387 let mut total_steps = 0;
388
389 if self.config.debug_mode {
390 println!(
391 "🔄 Starting workflow execution with {} steps",
392 agenda_groups.len()
393 );
394 }
395
396 for (i, group) in agenda_groups.iter().enumerate() {
397 if self.config.debug_mode {
398 println!("📋 Executing workflow step {}: {}", i + 1, group);
399 }
400
401 let step_result = self.execute_workflow_step(group, facts)?;
402 total_steps += 1;
403
404 if step_result.rules_fired == 0 {
405 if self.config.debug_mode {
406 println!("⏸️ No rules fired in step '{}', stopping workflow", group);
407 }
408 break;
409 }
410 }
411
412 let execution_time = start_time.elapsed();
413
414 Ok(crate::engine::workflow::WorkflowResult::success(
415 total_steps,
416 execution_time,
417 ))
418 }
419
420 fn process_workflow_actions(&mut self, facts: &Facts) -> Result<()> {
422 while let Some(group) = self.workflow_engine.get_next_agenda_group() {
424 self.set_agenda_focus(&group);
425 }
426
427 let ready_tasks = self.workflow_engine.get_ready_tasks();
429 for task in ready_tasks {
430 if self.config.debug_mode {
431 println!("⚡ Executing scheduled task: {}", task.rule_name);
432 }
433
434 if let Some(rule) = self
436 .knowledge_base
437 .get_rules()
438 .iter()
439 .find(|r| r.name == task.rule_name)
440 {
441 if self.evaluate_conditions(&rule.conditions, facts)? {
443 for action in &rule.actions {
444 self.execute_action(action, facts)?;
445 }
446 }
447 }
448 }
449
450 Ok(())
451 }
452
453 pub fn execute(&mut self, facts: &Facts) -> Result<GruleExecutionResult> {
455 self.execute_at_time(facts, Utc::now())
456 }
457
458 pub fn execute_at_time(
460 &mut self,
461 facts: &Facts,
462 timestamp: DateTime<Utc>,
463 ) -> Result<GruleExecutionResult> {
464 let start_time = Instant::now();
465 let mut cycle_count = 0;
466 let mut rules_evaluated = 0;
467 let mut rules_fired = 0;
468
469 self.sync_workflow_agenda_activations();
471
472 if self.config.debug_mode {
473 println!(
474 "🚀 Starting rule execution with {} rules (agenda group: {})",
475 self.knowledge_base.get_rules().len(),
476 self.agenda_manager.get_active_group()
477 );
478 }
479
480 for cycle in 0..self.config.max_cycles {
481 cycle_count = cycle + 1;
482 let mut any_rule_fired = false;
483 let mut fired_rules_in_cycle = std::collections::HashSet::new();
484
485 self.activation_group_manager.reset_cycle();
487
488 if let Some(timeout) = self.config.timeout {
490 if start_time.elapsed() > timeout {
491 return Err(RuleEngineError::EvaluationError {
492 message: "Execution timeout exceeded".to_string(),
493 });
494 }
495 }
496
497 let mut rules = self.knowledge_base.get_rules().clone();
499 rules.sort_by(|a, b| b.salience.cmp(&a.salience));
500
501 let rules: Vec<_> = rules
503 .iter()
504 .filter(|rule| self.agenda_manager.should_evaluate_rule(rule))
505 .collect();
506
507 for rule in &rules {
508 if !rule.enabled {
509 continue;
510 }
511
512 if !rule.is_active_at(timestamp) {
514 continue;
515 }
516
517 if !self.agenda_manager.can_fire_rule(rule) {
519 continue;
520 }
521
522 if !self.activation_group_manager.can_fire(rule) {
524 continue;
525 }
526
527 if rule.no_loop && self.fired_rules_global.contains(&rule.name) {
529 if self.config.debug_mode {
530 println!("⛔ Skipping '{}' due to no_loop (already fired)", rule.name);
531 }
532 continue;
533 }
534
535 rules_evaluated += 1;
536 let rule_start = Instant::now();
537
538 if self.config.debug_mode {
539 println!(
540 "📝 Evaluating rule: {} (no_loop={})",
541 rule.name, rule.no_loop
542 );
543 }
544
545 let condition_result = self.evaluate_conditions(&rule.conditions, facts)?;
547 if self.config.debug_mode {
548 println!(
549 " 🔍 Condition result for '{}': {}",
550 rule.name, condition_result
551 );
552 }
553
554 if condition_result {
555 if self.config.debug_mode {
556 println!(
557 "🔥 Rule '{}' fired (salience: {})",
558 rule.name, rule.salience
559 );
560 }
561
562 for action in &rule.actions {
564 self.execute_action(action, facts)?;
565 }
566
567 let rule_duration = rule_start.elapsed();
568
569 if let Some(analytics) = &mut self.analytics {
571 analytics.record_execution(&rule.name, rule_duration, true, true, None, 0);
572 }
573
574 rules_fired += 1;
575 any_rule_fired = true;
576
577 fired_rules_in_cycle.insert(rule.name.clone());
579
580 if rule.no_loop {
582 self.fired_rules_global.insert(rule.name.clone());
583 if self.config.debug_mode {
584 println!(" 🔒 Marked '{}' as fired (no_loop tracking)", rule.name);
585 }
586 }
587
588 self.agenda_manager.mark_rule_fired(rule);
590 self.activation_group_manager.mark_fired(rule);
591 } else {
592 let rule_duration = rule_start.elapsed();
593
594 if let Some(analytics) = &mut self.analytics {
596 analytics.record_execution(
597 &rule.name,
598 rule_duration,
599 false,
600 false,
601 None,
602 0,
603 );
604 }
605 }
606 }
607
608 if !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 }
689
690 #[allow(clippy::too_many_arguments)]
692 fn evaluate_accumulate(
693 &self,
694 _result_var: &str,
695 source_pattern: &str,
696 extract_field: &str,
697 source_conditions: &[String],
698 function: &str,
699 _function_arg: &str,
700 facts: &Facts,
701 ) -> Result<()> {
702 use crate::rete::accumulate::*;
703
704 let all_facts = facts.get_all_facts();
706 let mut matching_values = Vec::new();
707
708 let pattern_prefix = format!("{}.", source_pattern);
710
711 let mut instances: HashMap<String, HashMap<String, Value>> = HashMap::new();
713
714 for (key, value) in &all_facts {
715 if key.starts_with(&pattern_prefix) {
716 let parts: Vec<&str> = key
718 .strip_prefix(&pattern_prefix)
719 .unwrap()
720 .split('.')
721 .collect();
722
723 if parts.len() >= 2 {
724 let instance_id = parts[0];
726 let field_name = parts[1..].join(".");
727
728 instances
729 .entry(instance_id.to_string())
730 .or_default()
731 .insert(field_name, value.clone());
732 } else if parts.len() == 1 {
733 instances
735 .entry("default".to_string())
736 .or_default()
737 .insert(parts[0].to_string(), value.clone());
738 }
739 }
740 }
741
742 for (_instance_id, instance_facts) in instances {
744 let mut matches = true;
746
747 for condition_str in source_conditions {
748 if !self.evaluate_condition_string(condition_str, &instance_facts) {
750 matches = false;
751 break;
752 }
753 }
754
755 if matches {
756 if let Some(value) = instance_facts.get(extract_field) {
758 matching_values.push(value.clone());
759 }
760 }
761 }
762
763 let result = match function {
765 "sum" => {
766 let mut state = SumFunction.init();
767 for value in &matching_values {
768 state.accumulate(&self.value_to_fact_value(value));
769 }
770 self.fact_value_to_value(&state.get_result())
771 }
772 "count" => {
773 let mut state = CountFunction.init();
774 for value in &matching_values {
775 state.accumulate(&self.value_to_fact_value(value));
776 }
777 self.fact_value_to_value(&state.get_result())
778 }
779 "average" | "avg" => {
780 let mut state = AverageFunction.init();
781 for value in &matching_values {
782 state.accumulate(&self.value_to_fact_value(value));
783 }
784 self.fact_value_to_value(&state.get_result())
785 }
786 "min" => {
787 let mut state = MinFunction.init();
788 for value in &matching_values {
789 state.accumulate(&self.value_to_fact_value(value));
790 }
791 self.fact_value_to_value(&state.get_result())
792 }
793 "max" => {
794 let mut state = MaxFunction.init();
795 for value in &matching_values {
796 state.accumulate(&self.value_to_fact_value(value));
797 }
798 self.fact_value_to_value(&state.get_result())
799 }
800 _ => {
801 return Err(RuleEngineError::EvaluationError {
802 message: format!("Unknown accumulate function: {}", function),
803 });
804 }
805 };
806
807 let result_key = format!("{}.{}", source_pattern, function);
810
811 facts.set(&result_key, result);
812
813 if self.config.debug_mode {
814 println!(
815 " 🧮 Accumulate result: {} = {:?}",
816 result_key,
817 facts.get(&result_key)
818 );
819 }
820
821 Ok(())
822 }
823
824 fn value_to_fact_value(&self, value: &Value) -> crate::rete::facts::FactValue {
826 use crate::rete::facts::FactValue;
827 match value {
828 Value::Integer(i) => FactValue::Integer(*i),
829 Value::Number(n) => FactValue::Float(*n),
830 Value::String(s) => FactValue::String(s.clone()),
831 Value::Boolean(b) => FactValue::Boolean(*b),
832 _ => FactValue::String(value.to_string()),
833 }
834 }
835
836 fn fact_value_to_value(&self, fact_value: &crate::rete::facts::FactValue) -> Value {
838 use crate::rete::facts::FactValue;
839 match fact_value {
840 FactValue::Integer(i) => Value::Integer(*i),
841 FactValue::Float(f) => Value::Number(*f),
842 FactValue::String(s) => Value::String(s.clone()),
843 FactValue::Boolean(b) => Value::Boolean(*b),
844 FactValue::Array(_) => Value::String(format!("{:?}", fact_value)),
845 FactValue::Null => Value::String("null".to_string()),
846 }
847 }
848
849 fn evaluate_condition_string(&self, condition: &str, facts: &HashMap<String, Value>) -> bool {
851 let condition = condition.trim();
853
854 let operators = ["==", "!=", ">=", "<=", ">", "<"];
856
857 for op in &operators {
858 if let Some(pos) = condition.find(op) {
859 let field = condition[..pos].trim();
860 let value_str = condition[pos + op.len()..]
861 .trim()
862 .trim_matches('"')
863 .trim_matches('\'');
864
865 if let Some(field_value) = facts.get(field) {
866 return self.compare_values(field_value, op, value_str);
867 } else {
868 return false;
869 }
870 }
871 }
872
873 false
874 }
875
876 fn compare_values(&self, field_value: &Value, operator: &str, value_str: &str) -> bool {
878 match field_value {
879 Value::String(s) => match operator {
880 "==" => s == value_str,
881 "!=" => s != value_str,
882 _ => false,
883 },
884 Value::Integer(i) => {
885 if let Ok(num) = value_str.parse::<i64>() {
886 match operator {
887 "==" => *i == num,
888 "!=" => *i != num,
889 ">" => *i > num,
890 "<" => *i < num,
891 ">=" => *i >= num,
892 "<=" => *i <= num,
893 _ => false,
894 }
895 } else {
896 false
897 }
898 }
899 Value::Number(n) => {
900 if let Ok(num) = value_str.parse::<f64>() {
901 match operator {
902 "==" => (*n - num).abs() < f64::EPSILON,
903 "!=" => (*n - num).abs() >= f64::EPSILON,
904 ">" => *n > num,
905 "<" => *n < num,
906 ">=" => *n >= num,
907 "<=" => *n <= num,
908 _ => false,
909 }
910 } else {
911 false
912 }
913 }
914 Value::Boolean(b) => {
915 if let Ok(bool_val) = value_str.parse::<bool>() {
916 match operator {
917 "==" => *b == bool_val,
918 "!=" => *b != bool_val,
919 _ => false,
920 }
921 } else {
922 false
923 }
924 }
925 _ => false,
926 }
927 }
928
929 fn evaluate_rule_conditions(
931 &self,
932 rule: &crate::engine::rule::Rule,
933 facts: &Facts,
934 ) -> Result<bool> {
935 self.evaluate_conditions(&rule.conditions, facts)
936 }
937
938 fn is_retracted(&self, object_name: &str, facts: &Facts) -> bool {
940 let retract_key = format!("_retracted_{}", object_name);
941 matches!(facts.get(&retract_key), Some(Value::Boolean(true)))
942 }
943
944 fn evaluate_single_condition(
946 &self,
947 condition: &crate::engine::rule::Condition,
948 facts: &Facts,
949 ) -> Result<bool> {
950 use crate::engine::rule::ConditionExpression;
951
952 let result = match &condition.expression {
953 ConditionExpression::Field(field_name) => {
954 if let Some(object_name) = field_name.split('.').next() {
957 if self.is_retracted(object_name, facts) {
958 if self.config.debug_mode {
959 println!(" 🗑️ Skipping retracted fact: {}", object_name);
960 }
961 return Ok(false);
962 }
963 }
964
965 let field_value = facts
968 .get_nested(field_name)
969 .or_else(|| facts.get(field_name))
970 .unwrap_or(Value::Null);
971
972 if self.config.debug_mode {
973 println!(
974 " 🔎 Evaluating field condition: {} {} {:?}",
975 field_name,
976 format!("{:?}", condition.operator).to_lowercase(),
977 condition.value
978 );
979 println!(" Field value: {:?}", field_value);
980 }
981
982 let rhs = match &condition.value {
988 crate::types::Value::String(s) => {
989 facts
991 .get_nested(s)
992 .or_else(|| facts.get(s))
993 .unwrap_or(crate::types::Value::String(s.clone()))
994 }
995 crate::types::Value::Expression(expr) => {
996 match crate::expression::evaluate_expression(expr, facts) {
998 Ok(evaluated) => evaluated,
999 Err(_) => {
1000 facts
1002 .get_nested(expr)
1003 .or_else(|| facts.get(expr))
1004 .unwrap_or(crate::types::Value::Expression(expr.clone()))
1005 }
1006 }
1007 }
1008 _ => condition.value.clone(),
1009 };
1010
1011 if self.config.debug_mode {
1012 println!(" Resolved RHS for comparison: {:?}", rhs);
1013 }
1014
1015 condition.operator.evaluate(&field_value, &rhs)
1016 }
1017 ConditionExpression::FunctionCall { name, args } => {
1018 if self.config.debug_mode {
1020 println!(
1021 " 🔎 Evaluating function condition: {}({:?}) {} {:?}",
1022 name,
1023 args,
1024 format!("{:?}", condition.operator).to_lowercase(),
1025 condition.value
1026 );
1027 }
1028
1029 if let Some(function) = self.custom_functions.get(name) {
1030 let arg_values: Vec<Value> = args
1032 .iter()
1033 .map(|arg| {
1034 facts
1035 .get_nested(arg)
1036 .or_else(|| facts.get(arg))
1037 .unwrap_or(Value::String(arg.clone()))
1038 })
1039 .collect();
1040
1041 match function(&arg_values, facts) {
1043 Ok(result_value) => {
1044 if self.config.debug_mode {
1045 println!(" Function result: {:?}", result_value);
1046 }
1047 condition.operator.evaluate(&result_value, &condition.value)
1048 }
1049 Err(e) => {
1050 if self.config.debug_mode {
1051 println!(" Function error: {}", e);
1052 }
1053 false
1054 }
1055 }
1056 } else {
1057 if self.config.debug_mode {
1058 println!(" Function '{}' not found", name);
1059 }
1060 false
1061 }
1062 }
1063 ConditionExpression::Test { name, args } => {
1064 if self.config.debug_mode {
1066 println!(" 🧪 Evaluating test CE: test({}({:?}))", name, args);
1067 }
1068
1069 if let Some(function) = self.custom_functions.get(name) {
1071 let arg_values: Vec<Value> = args
1073 .iter()
1074 .map(|arg| {
1075 let resolved = facts
1076 .get_nested(arg)
1077 .or_else(|| facts.get(arg))
1078 .unwrap_or(Value::String(arg.clone()));
1079 if self.config.debug_mode {
1080 println!(" Resolving arg '{}' -> {:?}", arg, resolved);
1081 }
1082 resolved
1083 })
1084 .collect();
1085
1086 match function(&arg_values, facts) {
1088 Ok(result_value) => {
1089 if self.config.debug_mode {
1090 println!(" Test result: {:?}", result_value);
1091 }
1092 match result_value {
1094 Value::Boolean(b) => b,
1095 Value::Integer(i) => i != 0,
1096 Value::Number(f) => f != 0.0,
1097 Value::String(s) => !s.is_empty(),
1098 _ => false,
1099 }
1100 }
1101 Err(e) => {
1102 if self.config.debug_mode {
1103 println!(" Test function error: {}", e);
1104 }
1105 false
1106 }
1107 }
1108 } else {
1109 if self.config.debug_mode {
1112 println!(
1113 " Trying to evaluate '{}' as arithmetic expression",
1114 name
1115 );
1116 }
1117
1118 match self.evaluate_arithmetic_condition(name, facts) {
1120 Ok(result) => {
1121 if self.config.debug_mode {
1122 println!(" Arithmetic expression result: {}", result);
1123 }
1124 result
1125 }
1126 Err(e) => {
1127 if self.config.debug_mode {
1128 println!(" Failed to evaluate expression: {}", e);
1129 println!(" Test function '{}' not found", name);
1130 }
1131 false
1132 }
1133 }
1134 }
1135 }
1136 ConditionExpression::MultiField {
1137 field,
1138 operation,
1139 variable: _,
1140 } => {
1141 if self.config.debug_mode {
1143 println!(" 📦 Evaluating multi-field: {}.{}", field, operation);
1144 }
1145
1146 let field_value = facts.get_nested(field).or_else(|| facts.get(field));
1148
1149 if let Some(value) = field_value {
1150 match operation.as_str() {
1151 "empty" => {
1152 matches!(value, Value::Array(arr) if arr.is_empty())
1153 }
1154 "not_empty" => {
1155 matches!(value, Value::Array(arr) if !arr.is_empty())
1156 }
1157 "count" => {
1158 if let Value::Array(arr) = value {
1159 let count = Value::Integer(arr.len() as i64);
1160 condition.operator.evaluate(&count, &condition.value)
1161 } else {
1162 false
1163 }
1164 }
1165 "contains" => {
1166 condition.operator.evaluate(&value, &condition.value)
1168 }
1169 _ => {
1170 if self.config.debug_mode {
1173 println!(
1174 " ⚠️ Operation '{}' not fully implemented yet",
1175 operation
1176 );
1177 }
1178 true
1179 }
1180 }
1181 } else {
1182 false
1183 }
1184 }
1185 };
1186
1187 if self.config.debug_mode {
1188 println!(" Result: {}", result);
1189 }
1190
1191 Ok(result)
1192 }
1193
1194 fn execute_action(&mut self, action: &ActionType, facts: &Facts) -> Result<()> {
1196 match action {
1197 ActionType::Set { field, value } => {
1198 let evaluated_value = match value {
1200 Value::Expression(expr) => {
1201 crate::expression::evaluate_expression(expr, facts)?
1203 }
1204 _ => value.clone(),
1205 };
1206
1207 if facts.set_nested(field, evaluated_value.clone()).is_err() {
1209 facts.set(field, evaluated_value.clone());
1211 }
1212 if self.config.debug_mode {
1213 println!(" ✅ Set {field} = {evaluated_value:?}");
1214 }
1215 }
1216 ActionType::Log { message } => {
1217 println!("📋 LOG: {}", message);
1218 }
1219 ActionType::MethodCall {
1220 object,
1221 method,
1222 args,
1223 } => {
1224 let result = self.execute_method_call(object, method, args, facts)?;
1225 if self.config.debug_mode {
1226 println!(" 🔧 Called {object}.{method}({args:?}) -> {result}");
1227 }
1228 }
1229 ActionType::Retract { object } => {
1230 if self.config.debug_mode {
1231 println!(" 🗑️ Retracted {object}");
1232 }
1233 facts.set(&format!("_retracted_{}", object), Value::Boolean(true));
1235 }
1236 ActionType::Custom {
1237 action_type,
1238 params,
1239 } => {
1240 if let Some(handler) = self.action_handlers.get(action_type) {
1241 if self.config.debug_mode {
1242 println!(
1243 " 🎯 Executing custom action: {action_type} with params: {params:?}"
1244 );
1245 }
1246
1247 let resolved_params = self.resolve_action_parameters(params, facts)?;
1249
1250 handler(&resolved_params, facts)?;
1252 } else {
1253 if self.config.debug_mode {
1254 println!(" ⚠️ No handler registered for custom action: {action_type}");
1255 println!(
1256 " Available handlers: {:?}",
1257 self.action_handlers.keys().collect::<Vec<_>>()
1258 );
1259 }
1260
1261 return Err(RuleEngineError::EvaluationError {
1263 message: format!(
1264 "No action handler registered for '{action_type}'. Use engine.register_action_handler() to add custom action handlers."
1265 ),
1266 });
1267 }
1268 }
1269 ActionType::ActivateAgendaGroup { group } => {
1271 if self.config.debug_mode {
1272 println!(" 🎯 Activating agenda group: {}", group);
1273 }
1274 self.workflow_engine.activate_agenda_group(group.clone());
1276 self.agenda_manager.set_focus(group);
1277 }
1278 ActionType::ScheduleRule {
1279 rule_name,
1280 delay_ms,
1281 } => {
1282 if self.config.debug_mode {
1283 println!(
1284 " ⏰ Scheduling rule '{}' to execute in {}ms",
1285 rule_name, delay_ms
1286 );
1287 }
1288 self.workflow_engine
1289 .schedule_rule(rule_name.clone(), *delay_ms, None);
1290 }
1291 ActionType::CompleteWorkflow { workflow_name } => {
1292 if self.config.debug_mode {
1293 println!(" ✅ Completing workflow: {}", workflow_name);
1294 }
1295 self.workflow_engine
1296 .complete_workflow(workflow_name.clone());
1297 }
1298 ActionType::SetWorkflowData { key, value } => {
1299 if self.config.debug_mode {
1300 println!(" 💾 Setting workflow data: {} = {:?}", key, value);
1301 }
1302 let workflow_id = "default_workflow";
1305 self.workflow_engine
1306 .set_workflow_data(workflow_id, key.clone(), value.clone());
1307 }
1308 }
1309 Ok(())
1310 }
1311
1312 fn evaluate_arithmetic_condition(&self, expr: &str, facts: &Facts) -> Result<bool> {
1314 let operators = [">=", "<=", "==", "!=", ">", "<"];
1318 let mut split_pos = None;
1319 let mut found_op = "";
1320
1321 for op in &operators {
1322 if let Some(pos) = expr.rfind(op) {
1323 split_pos = Some(pos);
1324 found_op = op;
1325 break;
1326 }
1327 }
1328
1329 if split_pos.is_none() {
1330 return Err(RuleEngineError::EvaluationError {
1331 message: format!("No comparison operator found in expression: {}", expr),
1332 });
1333 }
1334
1335 let pos = split_pos.unwrap();
1336 let left_expr = expr[..pos].trim();
1337 let right_value = expr[pos + found_op.len()..].trim();
1338
1339 let left_result = crate::expression::evaluate_expression(left_expr, facts)?;
1341
1342 let right_val = if let Ok(i) = right_value.parse::<i64>() {
1344 Value::Integer(i)
1345 } else if let Ok(f) = right_value.parse::<f64>() {
1346 Value::Number(f)
1347 } else {
1348 match crate::expression::evaluate_expression(right_value, facts) {
1350 Ok(v) => v,
1351 Err(_) => Value::String(right_value.to_string()),
1352 }
1353 };
1354
1355 let operator =
1357 Operator::from_str(found_op).ok_or_else(|| RuleEngineError::InvalidOperator {
1358 operator: found_op.to_string(),
1359 })?;
1360
1361 Ok(operator.evaluate(&left_result, &right_val))
1362 }
1363
1364 fn execute_function_call(
1366 &self,
1367 function: &str,
1368 args: &[Value],
1369 facts: &Facts,
1370 ) -> Result<String> {
1371 let function_lower = function.to_lowercase();
1372
1373 match function_lower.as_str() {
1375 "log" | "print" | "println" => self.handle_log_function(args),
1376 "update" | "refresh" => self.handle_update_function(args),
1377 "now" | "timestamp" => self.handle_timestamp_function(),
1378 "random" => self.handle_random_function(args),
1379 "format" | "sprintf" => self.handle_format_function(args),
1380 "length" | "size" | "count" => self.handle_length_function(args),
1381 "sum" | "add" => self.handle_sum_function(args),
1382 "max" | "maximum" => self.handle_max_function(args),
1383 "min" | "minimum" => self.handle_min_function(args),
1384 "avg" | "average" => self.handle_average_function(args),
1385 "round" => self.handle_round_function(args),
1386 "floor" => self.handle_floor_function(args),
1387 "ceil" | "ceiling" => self.handle_ceil_function(args),
1388 "abs" | "absolute" => self.handle_abs_function(args),
1389 "contains" | "includes" => self.handle_contains_function(args),
1390 "startswith" | "begins_with" => self.handle_starts_with_function(args),
1391 "endswith" | "ends_with" => self.handle_ends_with_function(args),
1392 "lowercase" | "tolower" => self.handle_lowercase_function(args),
1393 "uppercase" | "toupper" => self.handle_uppercase_function(args),
1394 "trim" | "strip" => self.handle_trim_function(args),
1395 "split" => self.handle_split_function(args),
1396 "join" => self.handle_join_function(args),
1397 _ => {
1398 self.handle_custom_function(function, args, facts)
1400 }
1401 }
1402 }
1403
1404 fn handle_log_function(&self, args: &[Value]) -> Result<String> {
1406 let message = if args.is_empty() {
1407 "".to_string()
1408 } else if args.len() == 1 {
1409 args[0].to_string()
1410 } else {
1411 args.iter()
1412 .map(|v| v.to_string())
1413 .collect::<Vec<_>>()
1414 .join(" ")
1415 };
1416
1417 println!("📋 {}", message);
1418 Ok(message)
1419 }
1420
1421 fn handle_update_function(&self, args: &[Value]) -> Result<String> {
1423 if let Some(arg) = args.first() {
1424 Ok(format!("Updated: {}", arg.to_string()))
1425 } else {
1426 Ok("Updated".to_string())
1427 }
1428 }
1429
1430 fn handle_timestamp_function(&self) -> Result<String> {
1432 use std::time::{SystemTime, UNIX_EPOCH};
1433 let timestamp = SystemTime::now()
1434 .duration_since(UNIX_EPOCH)
1435 .map_err(|e| RuleEngineError::EvaluationError {
1436 message: format!("Failed to get timestamp: {}", e),
1437 })?
1438 .as_secs();
1439 Ok(timestamp.to_string())
1440 }
1441
1442 fn handle_random_function(&self, args: &[Value]) -> Result<String> {
1444 use std::collections::hash_map::DefaultHasher;
1445 use std::hash::{Hash, Hasher};
1446
1447 let mut hasher = DefaultHasher::new();
1449 std::time::SystemTime::now().hash(&mut hasher);
1450 let random_value = hasher.finish();
1451
1452 if args.is_empty() {
1453 Ok((random_value % 100).to_string()) } else if let Some(Value::Number(max)) = args.first() {
1455 let max_val = *max as u64;
1456 Ok((random_value % max_val).to_string())
1457 } else {
1458 Ok(random_value.to_string())
1459 }
1460 }
1461
1462 fn handle_format_function(&self, args: &[Value]) -> Result<String> {
1464 if args.is_empty() {
1465 return Ok("".to_string());
1466 }
1467
1468 let template = args[0].to_string();
1469 let values: Vec<String> = args[1..].iter().map(|v| v.to_string()).collect();
1470
1471 let mut result = template;
1473 for (i, value) in values.iter().enumerate() {
1474 result = result.replace(&format!("{{{}}}", i), value);
1475 }
1476
1477 Ok(result)
1478 }
1479
1480 fn handle_length_function(&self, args: &[Value]) -> Result<String> {
1482 if let Some(arg) = args.first() {
1483 match arg {
1484 Value::String(s) => Ok(s.len().to_string()),
1485 Value::Array(arr) => Ok(arr.len().to_string()),
1486 Value::Object(obj) => Ok(obj.len().to_string()),
1487 _ => Ok("1".to_string()), }
1489 } else {
1490 Ok("0".to_string())
1491 }
1492 }
1493
1494 fn handle_sum_function(&self, args: &[Value]) -> Result<String> {
1496 let sum = args.iter().fold(0.0, |acc, val| match val {
1497 Value::Number(n) => acc + n,
1498 Value::Integer(i) => acc + (*i as f64),
1499 _ => acc,
1500 });
1501 Ok(sum.to_string())
1502 }
1503
1504 fn handle_max_function(&self, args: &[Value]) -> Result<String> {
1506 let max = args.iter().fold(f64::NEG_INFINITY, |acc, val| match val {
1507 Value::Number(n) => acc.max(*n),
1508 Value::Integer(i) => acc.max(*i as f64),
1509 _ => acc,
1510 });
1511 Ok(max.to_string())
1512 }
1513
1514 fn handle_min_function(&self, args: &[Value]) -> Result<String> {
1516 let min = args.iter().fold(f64::INFINITY, |acc, val| match val {
1517 Value::Number(n) => acc.min(*n),
1518 Value::Integer(i) => acc.min(*i as f64),
1519 _ => acc,
1520 });
1521 Ok(min.to_string())
1522 }
1523
1524 fn handle_average_function(&self, args: &[Value]) -> Result<String> {
1526 if args.is_empty() {
1527 return Ok("0".to_string());
1528 }
1529
1530 let (sum, count) = args.iter().fold((0.0, 0), |(sum, count), val| match val {
1531 Value::Number(n) => (sum + n, count + 1),
1532 Value::Integer(i) => (sum + (*i as f64), count + 1),
1533 _ => (sum, count),
1534 });
1535
1536 if count > 0 {
1537 Ok((sum / count as f64).to_string())
1538 } else {
1539 Ok("0".to_string())
1540 }
1541 }
1542
1543 fn handle_round_function(&self, args: &[Value]) -> Result<String> {
1545 if let Some(Value::Number(n)) = args.first() {
1546 Ok(n.round().to_string())
1547 } else if let Some(Value::Integer(i)) = args.first() {
1548 Ok(i.to_string())
1549 } else {
1550 Err(RuleEngineError::EvaluationError {
1551 message: "round() requires a numeric argument".to_string(),
1552 })
1553 }
1554 }
1555
1556 fn handle_floor_function(&self, args: &[Value]) -> Result<String> {
1557 if let Some(Value::Number(n)) = args.first() {
1558 Ok(n.floor().to_string())
1559 } else if let Some(Value::Integer(i)) = args.first() {
1560 Ok(i.to_string())
1561 } else {
1562 Err(RuleEngineError::EvaluationError {
1563 message: "floor() requires a numeric argument".to_string(),
1564 })
1565 }
1566 }
1567
1568 fn handle_ceil_function(&self, args: &[Value]) -> Result<String> {
1569 if let Some(Value::Number(n)) = args.first() {
1570 Ok(n.ceil().to_string())
1571 } else if let Some(Value::Integer(i)) = args.first() {
1572 Ok(i.to_string())
1573 } else {
1574 Err(RuleEngineError::EvaluationError {
1575 message: "ceil() requires a numeric argument".to_string(),
1576 })
1577 }
1578 }
1579
1580 fn handle_abs_function(&self, args: &[Value]) -> Result<String> {
1581 if let Some(Value::Number(n)) = args.first() {
1582 Ok(n.abs().to_string())
1583 } else if let Some(Value::Integer(i)) = args.first() {
1584 Ok(i.abs().to_string())
1585 } else {
1586 Err(RuleEngineError::EvaluationError {
1587 message: "abs() requires a numeric argument".to_string(),
1588 })
1589 }
1590 }
1591
1592 fn handle_contains_function(&self, args: &[Value]) -> Result<String> {
1594 if args.len() >= 2 {
1595 let haystack = args[0].to_string();
1596 let needle = args[1].to_string();
1597 Ok(haystack.contains(&needle).to_string())
1598 } else {
1599 Err(RuleEngineError::EvaluationError {
1600 message: "contains() requires 2 arguments".to_string(),
1601 })
1602 }
1603 }
1604
1605 fn handle_starts_with_function(&self, args: &[Value]) -> Result<String> {
1606 if args.len() >= 2 {
1607 let text = args[0].to_string();
1608 let prefix = args[1].to_string();
1609 Ok(text.starts_with(&prefix).to_string())
1610 } else {
1611 Err(RuleEngineError::EvaluationError {
1612 message: "startswith() requires 2 arguments".to_string(),
1613 })
1614 }
1615 }
1616
1617 fn handle_ends_with_function(&self, args: &[Value]) -> Result<String> {
1618 if args.len() >= 2 {
1619 let text = args[0].to_string();
1620 let suffix = args[1].to_string();
1621 Ok(text.ends_with(&suffix).to_string())
1622 } else {
1623 Err(RuleEngineError::EvaluationError {
1624 message: "endswith() requires 2 arguments".to_string(),
1625 })
1626 }
1627 }
1628
1629 fn handle_lowercase_function(&self, args: &[Value]) -> Result<String> {
1630 if let Some(arg) = args.first() {
1631 Ok(arg.to_string().to_lowercase())
1632 } else {
1633 Err(RuleEngineError::EvaluationError {
1634 message: "lowercase() requires 1 argument".to_string(),
1635 })
1636 }
1637 }
1638
1639 fn handle_uppercase_function(&self, args: &[Value]) -> Result<String> {
1640 if let Some(arg) = args.first() {
1641 Ok(arg.to_string().to_uppercase())
1642 } else {
1643 Err(RuleEngineError::EvaluationError {
1644 message: "uppercase() requires 1 argument".to_string(),
1645 })
1646 }
1647 }
1648
1649 fn handle_trim_function(&self, args: &[Value]) -> Result<String> {
1650 if let Some(arg) = args.first() {
1651 Ok(arg.to_string().trim().to_string())
1652 } else {
1653 Err(RuleEngineError::EvaluationError {
1654 message: "trim() requires 1 argument".to_string(),
1655 })
1656 }
1657 }
1658
1659 fn handle_split_function(&self, args: &[Value]) -> Result<String> {
1660 if args.len() >= 2 {
1661 let text = args[0].to_string();
1662 let delimiter = args[1].to_string();
1663 let parts: Vec<String> = text.split(&delimiter).map(|s| s.to_string()).collect();
1664 Ok(format!("{:?}", parts)) } else {
1666 Err(RuleEngineError::EvaluationError {
1667 message: "split() requires 2 arguments".to_string(),
1668 })
1669 }
1670 }
1671
1672 fn handle_join_function(&self, args: &[Value]) -> Result<String> {
1673 if args.len() >= 2 {
1674 let delimiter = args[0].to_string();
1675 let parts: Vec<String> = args[1..].iter().map(|v| v.to_string()).collect();
1676 Ok(parts.join(&delimiter))
1677 } else {
1678 Err(RuleEngineError::EvaluationError {
1679 message: "join() requires at least 2 arguments".to_string(),
1680 })
1681 }
1682 }
1683
1684 fn handle_custom_function(
1686 &self,
1687 function: &str,
1688 args: &[Value],
1689 facts: &Facts,
1690 ) -> Result<String> {
1691 if let Some(custom_func) = self.custom_functions.get(function) {
1693 if self.config.debug_mode {
1694 println!("🎯 Calling registered function: {}({:?})", function, args);
1695 }
1696
1697 match custom_func(args, facts) {
1698 Ok(result) => Ok(result.to_string()),
1699 Err(e) => Err(e),
1700 }
1701 } else {
1702 if self.config.debug_mode {
1704 println!("⚠️ Custom function '{}' not registered", function);
1705 }
1706
1707 Err(RuleEngineError::EvaluationError {
1708 message: format!("Function '{}' is not registered. Use engine.register_function() to add custom functions.", function),
1709 })
1710 }
1711 }
1712
1713 fn execute_method_call(
1715 &self,
1716 object_name: &str,
1717 method: &str,
1718 args: &[Value],
1719 facts: &Facts,
1720 ) -> Result<String> {
1721 let Some(object_value) = facts.get(object_name) else {
1723 return Err(RuleEngineError::EvaluationError {
1724 message: format!("Object '{}' not found in facts", object_name),
1725 });
1726 };
1727
1728 let method_lower = method.to_lowercase();
1729
1730 if method_lower.starts_with("set") && args.len() == 1 {
1732 return self.handle_setter_method(object_name, method, &args[0], object_value, facts);
1733 }
1734
1735 if method_lower.starts_with("get") && args.is_empty() {
1737 return self.handle_getter_method(object_name, method, &object_value);
1738 }
1739
1740 match method_lower.as_str() {
1742 "tostring" => Ok(object_value.to_string()),
1743 "update" => {
1744 facts.add_value(object_name, object_value)?;
1745 Ok(format!("Updated {}", object_name))
1746 }
1747 "reset" => self.handle_reset_method(object_name, object_value, facts),
1748 _ => self.handle_property_access_or_fallback(
1749 object_name,
1750 method,
1751 args.len(),
1752 &object_value,
1753 ),
1754 }
1755 }
1756
1757 fn handle_setter_method(
1759 &self,
1760 object_name: &str,
1761 method: &str,
1762 new_value: &Value,
1763 mut object_value: Value,
1764 facts: &Facts,
1765 ) -> Result<String> {
1766 let property_name = Self::extract_property_name_from_setter(method);
1767
1768 match object_value {
1769 Value::Object(ref mut obj) => {
1770 obj.insert(property_name.clone(), new_value.clone());
1771 facts.add_value(object_name, object_value)?;
1772 Ok(format!(
1773 "Set {} to {}",
1774 property_name,
1775 new_value.to_string()
1776 ))
1777 }
1778 _ => Err(RuleEngineError::EvaluationError {
1779 message: format!("Cannot call setter on non-object type: {}", object_name),
1780 }),
1781 }
1782 }
1783
1784 fn handle_getter_method(
1786 &self,
1787 object_name: &str,
1788 method: &str,
1789 object_value: &Value,
1790 ) -> Result<String> {
1791 let property_name = Self::extract_property_name_from_getter(method);
1792
1793 match object_value {
1794 Value::Object(obj) => {
1795 if let Some(value) = obj.get(&property_name) {
1796 Ok(value.to_string())
1797 } else {
1798 Err(RuleEngineError::EvaluationError {
1799 message: format!(
1800 "Property '{}' not found on object '{}'",
1801 property_name, object_name
1802 ),
1803 })
1804 }
1805 }
1806 _ => Err(RuleEngineError::EvaluationError {
1807 message: format!("Cannot call getter on non-object type: {}", object_name),
1808 }),
1809 }
1810 }
1811
1812 fn handle_reset_method(
1814 &self,
1815 object_name: &str,
1816 mut object_value: Value,
1817 facts: &Facts,
1818 ) -> Result<String> {
1819 match object_value {
1820 Value::Object(ref mut obj) => {
1821 obj.clear();
1822 facts.add_value(object_name, object_value)?;
1823 Ok(format!("Reset {}", object_name))
1824 }
1825 _ => Err(RuleEngineError::EvaluationError {
1826 message: format!("Cannot reset non-object type: {}", object_name),
1827 }),
1828 }
1829 }
1830
1831 fn handle_property_access_or_fallback(
1833 &self,
1834 object_name: &str,
1835 method: &str,
1836 arg_count: usize,
1837 object_value: &Value,
1838 ) -> Result<String> {
1839 if let Value::Object(obj) = object_value {
1840 if let Some(value) = obj.get(method) {
1842 return Ok(value.to_string());
1843 }
1844
1845 let capitalized_method = Self::capitalize_first_letter(method);
1847 if let Some(value) = obj.get(&capitalized_method) {
1848 return Ok(value.to_string());
1849 }
1850 }
1851
1852 Ok(format!(
1854 "Called {}.{} with {} args",
1855 object_name, method, arg_count
1856 ))
1857 }
1858
1859 fn extract_property_name_from_setter(method: &str) -> String {
1861 let property_name = &method[3..]; Self::capitalize_first_letter(property_name)
1863 }
1864
1865 fn extract_property_name_from_getter(method: &str) -> String {
1867 let property_name = &method[3..]; Self::capitalize_first_letter(property_name)
1869 }
1870
1871 fn capitalize_first_letter(s: &str) -> String {
1873 if s.is_empty() {
1874 return String::new();
1875 }
1876 let mut chars = s.chars();
1877 match chars.next() {
1878 None => String::new(),
1879 Some(first) => first.to_uppercase().collect::<String>() + chars.as_str(),
1880 }
1881 }
1882
1883 fn resolve_action_parameters(
1885 &self,
1886 params: &HashMap<String, Value>,
1887 facts: &Facts,
1888 ) -> Result<HashMap<String, Value>> {
1889 let mut resolved = HashMap::new();
1890
1891 for (key, value) in params {
1892 let resolved_value = match value {
1893 Value::String(s) => {
1894 if s.contains('.') {
1896 if let Some(fact_value) = facts.get_nested(s) {
1898 fact_value
1899 } else {
1900 value.clone()
1902 }
1903 } else {
1904 value.clone()
1905 }
1906 }
1907 _ => value.clone(),
1908 };
1909 resolved.insert(key.clone(), resolved_value);
1910 }
1911
1912 Ok(resolved)
1913 }
1914
1915 pub fn load_plugin(
1919 &mut self,
1920 plugin: std::sync::Arc<dyn crate::engine::plugin::RulePlugin>,
1921 ) -> Result<()> {
1922 plugin.register_actions(self)?;
1924 plugin.register_functions(self)?;
1925
1926 self.plugin_manager.load_plugin(plugin)
1928 }
1929
1930 pub fn unload_plugin(&mut self, name: &str) -> Result<()> {
1932 self.plugin_manager.unload_plugin(name)
1933 }
1934
1935 pub fn hot_reload_plugin(
1937 &mut self,
1938 name: &str,
1939 new_plugin: std::sync::Arc<dyn crate::engine::plugin::RulePlugin>,
1940 ) -> Result<()> {
1941 self.plugin_manager.unload_plugin(name)?;
1943
1944 new_plugin.register_actions(self)?;
1946 new_plugin.register_functions(self)?;
1947
1948 self.plugin_manager.load_plugin(new_plugin)
1950 }
1951
1952 pub fn get_plugin_info(&self, name: &str) -> Option<&crate::engine::plugin::PluginMetadata> {
1954 self.plugin_manager.get_plugin_info(name)
1955 }
1956
1957 pub fn list_plugins(&self) -> Vec<PluginInfo> {
1959 self.plugin_manager.list_plugins()
1960 }
1961
1962 pub fn get_plugin_stats(&self) -> PluginStats {
1964 self.plugin_manager.get_stats()
1965 }
1966
1967 pub fn plugin_health_check(&mut self) -> HashMap<String, crate::engine::plugin::PluginHealth> {
1969 self.plugin_manager.plugin_health_check()
1970 }
1971
1972 pub fn configure_plugins(&mut self, config: PluginConfig) {
1974 self.plugin_manager = PluginManager::new(config);
1975 }
1976}