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
75impl RustRuleEngine {
76 pub fn execute_with_callback<F>(&mut self, facts: &Facts, mut on_rule_fired: F) -> Result<GruleExecutionResult>
78 where
79 F: FnMut(&str, &Facts),
80 {
81 use chrono::Utc;
82 let timestamp = Utc::now();
83 let start_time = std::time::Instant::now();
84 let mut cycle_count = 0;
85 let mut rules_evaluated = 0;
86 let mut rules_fired = 0;
87
88 self.sync_workflow_agenda_activations();
89
90 for cycle in 0..self.config.max_cycles {
91 cycle_count = cycle + 1;
92 let mut any_rule_fired = false;
93 let mut fired_rules_in_cycle = std::collections::HashSet::new();
94 self.activation_group_manager.reset_cycle();
95
96 if let Some(timeout) = self.config.timeout {
97 if start_time.elapsed() > timeout {
98 return Err(crate::errors::RuleEngineError::EvaluationError {
99 message: "Execution timeout exceeded".to_string(),
100 });
101 }
102 }
103
104 let mut rules = self.knowledge_base.get_rules().clone();
105 rules.sort_by(|a, b| b.salience.cmp(&a.salience));
106 let rules: Vec<_> = rules
107 .iter()
108 .filter(|rule| self.agenda_manager.should_evaluate_rule(rule))
109 .collect();
110
111 for rule in &rules {
112 if !rule.enabled {
113 continue;
114 }
115 if !rule.is_active_at(timestamp) {
116 continue;
117 }
118 if !self.agenda_manager.can_fire_rule(rule) {
119 continue;
120 }
121 if !self.activation_group_manager.can_fire(rule) {
122 continue;
123 }
124 if rule.no_loop && self.fired_rules_global.contains(&rule.name) {
125 continue;
126 }
127 rules_evaluated += 1;
128 let condition_result = self.evaluate_conditions(&rule.conditions, facts)?;
129 if condition_result {
130 for action in &rule.actions {
131 self.execute_action(action, facts)?;
132 }
133 rules_fired += 1;
134 any_rule_fired = true;
135 fired_rules_in_cycle.insert(rule.name.clone());
136 if rule.no_loop {
137 self.fired_rules_global.insert(rule.name.clone());
138 }
139 self.agenda_manager.mark_rule_fired(rule);
140 self.activation_group_manager.mark_fired(rule);
141 on_rule_fired(&rule.name, facts);
143 }
144 }
145 if !any_rule_fired {
146 break;
147 }
148 self.sync_workflow_agenda_activations();
149 }
150 let execution_time = start_time.elapsed();
151 Ok(crate::engine::GruleExecutionResult {
152 cycle_count,
153 rules_evaluated,
154 rules_fired,
155 execution_time,
156 })
157 }
158 pub fn new(knowledge_base: KnowledgeBase) -> Self {
160 Self {
161 knowledge_base,
162 config: EngineConfig::default(),
163 custom_functions: HashMap::new(),
164 action_handlers: HashMap::new(),
165 analytics: None,
166 agenda_manager: AgendaManager::new(),
167 activation_group_manager: ActivationGroupManager::new(),
168 fired_rules_global: std::collections::HashSet::new(),
169 workflow_engine: WorkflowEngine::new(),
170 plugin_manager: PluginManager::with_default_config(),
171 }
172 }
173
174 pub fn with_config(knowledge_base: KnowledgeBase, config: EngineConfig) -> Self {
176 Self {
177 knowledge_base,
178 config,
179 custom_functions: HashMap::new(),
180 action_handlers: HashMap::new(),
181 analytics: None,
182 agenda_manager: AgendaManager::new(),
183 activation_group_manager: ActivationGroupManager::new(),
184 fired_rules_global: std::collections::HashSet::new(),
185 workflow_engine: WorkflowEngine::new(),
186 plugin_manager: PluginManager::with_default_config(),
187 }
188 }
189
190 pub fn register_function<F>(&mut self, name: &str, func: F)
192 where
193 F: Fn(&[Value], &Facts) -> Result<Value> + Send + Sync + 'static,
194 {
195 self.custom_functions
196 .insert(name.to_string(), Box::new(func));
197 }
198
199 pub fn register_action_handler<F>(&mut self, action_type: &str, handler: F)
201 where
202 F: Fn(&HashMap<String, Value>, &Facts) -> Result<()> + Send + Sync + 'static,
203 {
204 self.action_handlers
205 .insert(action_type.to_string(), Box::new(handler));
206 }
207
208 pub fn enable_analytics(&mut self, analytics: RuleAnalytics) {
210 self.analytics = Some(analytics);
211 }
212
213 pub fn reset_no_loop_tracking(&mut self) {
215 self.fired_rules_global.clear();
216 }
217
218 pub fn disable_analytics(&mut self) {
220 self.analytics = None;
221 }
222
223 pub fn analytics(&self) -> Option<&RuleAnalytics> {
225 self.analytics.as_ref()
226 }
227
228 pub fn set_debug_mode(&mut self, enabled: bool) {
230 self.config.debug_mode = enabled;
231 }
232
233 pub fn has_function(&self, name: &str) -> bool {
235 self.custom_functions.contains_key(name)
236 }
237
238 pub fn has_action_handler(&self, action_type: &str) -> bool {
240 self.action_handlers.contains_key(action_type)
241 }
242
243 pub fn get_ready_tasks(&mut self) -> Vec<crate::engine::workflow::ScheduledTask> {
245 self.workflow_engine.get_ready_tasks()
246 }
247
248 pub fn execute_scheduled_tasks(&mut self, facts: &Facts) -> Result<()> {
250 let ready_tasks = self.get_ready_tasks();
251 for task in ready_tasks {
252 if let Some(rule) = self
253 .knowledge_base
254 .get_rules()
255 .iter()
256 .find(|r| r.name == task.rule_name)
257 {
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
431 .knowledge_base
432 .get_rules()
433 .iter()
434 .find(|r| r.name == task.rule_name)
435 {
436 if self.evaluate_conditions(&rule.conditions, facts)? {
438 for action in &rule.actions {
439 self.execute_action(action, facts)?;
440 }
441 }
442 }
443 }
444
445 Ok(())
446 }
447
448 pub fn execute(&mut self, facts: &Facts) -> Result<GruleExecutionResult> {
450 self.execute_at_time(facts, Utc::now())
451 }
452
453 pub fn execute_at_time(
455 &mut self,
456 facts: &Facts,
457 timestamp: DateTime<Utc>,
458 ) -> Result<GruleExecutionResult> {
459 let start_time = Instant::now();
460 let mut cycle_count = 0;
461 let mut rules_evaluated = 0;
462 let mut rules_fired = 0;
463
464 self.sync_workflow_agenda_activations();
466
467 if self.config.debug_mode {
468 println!(
469 "🚀 Starting rule execution with {} rules (agenda group: {})",
470 self.knowledge_base.get_rules().len(),
471 self.agenda_manager.get_active_group()
472 );
473 }
474
475 for cycle in 0..self.config.max_cycles {
476 cycle_count = cycle + 1;
477 let mut any_rule_fired = false;
478 let mut fired_rules_in_cycle = std::collections::HashSet::new();
479
480 self.activation_group_manager.reset_cycle();
482
483 if let Some(timeout) = self.config.timeout {
485 if start_time.elapsed() > timeout {
486 return Err(RuleEngineError::EvaluationError {
487 message: "Execution timeout exceeded".to_string(),
488 });
489 }
490 }
491
492 let mut rules = self.knowledge_base.get_rules().clone();
494 rules.sort_by(|a, b| b.salience.cmp(&a.salience));
495
496 let rules: Vec<_> = rules
498 .iter()
499 .filter(|rule| self.agenda_manager.should_evaluate_rule(rule))
500 .collect();
501
502 for rule in &rules {
503 if !rule.enabled {
504 continue;
505 }
506
507 if !rule.is_active_at(timestamp) {
509 continue;
510 }
511
512 if !self.agenda_manager.can_fire_rule(rule) {
514 continue;
515 }
516
517 if !self.activation_group_manager.can_fire(rule) {
519 continue;
520 }
521
522 if rule.no_loop && self.fired_rules_global.contains(&rule.name) {
524 if self.config.debug_mode {
525 println!("⛔ Skipping '{}' due to no_loop (already fired)", rule.name);
526 }
527 continue;
528 }
529
530 rules_evaluated += 1;
531 let rule_start = Instant::now();
532
533 if self.config.debug_mode {
534 println!("📝 Evaluating rule: {} (no_loop={})", rule.name, rule.no_loop);
535 }
536
537 let condition_result = self.evaluate_conditions(&rule.conditions, facts)?;
539 if self.config.debug_mode {
540 println!(
541 " 🔍 Condition result for '{}': {}",
542 rule.name, condition_result
543 );
544 }
545
546 if condition_result {
547 if self.config.debug_mode {
548 println!(
549 "🔥 Rule '{}' fired (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(&rule.name, rule_duration, true, true, None, 0);
564 }
565
566 rules_fired += 1;
567 any_rule_fired = true;
568
569 fired_rules_in_cycle.insert(rule.name.clone());
571
572 if rule.no_loop {
574 self.fired_rules_global.insert(rule.name.clone());
575 if self.config.debug_mode {
576 println!(" 🔒 Marked '{}' as fired (no_loop tracking)", rule.name);
577 }
578 }
579
580 self.agenda_manager.mark_rule_fired(rule);
582 self.activation_group_manager.mark_fired(rule);
583 } else {
584 let rule_duration = rule_start.elapsed();
585
586 if let Some(analytics) = &mut self.analytics {
588 analytics.record_execution(
589 &rule.name,
590 rule_duration,
591 false,
592 false,
593 None,
594 0,
595 );
596 }
597 }
598 }
599
600 if !any_rule_fired {
602 break;
603 }
604
605 self.sync_workflow_agenda_activations();
607 }
608
609 let execution_time = start_time.elapsed();
610
611 Ok(GruleExecutionResult {
612 cycle_count,
613 rules_evaluated,
614 rules_fired,
615 execution_time,
616 })
617 }
618
619 fn evaluate_conditions(
621 &self,
622 conditions: &crate::engine::rule::ConditionGroup,
623 facts: &Facts,
624 ) -> Result<bool> {
625 use crate::engine::pattern_matcher::PatternMatcher;
626 use crate::engine::rule::ConditionGroup;
627
628 match conditions {
629 ConditionGroup::Single(condition) => self.evaluate_single_condition(condition, facts),
630 ConditionGroup::Compound {
631 left,
632 operator,
633 right,
634 } => {
635 let left_result = self.evaluate_conditions(left, facts)?;
636 let right_result = self.evaluate_conditions(right, facts)?;
637
638 match operator {
639 crate::types::LogicalOperator::And => Ok(left_result && right_result),
640 crate::types::LogicalOperator::Or => Ok(left_result || right_result),
641 crate::types::LogicalOperator::Not => Err(RuleEngineError::EvaluationError {
642 message: "NOT operator should not appear in compound conditions"
643 .to_string(),
644 }),
645 }
646 }
647 ConditionGroup::Not(condition) => {
648 let result = self.evaluate_conditions(condition, facts)?;
649 Ok(!result)
650 }
651 ConditionGroup::Exists(condition) => {
653 Ok(PatternMatcher::evaluate_exists(condition, facts))
654 }
655 ConditionGroup::Forall(condition) => {
656 Ok(PatternMatcher::evaluate_forall(condition, facts))
657 }
658 ConditionGroup::Accumulate {
659 result_var,
660 source_pattern,
661 extract_field,
662 source_conditions,
663 function,
664 function_arg,
665 } => {
666 self.evaluate_accumulate(
668 result_var,
669 source_pattern,
670 extract_field,
671 source_conditions,
672 function,
673 function_arg,
674 facts,
675 )?;
676 Ok(true)
678 }
679 }
680 }
681
682 fn evaluate_accumulate(
684 &self,
685 result_var: &str,
686 source_pattern: &str,
687 extract_field: &str,
688 source_conditions: &[String],
689 function: &str,
690 function_arg: &str,
691 facts: &Facts,
692 ) -> Result<()> {
693 use crate::rete::accumulate::*;
694
695 let all_facts = facts.get_all_facts();
697 let mut matching_values = Vec::new();
698
699 let pattern_prefix = format!("{}.", source_pattern);
701
702 let mut instances: HashMap<String, HashMap<String, Value>> = HashMap::new();
704
705 for (key, value) in &all_facts {
706 if key.starts_with(&pattern_prefix) {
707 let parts: Vec<&str> = key.strip_prefix(&pattern_prefix).unwrap().split('.').collect();
709
710 if parts.len() >= 2 {
711 let instance_id = parts[0];
713 let field_name = parts[1..].join(".");
714
715 instances
716 .entry(instance_id.to_string())
717 .or_insert_with(HashMap::new)
718 .insert(field_name, value.clone());
719 } else if parts.len() == 1 {
720 instances
722 .entry("default".to_string())
723 .or_insert_with(HashMap::new)
724 .insert(parts[0].to_string(), value.clone());
725 }
726 }
727 }
728
729 for (_instance_id, instance_facts) in instances {
731 let mut matches = true;
733
734 for condition_str in source_conditions {
735 if !self.evaluate_condition_string(condition_str, &instance_facts) {
737 matches = false;
738 break;
739 }
740 }
741
742 if matches {
743 if let Some(value) = instance_facts.get(extract_field) {
745 matching_values.push(value.clone());
746 }
747 }
748 }
749
750 let result = match function {
752 "sum" => {
753 let mut state = SumFunction.init();
754 for value in &matching_values {
755 state.accumulate(&self.value_to_fact_value(value));
756 }
757 self.fact_value_to_value(&state.get_result())
758 }
759 "count" => {
760 let mut state = CountFunction.init();
761 for value in &matching_values {
762 state.accumulate(&self.value_to_fact_value(value));
763 }
764 self.fact_value_to_value(&state.get_result())
765 }
766 "average" | "avg" => {
767 let mut state = AverageFunction.init();
768 for value in &matching_values {
769 state.accumulate(&self.value_to_fact_value(value));
770 }
771 self.fact_value_to_value(&state.get_result())
772 }
773 "min" => {
774 let mut state = MinFunction.init();
775 for value in &matching_values {
776 state.accumulate(&self.value_to_fact_value(value));
777 }
778 self.fact_value_to_value(&state.get_result())
779 }
780 "max" => {
781 let mut state = MaxFunction.init();
782 for value in &matching_values {
783 state.accumulate(&self.value_to_fact_value(value));
784 }
785 self.fact_value_to_value(&state.get_result())
786 }
787 _ => {
788 return Err(RuleEngineError::EvaluationError {
789 message: format!("Unknown accumulate function: {}", function),
790 });
791 }
792 };
793
794 let result_key = format!("{}.{}", source_pattern, function);
797
798 facts.set(&result_key, result);
799
800 if self.config.debug_mode {
801 println!(" 🧮 Accumulate result: {} = {:?}", result_key, facts.get(&result_key));
802 }
803
804 Ok(())
805 }
806
807 fn value_to_fact_value(&self, value: &Value) -> crate::rete::facts::FactValue {
809 use crate::rete::facts::FactValue;
810 match value {
811 Value::Integer(i) => FactValue::Integer(*i),
812 Value::Number(n) => FactValue::Float(*n),
813 Value::String(s) => FactValue::String(s.clone()),
814 Value::Boolean(b) => FactValue::Boolean(*b),
815 _ => FactValue::String(value.to_string()),
816 }
817 }
818
819 fn fact_value_to_value(&self, fact_value: &crate::rete::facts::FactValue) -> Value {
821 use crate::rete::facts::FactValue;
822 match fact_value {
823 FactValue::Integer(i) => Value::Integer(*i),
824 FactValue::Float(f) => Value::Number(*f),
825 FactValue::String(s) => Value::String(s.clone()),
826 FactValue::Boolean(b) => Value::Boolean(*b),
827 FactValue::Array(_) => Value::String(format!("{:?}", fact_value)),
828 FactValue::Null => Value::String("null".to_string()),
829 }
830 }
831
832 fn evaluate_condition_string(&self, condition: &str, facts: &HashMap<String, Value>) -> bool {
834 let condition = condition.trim();
836
837 let operators = ["==", "!=", ">=", "<=", ">", "<"];
839
840 for op in &operators {
841 if let Some(pos) = condition.find(op) {
842 let field = condition[..pos].trim();
843 let value_str = condition[pos + op.len()..].trim()
844 .trim_matches('"')
845 .trim_matches('\'');
846
847 if let Some(field_value) = facts.get(field) {
848 return self.compare_values(field_value, op, value_str);
849 } else {
850 return false;
851 }
852 }
853 }
854
855 false
856 }
857
858 fn compare_values(&self, field_value: &Value, operator: &str, value_str: &str) -> bool {
860 match field_value {
861 Value::String(s) => {
862 match operator {
863 "==" => s == value_str,
864 "!=" => s != value_str,
865 _ => false,
866 }
867 }
868 Value::Integer(i) => {
869 if let Ok(num) = value_str.parse::<i64>() {
870 match operator {
871 "==" => *i == num,
872 "!=" => *i != num,
873 ">" => *i > num,
874 "<" => *i < num,
875 ">=" => *i >= num,
876 "<=" => *i <= num,
877 _ => false,
878 }
879 } else {
880 false
881 }
882 }
883 Value::Number(n) => {
884 if let Ok(num) = value_str.parse::<f64>() {
885 match operator {
886 "==" => (*n - num).abs() < f64::EPSILON,
887 "!=" => (*n - num).abs() >= f64::EPSILON,
888 ">" => *n > num,
889 "<" => *n < num,
890 ">=" => *n >= num,
891 "<=" => *n <= num,
892 _ => false,
893 }
894 } else {
895 false
896 }
897 }
898 Value::Boolean(b) => {
899 if let Ok(bool_val) = value_str.parse::<bool>() {
900 match operator {
901 "==" => *b == bool_val,
902 "!=" => *b != bool_val,
903 _ => false,
904 }
905 } else {
906 false
907 }
908 }
909 _ => false,
910 }
911 }
912
913 fn evaluate_rule_conditions(
915 &self,
916 rule: &crate::engine::rule::Rule,
917 facts: &Facts,
918 ) -> Result<bool> {
919 self.evaluate_conditions(&rule.conditions, facts)
920 }
921
922 fn is_retracted(&self, object_name: &str, facts: &Facts) -> bool {
924 let retract_key = format!("_retracted_{}", object_name);
925 matches!(facts.get(&retract_key), Some(Value::Boolean(true)))
926 }
927
928 fn evaluate_single_condition(
930 &self,
931 condition: &crate::engine::rule::Condition,
932 facts: &Facts,
933 ) -> Result<bool> {
934 use crate::engine::rule::ConditionExpression;
935
936 let result = match &condition.expression {
937 ConditionExpression::Field(field_name) => {
938 if let Some(object_name) = field_name.split('.').next() {
941 if self.is_retracted(object_name, facts) {
942 if self.config.debug_mode {
943 println!(" 🗑️ Skipping retracted fact: {}", object_name);
944 }
945 return Ok(false);
946 }
947 }
948
949 let field_value = facts
952 .get_nested(field_name)
953 .or_else(|| facts.get(field_name))
954 .unwrap_or(Value::Null);
955
956 if self.config.debug_mode {
957 println!(
958 " 🔎 Evaluating field condition: {} {} {:?}",
959 field_name,
960 format!("{:?}", condition.operator).to_lowercase(),
961 condition.value
962 );
963 println!(" Field value: {:?}", field_value);
964 }
965
966 let rhs = match &condition.value {
972 crate::types::Value::String(s) => {
973 facts
975 .get_nested(s)
976 .or_else(|| facts.get(s))
977 .unwrap_or(crate::types::Value::String(s.clone()))
978 }
979 crate::types::Value::Expression(expr) => {
980 match crate::expression::evaluate_expression(expr, facts) {
982 Ok(evaluated) => evaluated,
983 Err(_) => {
984 facts
986 .get_nested(expr)
987 .or_else(|| facts.get(expr))
988 .unwrap_or(crate::types::Value::Expression(expr.clone()))
989 }
990 }
991 }
992 _ => condition.value.clone(),
993 };
994
995 if self.config.debug_mode {
996 println!(" Resolved RHS for comparison: {:?}", rhs);
997 }
998
999 condition.operator.evaluate(&field_value, &rhs)
1000 }
1001 ConditionExpression::FunctionCall { name, args } => {
1002 if self.config.debug_mode {
1004 println!(
1005 " 🔎 Evaluating function condition: {}({:?}) {} {:?}",
1006 name,
1007 args,
1008 format!("{:?}", condition.operator).to_lowercase(),
1009 condition.value
1010 );
1011 }
1012
1013 if let Some(function) = self.custom_functions.get(name) {
1014 let arg_values: Vec<Value> = args
1016 .iter()
1017 .map(|arg| {
1018 facts
1019 .get_nested(arg)
1020 .or_else(|| facts.get(arg))
1021 .unwrap_or(Value::String(arg.clone()))
1022 })
1023 .collect();
1024
1025 match function(&arg_values, facts) {
1027 Ok(result_value) => {
1028 if self.config.debug_mode {
1029 println!(" Function result: {:?}", result_value);
1030 }
1031 condition.operator.evaluate(&result_value, &condition.value)
1032 }
1033 Err(e) => {
1034 if self.config.debug_mode {
1035 println!(" Function error: {}", e);
1036 }
1037 false
1038 }
1039 }
1040 } else {
1041 if self.config.debug_mode {
1042 println!(" Function '{}' not found", name);
1043 }
1044 false
1045 }
1046 }
1047 ConditionExpression::Test { name, args } => {
1048 if self.config.debug_mode {
1050 println!(" 🧪 Evaluating test CE: test({}({:?}))", name, args);
1051 }
1052
1053 if let Some(function) = self.custom_functions.get(name) {
1055 let arg_values: Vec<Value> = args
1057 .iter()
1058 .map(|arg| {
1059 let resolved = facts
1060 .get_nested(arg)
1061 .or_else(|| facts.get(arg))
1062 .unwrap_or(Value::String(arg.clone()));
1063 if self.config.debug_mode {
1064 println!(" Resolving arg '{}' -> {:?}", arg, resolved);
1065 }
1066 resolved
1067 })
1068 .collect();
1069
1070 match function(&arg_values, facts) {
1072 Ok(result_value) => {
1073 if self.config.debug_mode {
1074 println!(" Test result: {:?}", result_value);
1075 }
1076 match result_value {
1078 Value::Boolean(b) => b,
1079 Value::Integer(i) => i != 0,
1080 Value::Number(f) => f != 0.0,
1081 Value::String(s) => !s.is_empty(),
1082 _ => false,
1083 }
1084 }
1085 Err(e) => {
1086 if self.config.debug_mode {
1087 println!(" Test function error: {}", e);
1088 }
1089 false
1090 }
1091 }
1092 } else {
1093 if self.config.debug_mode {
1096 println!(" Trying to evaluate '{}' as arithmetic expression", name);
1097 }
1098
1099 match self.evaluate_arithmetic_condition(name, facts) {
1101 Ok(result) => {
1102 if self.config.debug_mode {
1103 println!(" Arithmetic expression result: {}", result);
1104 }
1105 result
1106 }
1107 Err(e) => {
1108 if self.config.debug_mode {
1109 println!(" Failed to evaluate expression: {}", e);
1110 println!(" Test function '{}' not found", name);
1111 }
1112 false
1113 }
1114 }
1115 }
1116 }
1117 ConditionExpression::MultiField { field, operation, variable: _ } => {
1118 if self.config.debug_mode {
1120 println!(" 📦 Evaluating multi-field: {}.{}", field, operation);
1121 }
1122
1123 let field_value = facts.get_nested(field).or_else(|| facts.get(field));
1125
1126 if let Some(value) = field_value {
1127 match operation.as_str() {
1128 "empty" => {
1129 matches!(value, Value::Array(arr) if arr.is_empty())
1130 }
1131 "not_empty" => {
1132 matches!(value, Value::Array(arr) if !arr.is_empty())
1133 }
1134 "count" => {
1135 if let Value::Array(arr) = value {
1136 let count = Value::Integer(arr.len() as i64);
1137 condition.operator.evaluate(&count, &condition.value)
1138 } else {
1139 false
1140 }
1141 }
1142 "contains" => {
1143 condition.operator.evaluate(&value, &condition.value)
1145 }
1146 _ => {
1147 if self.config.debug_mode {
1150 println!(" ⚠️ Operation '{}' not fully implemented yet", operation);
1151 }
1152 true
1153 }
1154 }
1155 } else {
1156 false
1157 }
1158 }
1159 };
1160
1161 if self.config.debug_mode {
1162 println!(" Result: {}", result);
1163 }
1164
1165 Ok(result)
1166 }
1167
1168 fn execute_action(&mut self, action: &ActionType, facts: &Facts) -> Result<()> {
1170 match action {
1171 ActionType::Set { field, value } => {
1172 let evaluated_value = match value {
1174 Value::Expression(expr) => {
1175 crate::expression::evaluate_expression(expr, facts)?
1177 }
1178 _ => value.clone(),
1179 };
1180
1181 if let Err(_) = facts.set_nested(field, evaluated_value.clone()) {
1183 facts.set(field, evaluated_value.clone());
1185 }
1186 if self.config.debug_mode {
1187 println!(" ✅ Set {field} = {evaluated_value:?}");
1188 }
1189 }
1190 ActionType::Log { message } => {
1191 println!("📋 LOG: {}", message);
1192 }
1193 ActionType::MethodCall {
1194 object,
1195 method,
1196 args,
1197 } => {
1198 let result = self.execute_method_call(object, method, args, facts)?;
1199 if self.config.debug_mode {
1200 println!(" 🔧 Called {object}.{method}({args:?}) -> {result}");
1201 }
1202 }
1203 ActionType::Retract { object } => {
1204 if self.config.debug_mode {
1205 println!(" 🗑️ Retracted {object}");
1206 }
1207 facts.set(&format!("_retracted_{}", object), Value::Boolean(true));
1209 }
1210 ActionType::Custom {
1211 action_type,
1212 params,
1213 } => {
1214 if let Some(handler) = self.action_handlers.get(action_type) {
1215 if self.config.debug_mode {
1216 println!(
1217 " 🎯 Executing custom action: {action_type} with params: {params:?}"
1218 );
1219 }
1220
1221 let resolved_params = self.resolve_action_parameters(params, facts)?;
1223
1224 handler(&resolved_params, facts)?;
1226 } else {
1227 if self.config.debug_mode {
1228 println!(" ⚠️ No handler registered for custom action: {action_type}");
1229 println!(
1230 " Available handlers: {:?}",
1231 self.action_handlers.keys().collect::<Vec<_>>()
1232 );
1233 }
1234
1235 return Err(RuleEngineError::EvaluationError {
1237 message: format!(
1238 "No action handler registered for '{action_type}'. Use engine.register_action_handler() to add custom action handlers."
1239 ),
1240 });
1241 }
1242 }
1243 ActionType::ActivateAgendaGroup { group } => {
1245 if self.config.debug_mode {
1246 println!(" 🎯 Activating agenda group: {}", group);
1247 }
1248 self.workflow_engine.activate_agenda_group(group.clone());
1250 self.agenda_manager.set_focus(group);
1251 }
1252 ActionType::ScheduleRule {
1253 rule_name,
1254 delay_ms,
1255 } => {
1256 if self.config.debug_mode {
1257 println!(
1258 " ⏰ Scheduling rule '{}' to execute in {}ms",
1259 rule_name, delay_ms
1260 );
1261 }
1262 self.workflow_engine
1263 .schedule_rule(rule_name.clone(), *delay_ms, None);
1264 }
1265 ActionType::CompleteWorkflow { workflow_name } => {
1266 if self.config.debug_mode {
1267 println!(" ✅ Completing workflow: {}", workflow_name);
1268 }
1269 self.workflow_engine
1270 .complete_workflow(workflow_name.clone());
1271 }
1272 ActionType::SetWorkflowData { key, value } => {
1273 if self.config.debug_mode {
1274 println!(" 💾 Setting workflow data: {} = {:?}", key, value);
1275 }
1276 let workflow_id = "default_workflow";
1279 self.workflow_engine
1280 .set_workflow_data(workflow_id, key.clone(), value.clone());
1281 }
1282 }
1283 Ok(())
1284 }
1285
1286 fn evaluate_arithmetic_condition(&self, expr: &str, facts: &Facts) -> Result<bool> {
1288 let operators = [">=", "<=", "==", "!=", ">", "<"];
1292 let mut split_pos = None;
1293 let mut found_op = "";
1294
1295 for op in &operators {
1296 if let Some(pos) = expr.rfind(op) {
1297 split_pos = Some(pos);
1298 found_op = op;
1299 break;
1300 }
1301 }
1302
1303 if split_pos.is_none() {
1304 return Err(RuleEngineError::EvaluationError {
1305 message: format!("No comparison operator found in expression: {}", expr),
1306 });
1307 }
1308
1309 let pos = split_pos.unwrap();
1310 let left_expr = expr[..pos].trim();
1311 let right_value = expr[pos + found_op.len()..].trim();
1312
1313 let left_result = crate::expression::evaluate_expression(left_expr, facts)?;
1315
1316 let right_val = if let Ok(i) = right_value.parse::<i64>() {
1318 Value::Integer(i)
1319 } else if let Ok(f) = right_value.parse::<f64>() {
1320 Value::Number(f)
1321 } else {
1322 match crate::expression::evaluate_expression(right_value, facts) {
1324 Ok(v) => v,
1325 Err(_) => Value::String(right_value.to_string()),
1326 }
1327 };
1328
1329 let operator = Operator::from_str(found_op).ok_or_else(|| {
1331 RuleEngineError::InvalidOperator {
1332 operator: found_op.to_string(),
1333 }
1334 })?;
1335
1336 Ok(operator.evaluate(&left_result, &right_val))
1337 }
1338
1339 fn execute_function_call(
1341 &self,
1342 function: &str,
1343 args: &[Value],
1344 facts: &Facts,
1345 ) -> Result<String> {
1346 let function_lower = function.to_lowercase();
1347
1348 match function_lower.as_str() {
1350 "log" | "print" | "println" => self.handle_log_function(args),
1351 "update" | "refresh" => self.handle_update_function(args),
1352 "now" | "timestamp" => self.handle_timestamp_function(),
1353 "random" => self.handle_random_function(args),
1354 "format" | "sprintf" => self.handle_format_function(args),
1355 "length" | "size" | "count" => self.handle_length_function(args),
1356 "sum" | "add" => self.handle_sum_function(args),
1357 "max" | "maximum" => self.handle_max_function(args),
1358 "min" | "minimum" => self.handle_min_function(args),
1359 "avg" | "average" => self.handle_average_function(args),
1360 "round" => self.handle_round_function(args),
1361 "floor" => self.handle_floor_function(args),
1362 "ceil" | "ceiling" => self.handle_ceil_function(args),
1363 "abs" | "absolute" => self.handle_abs_function(args),
1364 "contains" | "includes" => self.handle_contains_function(args),
1365 "startswith" | "begins_with" => self.handle_starts_with_function(args),
1366 "endswith" | "ends_with" => self.handle_ends_with_function(args),
1367 "lowercase" | "tolower" => self.handle_lowercase_function(args),
1368 "uppercase" | "toupper" => self.handle_uppercase_function(args),
1369 "trim" | "strip" => self.handle_trim_function(args),
1370 "split" => self.handle_split_function(args),
1371 "join" => self.handle_join_function(args),
1372 _ => {
1373 self.handle_custom_function(function, args, facts)
1375 }
1376 }
1377 }
1378
1379 fn handle_log_function(&self, args: &[Value]) -> Result<String> {
1381 let message = if args.is_empty() {
1382 "".to_string()
1383 } else if args.len() == 1 {
1384 args[0].to_string()
1385 } else {
1386 args.iter()
1387 .map(|v| v.to_string())
1388 .collect::<Vec<_>>()
1389 .join(" ")
1390 };
1391
1392 println!("📋 {}", message);
1393 Ok(message)
1394 }
1395
1396 fn handle_update_function(&self, args: &[Value]) -> Result<String> {
1398 if let Some(arg) = args.first() {
1399 Ok(format!("Updated: {}", arg.to_string()))
1400 } else {
1401 Ok("Updated".to_string())
1402 }
1403 }
1404
1405 fn handle_timestamp_function(&self) -> Result<String> {
1407 use std::time::{SystemTime, UNIX_EPOCH};
1408 let timestamp = SystemTime::now()
1409 .duration_since(UNIX_EPOCH)
1410 .map_err(|e| RuleEngineError::EvaluationError {
1411 message: format!("Failed to get timestamp: {}", e),
1412 })?
1413 .as_secs();
1414 Ok(timestamp.to_string())
1415 }
1416
1417 fn handle_random_function(&self, args: &[Value]) -> Result<String> {
1419 use std::collections::hash_map::DefaultHasher;
1420 use std::hash::{Hash, Hasher};
1421
1422 let mut hasher = DefaultHasher::new();
1424 std::time::SystemTime::now().hash(&mut hasher);
1425 let random_value = hasher.finish();
1426
1427 if args.is_empty() {
1428 Ok((random_value % 100).to_string()) } else if let Some(Value::Number(max)) = args.first() {
1430 let max_val = *max as u64;
1431 Ok((random_value % max_val).to_string())
1432 } else {
1433 Ok(random_value.to_string())
1434 }
1435 }
1436
1437 fn handle_format_function(&self, args: &[Value]) -> Result<String> {
1439 if args.is_empty() {
1440 return Ok("".to_string());
1441 }
1442
1443 let template = args[0].to_string();
1444 let values: Vec<String> = args[1..].iter().map(|v| v.to_string()).collect();
1445
1446 let mut result = template;
1448 for (i, value) in values.iter().enumerate() {
1449 result = result.replace(&format!("{{{}}}", i), value);
1450 }
1451
1452 Ok(result)
1453 }
1454
1455 fn handle_length_function(&self, args: &[Value]) -> Result<String> {
1457 if let Some(arg) = args.first() {
1458 match arg {
1459 Value::String(s) => Ok(s.len().to_string()),
1460 Value::Array(arr) => Ok(arr.len().to_string()),
1461 Value::Object(obj) => Ok(obj.len().to_string()),
1462 _ => Ok("1".to_string()), }
1464 } else {
1465 Ok("0".to_string())
1466 }
1467 }
1468
1469 fn handle_sum_function(&self, args: &[Value]) -> Result<String> {
1471 let sum = args.iter().fold(0.0, |acc, val| match val {
1472 Value::Number(n) => acc + n,
1473 Value::Integer(i) => acc + (*i as f64),
1474 _ => acc,
1475 });
1476 Ok(sum.to_string())
1477 }
1478
1479 fn handle_max_function(&self, args: &[Value]) -> Result<String> {
1481 let max = args.iter().fold(f64::NEG_INFINITY, |acc, val| match val {
1482 Value::Number(n) => acc.max(*n),
1483 Value::Integer(i) => acc.max(*i as f64),
1484 _ => acc,
1485 });
1486 Ok(max.to_string())
1487 }
1488
1489 fn handle_min_function(&self, args: &[Value]) -> Result<String> {
1491 let min = args.iter().fold(f64::INFINITY, |acc, val| match val {
1492 Value::Number(n) => acc.min(*n),
1493 Value::Integer(i) => acc.min(*i as f64),
1494 _ => acc,
1495 });
1496 Ok(min.to_string())
1497 }
1498
1499 fn handle_average_function(&self, args: &[Value]) -> Result<String> {
1501 if args.is_empty() {
1502 return Ok("0".to_string());
1503 }
1504
1505 let (sum, count) = args.iter().fold((0.0, 0), |(sum, count), val| match val {
1506 Value::Number(n) => (sum + n, count + 1),
1507 Value::Integer(i) => (sum + (*i as f64), count + 1),
1508 _ => (sum, count),
1509 });
1510
1511 if count > 0 {
1512 Ok((sum / count as f64).to_string())
1513 } else {
1514 Ok("0".to_string())
1515 }
1516 }
1517
1518 fn handle_round_function(&self, args: &[Value]) -> Result<String> {
1520 if let Some(Value::Number(n)) = args.first() {
1521 Ok(n.round().to_string())
1522 } else if let Some(Value::Integer(i)) = args.first() {
1523 Ok(i.to_string())
1524 } else {
1525 Err(RuleEngineError::EvaluationError {
1526 message: "round() requires a numeric argument".to_string(),
1527 })
1528 }
1529 }
1530
1531 fn handle_floor_function(&self, args: &[Value]) -> Result<String> {
1532 if let Some(Value::Number(n)) = args.first() {
1533 Ok(n.floor().to_string())
1534 } else if let Some(Value::Integer(i)) = args.first() {
1535 Ok(i.to_string())
1536 } else {
1537 Err(RuleEngineError::EvaluationError {
1538 message: "floor() requires a numeric argument".to_string(),
1539 })
1540 }
1541 }
1542
1543 fn handle_ceil_function(&self, args: &[Value]) -> Result<String> {
1544 if let Some(Value::Number(n)) = args.first() {
1545 Ok(n.ceil().to_string())
1546 } else if let Some(Value::Integer(i)) = args.first() {
1547 Ok(i.to_string())
1548 } else {
1549 Err(RuleEngineError::EvaluationError {
1550 message: "ceil() requires a numeric argument".to_string(),
1551 })
1552 }
1553 }
1554
1555 fn handle_abs_function(&self, args: &[Value]) -> Result<String> {
1556 if let Some(Value::Number(n)) = args.first() {
1557 Ok(n.abs().to_string())
1558 } else if let Some(Value::Integer(i)) = args.first() {
1559 Ok(i.abs().to_string())
1560 } else {
1561 Err(RuleEngineError::EvaluationError {
1562 message: "abs() requires a numeric argument".to_string(),
1563 })
1564 }
1565 }
1566
1567 fn handle_contains_function(&self, args: &[Value]) -> Result<String> {
1569 if args.len() >= 2 {
1570 let haystack = args[0].to_string();
1571 let needle = args[1].to_string();
1572 Ok(haystack.contains(&needle).to_string())
1573 } else {
1574 Err(RuleEngineError::EvaluationError {
1575 message: "contains() requires 2 arguments".to_string(),
1576 })
1577 }
1578 }
1579
1580 fn handle_starts_with_function(&self, args: &[Value]) -> Result<String> {
1581 if args.len() >= 2 {
1582 let text = args[0].to_string();
1583 let prefix = args[1].to_string();
1584 Ok(text.starts_with(&prefix).to_string())
1585 } else {
1586 Err(RuleEngineError::EvaluationError {
1587 message: "startswith() requires 2 arguments".to_string(),
1588 })
1589 }
1590 }
1591
1592 fn handle_ends_with_function(&self, args: &[Value]) -> Result<String> {
1593 if args.len() >= 2 {
1594 let text = args[0].to_string();
1595 let suffix = args[1].to_string();
1596 Ok(text.ends_with(&suffix).to_string())
1597 } else {
1598 Err(RuleEngineError::EvaluationError {
1599 message: "endswith() requires 2 arguments".to_string(),
1600 })
1601 }
1602 }
1603
1604 fn handle_lowercase_function(&self, args: &[Value]) -> Result<String> {
1605 if let Some(arg) = args.first() {
1606 Ok(arg.to_string().to_lowercase())
1607 } else {
1608 Err(RuleEngineError::EvaluationError {
1609 message: "lowercase() requires 1 argument".to_string(),
1610 })
1611 }
1612 }
1613
1614 fn handle_uppercase_function(&self, args: &[Value]) -> Result<String> {
1615 if let Some(arg) = args.first() {
1616 Ok(arg.to_string().to_uppercase())
1617 } else {
1618 Err(RuleEngineError::EvaluationError {
1619 message: "uppercase() requires 1 argument".to_string(),
1620 })
1621 }
1622 }
1623
1624 fn handle_trim_function(&self, args: &[Value]) -> Result<String> {
1625 if let Some(arg) = args.first() {
1626 Ok(arg.to_string().trim().to_string())
1627 } else {
1628 Err(RuleEngineError::EvaluationError {
1629 message: "trim() requires 1 argument".to_string(),
1630 })
1631 }
1632 }
1633
1634 fn handle_split_function(&self, args: &[Value]) -> Result<String> {
1635 if args.len() >= 2 {
1636 let text = args[0].to_string();
1637 let delimiter = args[1].to_string();
1638 let parts: Vec<String> = text.split(&delimiter).map(|s| s.to_string()).collect();
1639 Ok(format!("{:?}", parts)) } else {
1641 Err(RuleEngineError::EvaluationError {
1642 message: "split() requires 2 arguments".to_string(),
1643 })
1644 }
1645 }
1646
1647 fn handle_join_function(&self, args: &[Value]) -> Result<String> {
1648 if args.len() >= 2 {
1649 let delimiter = args[0].to_string();
1650 let parts: Vec<String> = args[1..].iter().map(|v| v.to_string()).collect();
1651 Ok(parts.join(&delimiter))
1652 } else {
1653 Err(RuleEngineError::EvaluationError {
1654 message: "join() requires at least 2 arguments".to_string(),
1655 })
1656 }
1657 }
1658
1659 fn handle_custom_function(
1661 &self,
1662 function: &str,
1663 args: &[Value],
1664 facts: &Facts,
1665 ) -> Result<String> {
1666 if let Some(custom_func) = self.custom_functions.get(function) {
1668 if self.config.debug_mode {
1669 println!("🎯 Calling registered function: {}({:?})", function, args);
1670 }
1671
1672 match custom_func(args, facts) {
1673 Ok(result) => Ok(result.to_string()),
1674 Err(e) => Err(e),
1675 }
1676 } else {
1677 if self.config.debug_mode {
1679 println!("⚠️ Custom function '{}' not registered", function);
1680 }
1681
1682 Err(RuleEngineError::EvaluationError {
1683 message: format!("Function '{}' is not registered. Use engine.register_function() to add custom functions.", function),
1684 })
1685 }
1686 }
1687
1688 fn execute_method_call(
1690 &self,
1691 object_name: &str,
1692 method: &str,
1693 args: &[Value],
1694 facts: &Facts,
1695 ) -> Result<String> {
1696 let Some(object_value) = facts.get(object_name) else {
1698 return Err(RuleEngineError::EvaluationError {
1699 message: format!("Object '{}' not found in facts", object_name),
1700 });
1701 };
1702
1703 let method_lower = method.to_lowercase();
1704
1705 if method_lower.starts_with("set") && args.len() == 1 {
1707 return self.handle_setter_method(object_name, method, &args[0], object_value, facts);
1708 }
1709
1710 if method_lower.starts_with("get") && args.is_empty() {
1712 return self.handle_getter_method(object_name, method, &object_value);
1713 }
1714
1715 match method_lower.as_str() {
1717 "tostring" => Ok(object_value.to_string()),
1718 "update" => {
1719 facts.add_value(object_name, object_value)?;
1720 Ok(format!("Updated {}", object_name))
1721 }
1722 "reset" => self.handle_reset_method(object_name, object_value, facts),
1723 _ => self.handle_property_access_or_fallback(
1724 object_name,
1725 method,
1726 args.len(),
1727 &object_value,
1728 ),
1729 }
1730 }
1731
1732 fn handle_setter_method(
1734 &self,
1735 object_name: &str,
1736 method: &str,
1737 new_value: &Value,
1738 mut object_value: Value,
1739 facts: &Facts,
1740 ) -> Result<String> {
1741 let property_name = Self::extract_property_name_from_setter(method);
1742
1743 match object_value {
1744 Value::Object(ref mut obj) => {
1745 obj.insert(property_name.clone(), new_value.clone());
1746 facts.add_value(object_name, object_value)?;
1747 Ok(format!(
1748 "Set {} to {}",
1749 property_name,
1750 new_value.to_string()
1751 ))
1752 }
1753 _ => Err(RuleEngineError::EvaluationError {
1754 message: format!("Cannot call setter on non-object type: {}", object_name),
1755 }),
1756 }
1757 }
1758
1759 fn handle_getter_method(
1761 &self,
1762 object_name: &str,
1763 method: &str,
1764 object_value: &Value,
1765 ) -> Result<String> {
1766 let property_name = Self::extract_property_name_from_getter(method);
1767
1768 match object_value {
1769 Value::Object(obj) => {
1770 if let Some(value) = obj.get(&property_name) {
1771 Ok(value.to_string())
1772 } else {
1773 Err(RuleEngineError::EvaluationError {
1774 message: format!(
1775 "Property '{}' not found on object '{}'",
1776 property_name, object_name
1777 ),
1778 })
1779 }
1780 }
1781 _ => Err(RuleEngineError::EvaluationError {
1782 message: format!("Cannot call getter on non-object type: {}", object_name),
1783 }),
1784 }
1785 }
1786
1787 fn handle_reset_method(
1789 &self,
1790 object_name: &str,
1791 mut object_value: Value,
1792 facts: &Facts,
1793 ) -> Result<String> {
1794 match object_value {
1795 Value::Object(ref mut obj) => {
1796 obj.clear();
1797 facts.add_value(object_name, object_value)?;
1798 Ok(format!("Reset {}", object_name))
1799 }
1800 _ => Err(RuleEngineError::EvaluationError {
1801 message: format!("Cannot reset non-object type: {}", object_name),
1802 }),
1803 }
1804 }
1805
1806 fn handle_property_access_or_fallback(
1808 &self,
1809 object_name: &str,
1810 method: &str,
1811 arg_count: usize,
1812 object_value: &Value,
1813 ) -> Result<String> {
1814 if let Value::Object(obj) = object_value {
1815 if let Some(value) = obj.get(method) {
1817 return Ok(value.to_string());
1818 }
1819
1820 let capitalized_method = Self::capitalize_first_letter(method);
1822 if let Some(value) = obj.get(&capitalized_method) {
1823 return Ok(value.to_string());
1824 }
1825 }
1826
1827 Ok(format!(
1829 "Called {}.{} with {} args",
1830 object_name, method, arg_count
1831 ))
1832 }
1833
1834 fn extract_property_name_from_setter(method: &str) -> String {
1836 let property_name = &method[3..]; Self::capitalize_first_letter(property_name)
1838 }
1839
1840 fn extract_property_name_from_getter(method: &str) -> String {
1842 let property_name = &method[3..]; Self::capitalize_first_letter(property_name)
1844 }
1845
1846 fn capitalize_first_letter(s: &str) -> String {
1848 if s.is_empty() {
1849 return String::new();
1850 }
1851 let mut chars = s.chars();
1852 match chars.next() {
1853 None => String::new(),
1854 Some(first) => first.to_uppercase().collect::<String>() + chars.as_str(),
1855 }
1856 }
1857
1858 fn resolve_action_parameters(
1860 &self,
1861 params: &HashMap<String, Value>,
1862 facts: &Facts,
1863 ) -> Result<HashMap<String, Value>> {
1864 let mut resolved = HashMap::new();
1865
1866 for (key, value) in params {
1867 let resolved_value = match value {
1868 Value::String(s) => {
1869 if s.contains('.') {
1871 if let Some(fact_value) = facts.get_nested(s) {
1873 fact_value
1874 } else {
1875 value.clone()
1877 }
1878 } else {
1879 value.clone()
1880 }
1881 }
1882 _ => value.clone(),
1883 };
1884 resolved.insert(key.clone(), resolved_value);
1885 }
1886
1887 Ok(resolved)
1888 }
1889
1890 pub fn load_plugin(
1894 &mut self,
1895 plugin: std::sync::Arc<dyn crate::engine::plugin::RulePlugin>,
1896 ) -> Result<()> {
1897 plugin.register_actions(self)?;
1899 plugin.register_functions(self)?;
1900
1901 self.plugin_manager.load_plugin(plugin)
1903 }
1904
1905 pub fn unload_plugin(&mut self, name: &str) -> Result<()> {
1907 self.plugin_manager.unload_plugin(name)
1908 }
1909
1910 pub fn hot_reload_plugin(
1912 &mut self,
1913 name: &str,
1914 new_plugin: std::sync::Arc<dyn crate::engine::plugin::RulePlugin>,
1915 ) -> Result<()> {
1916 self.plugin_manager.unload_plugin(name)?;
1918
1919 new_plugin.register_actions(self)?;
1921 new_plugin.register_functions(self)?;
1922
1923 self.plugin_manager.load_plugin(new_plugin)
1925 }
1926
1927 pub fn get_plugin_info(&self, name: &str) -> Option<&crate::engine::plugin::PluginMetadata> {
1929 self.plugin_manager.get_plugin_info(name)
1930 }
1931
1932 pub fn list_plugins(&self) -> Vec<PluginInfo> {
1934 self.plugin_manager.list_plugins()
1935 }
1936
1937 pub fn get_plugin_stats(&self) -> PluginStats {
1939 self.plugin_manager.get_stats()
1940 }
1941
1942 pub fn plugin_health_check(&mut self) -> HashMap<String, crate::engine::plugin::PluginHealth> {
1944 self.plugin_manager.plugin_health_check()
1945 }
1946
1947 pub fn configure_plugins(&mut self, config: PluginConfig) {
1949 self.plugin_manager = PluginManager::new(config);
1950 }
1951}