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, &str),
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"); }
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
951 .get_nested(field_name)
952 .or_else(|| facts.get(field_name));
953
954 if self.config.debug_mode {
955 println!(
956 " 🔎 Evaluating field condition: {} {} {:?}",
957 field_name,
958 format!("{:?}", condition.operator).to_lowercase(),
959 condition.value
960 );
961 println!(" Field value: {:?}", field_value);
962 }
963
964 if let Some(value) = field_value {
965 let rhs = match &condition.value {
971 crate::types::Value::String(s) => {
972 facts
974 .get_nested(s)
975 .or_else(|| facts.get(s))
976 .unwrap_or(crate::types::Value::String(s.clone()))
977 }
978 crate::types::Value::Expression(expr) => {
979 match crate::expression::evaluate_expression(expr, facts) {
981 Ok(evaluated) => evaluated,
982 Err(_) => {
983 facts
985 .get_nested(expr)
986 .or_else(|| facts.get(expr))
987 .unwrap_or(crate::types::Value::Expression(expr.clone()))
988 }
989 }
990 }
991 _ => condition.value.clone(),
992 };
993
994 if self.config.debug_mode {
995 println!(" Resolved RHS for comparison: {:?}", rhs);
996 }
997
998 condition.operator.evaluate(&value, &rhs)
999 } else {
1000 false
1001 }
1002 }
1003 ConditionExpression::FunctionCall { name, args } => {
1004 if self.config.debug_mode {
1006 println!(
1007 " 🔎 Evaluating function condition: {}({:?}) {} {:?}",
1008 name,
1009 args,
1010 format!("{:?}", condition.operator).to_lowercase(),
1011 condition.value
1012 );
1013 }
1014
1015 if let Some(function) = self.custom_functions.get(name) {
1016 let arg_values: Vec<Value> = args
1018 .iter()
1019 .map(|arg| {
1020 facts
1021 .get_nested(arg)
1022 .or_else(|| facts.get(arg))
1023 .unwrap_or(Value::String(arg.clone()))
1024 })
1025 .collect();
1026
1027 match function(&arg_values, facts) {
1029 Ok(result_value) => {
1030 if self.config.debug_mode {
1031 println!(" Function result: {:?}", result_value);
1032 }
1033 condition.operator.evaluate(&result_value, &condition.value)
1034 }
1035 Err(e) => {
1036 if self.config.debug_mode {
1037 println!(" Function error: {}", e);
1038 }
1039 false
1040 }
1041 }
1042 } else {
1043 if self.config.debug_mode {
1044 println!(" Function '{}' not found", name);
1045 }
1046 false
1047 }
1048 }
1049 ConditionExpression::Test { name, args } => {
1050 if self.config.debug_mode {
1052 println!(" 🧪 Evaluating test CE: test({}({:?}))", name, args);
1053 }
1054
1055 if let Some(function) = self.custom_functions.get(name) {
1057 let arg_values: Vec<Value> = args
1059 .iter()
1060 .map(|arg| {
1061 let resolved = facts
1062 .get_nested(arg)
1063 .or_else(|| facts.get(arg))
1064 .unwrap_or(Value::String(arg.clone()));
1065 if self.config.debug_mode {
1066 println!(" Resolving arg '{}' -> {:?}", arg, resolved);
1067 }
1068 resolved
1069 })
1070 .collect();
1071
1072 match function(&arg_values, facts) {
1074 Ok(result_value) => {
1075 if self.config.debug_mode {
1076 println!(" Test result: {:?}", result_value);
1077 }
1078 match result_value {
1080 Value::Boolean(b) => b,
1081 Value::Integer(i) => i != 0,
1082 Value::Number(f) => f != 0.0,
1083 Value::String(s) => !s.is_empty(),
1084 _ => false,
1085 }
1086 }
1087 Err(e) => {
1088 if self.config.debug_mode {
1089 println!(" Test function error: {}", e);
1090 }
1091 false
1092 }
1093 }
1094 } else {
1095 if self.config.debug_mode {
1098 println!(" Trying to evaluate '{}' as arithmetic expression", name);
1099 }
1100
1101 match self.evaluate_arithmetic_condition(name, facts) {
1103 Ok(result) => {
1104 if self.config.debug_mode {
1105 println!(" Arithmetic expression result: {}", result);
1106 }
1107 result
1108 }
1109 Err(e) => {
1110 if self.config.debug_mode {
1111 println!(" Failed to evaluate expression: {}", e);
1112 println!(" Test function '{}' not found", name);
1113 }
1114 false
1115 }
1116 }
1117 }
1118 }
1119 ConditionExpression::MultiField { field, operation, variable: _ } => {
1120 if self.config.debug_mode {
1122 println!(" 📦 Evaluating multi-field: {}.{}", field, operation);
1123 }
1124
1125 let field_value = facts.get_nested(field).or_else(|| facts.get(field));
1127
1128 if let Some(value) = field_value {
1129 match operation.as_str() {
1130 "empty" => {
1131 matches!(value, Value::Array(arr) if arr.is_empty())
1132 }
1133 "not_empty" => {
1134 matches!(value, Value::Array(arr) if !arr.is_empty())
1135 }
1136 "count" => {
1137 if let Value::Array(arr) = value {
1138 let count = Value::Integer(arr.len() as i64);
1139 condition.operator.evaluate(&count, &condition.value)
1140 } else {
1141 false
1142 }
1143 }
1144 "contains" => {
1145 condition.operator.evaluate(&value, &condition.value)
1147 }
1148 _ => {
1149 if self.config.debug_mode {
1152 println!(" ⚠️ Operation '{}' not fully implemented yet", operation);
1153 }
1154 true
1155 }
1156 }
1157 } else {
1158 false
1159 }
1160 }
1161 };
1162
1163 if self.config.debug_mode {
1164 println!(" Result: {}", result);
1165 }
1166
1167 Ok(result)
1168 }
1169
1170 fn execute_action(&mut self, action: &ActionType, facts: &Facts) -> Result<()> {
1172 match action {
1173 ActionType::Set { field, value } => {
1174 let evaluated_value = match value {
1176 Value::Expression(expr) => {
1177 crate::expression::evaluate_expression(expr, facts)?
1179 }
1180 _ => value.clone(),
1181 };
1182
1183 if let Err(_) = facts.set_nested(field, evaluated_value.clone()) {
1185 facts.set(field, evaluated_value.clone());
1187 }
1188 if self.config.debug_mode {
1189 println!(" ✅ Set {field} = {evaluated_value:?}");
1190 }
1191 }
1192 ActionType::Log { message } => {
1193 println!("📋 LOG: {}", message);
1194 }
1195 ActionType::MethodCall {
1196 object,
1197 method,
1198 args,
1199 } => {
1200 let result = self.execute_method_call(object, method, args, facts)?;
1201 if self.config.debug_mode {
1202 println!(" 🔧 Called {object}.{method}({args:?}) -> {result}");
1203 }
1204 }
1205 ActionType::Retract { object } => {
1206 if self.config.debug_mode {
1207 println!(" 🗑️ Retracted {object}");
1208 }
1209 facts.set(&format!("_retracted_{}", object), Value::Boolean(true));
1211 }
1212 ActionType::Custom {
1213 action_type,
1214 params,
1215 } => {
1216 if let Some(handler) = self.action_handlers.get(action_type) {
1217 if self.config.debug_mode {
1218 println!(
1219 " 🎯 Executing custom action: {action_type} with params: {params:?}"
1220 );
1221 }
1222
1223 let resolved_params = self.resolve_action_parameters(params, facts)?;
1225
1226 handler(&resolved_params, facts)?;
1228 } else {
1229 if self.config.debug_mode {
1230 println!(" ⚠️ No handler registered for custom action: {action_type}");
1231 println!(
1232 " Available handlers: {:?}",
1233 self.action_handlers.keys().collect::<Vec<_>>()
1234 );
1235 }
1236
1237 return Err(RuleEngineError::EvaluationError {
1239 message: format!(
1240 "No action handler registered for '{action_type}'. Use engine.register_action_handler() to add custom action handlers."
1241 ),
1242 });
1243 }
1244 }
1245 ActionType::ActivateAgendaGroup { group } => {
1247 if self.config.debug_mode {
1248 println!(" 🎯 Activating agenda group: {}", group);
1249 }
1250 self.workflow_engine.activate_agenda_group(group.clone());
1252 self.agenda_manager.set_focus(group);
1253 }
1254 ActionType::ScheduleRule {
1255 rule_name,
1256 delay_ms,
1257 } => {
1258 if self.config.debug_mode {
1259 println!(
1260 " ⏰ Scheduling rule '{}' to execute in {}ms",
1261 rule_name, delay_ms
1262 );
1263 }
1264 self.workflow_engine
1265 .schedule_rule(rule_name.clone(), *delay_ms, None);
1266 }
1267 ActionType::CompleteWorkflow { workflow_name } => {
1268 if self.config.debug_mode {
1269 println!(" ✅ Completing workflow: {}", workflow_name);
1270 }
1271 self.workflow_engine
1272 .complete_workflow(workflow_name.clone());
1273 }
1274 ActionType::SetWorkflowData { key, value } => {
1275 if self.config.debug_mode {
1276 println!(" 💾 Setting workflow data: {} = {:?}", key, value);
1277 }
1278 let workflow_id = "default_workflow";
1281 self.workflow_engine
1282 .set_workflow_data(workflow_id, key.clone(), value.clone());
1283 }
1284 }
1285 Ok(())
1286 }
1287
1288 fn evaluate_arithmetic_condition(&self, expr: &str, facts: &Facts) -> Result<bool> {
1290 let operators = [">=", "<=", "==", "!=", ">", "<"];
1294 let mut split_pos = None;
1295 let mut found_op = "";
1296
1297 for op in &operators {
1298 if let Some(pos) = expr.rfind(op) {
1299 split_pos = Some(pos);
1300 found_op = op;
1301 break;
1302 }
1303 }
1304
1305 if split_pos.is_none() {
1306 return Err(RuleEngineError::EvaluationError {
1307 message: format!("No comparison operator found in expression: {}", expr),
1308 });
1309 }
1310
1311 let pos = split_pos.unwrap();
1312 let left_expr = expr[..pos].trim();
1313 let right_value = expr[pos + found_op.len()..].trim();
1314
1315 let left_result = crate::expression::evaluate_expression(left_expr, facts)?;
1317
1318 let right_val = if let Ok(i) = right_value.parse::<i64>() {
1320 Value::Integer(i)
1321 } else if let Ok(f) = right_value.parse::<f64>() {
1322 Value::Number(f)
1323 } else {
1324 match crate::expression::evaluate_expression(right_value, facts) {
1326 Ok(v) => v,
1327 Err(_) => Value::String(right_value.to_string()),
1328 }
1329 };
1330
1331 let operator = Operator::from_str(found_op).ok_or_else(|| {
1333 RuleEngineError::InvalidOperator {
1334 operator: found_op.to_string(),
1335 }
1336 })?;
1337
1338 Ok(operator.evaluate(&left_result, &right_val))
1339 }
1340
1341 fn execute_function_call(
1343 &self,
1344 function: &str,
1345 args: &[Value],
1346 facts: &Facts,
1347 ) -> Result<String> {
1348 let function_lower = function.to_lowercase();
1349
1350 match function_lower.as_str() {
1352 "log" | "print" | "println" => self.handle_log_function(args),
1353 "update" | "refresh" => self.handle_update_function(args),
1354 "now" | "timestamp" => self.handle_timestamp_function(),
1355 "random" => self.handle_random_function(args),
1356 "format" | "sprintf" => self.handle_format_function(args),
1357 "length" | "size" | "count" => self.handle_length_function(args),
1358 "sum" | "add" => self.handle_sum_function(args),
1359 "max" | "maximum" => self.handle_max_function(args),
1360 "min" | "minimum" => self.handle_min_function(args),
1361 "avg" | "average" => self.handle_average_function(args),
1362 "round" => self.handle_round_function(args),
1363 "floor" => self.handle_floor_function(args),
1364 "ceil" | "ceiling" => self.handle_ceil_function(args),
1365 "abs" | "absolute" => self.handle_abs_function(args),
1366 "contains" | "includes" => self.handle_contains_function(args),
1367 "startswith" | "begins_with" => self.handle_starts_with_function(args),
1368 "endswith" | "ends_with" => self.handle_ends_with_function(args),
1369 "lowercase" | "tolower" => self.handle_lowercase_function(args),
1370 "uppercase" | "toupper" => self.handle_uppercase_function(args),
1371 "trim" | "strip" => self.handle_trim_function(args),
1372 "split" => self.handle_split_function(args),
1373 "join" => self.handle_join_function(args),
1374 _ => {
1375 self.handle_custom_function(function, args, facts)
1377 }
1378 }
1379 }
1380
1381 fn handle_log_function(&self, args: &[Value]) -> Result<String> {
1383 let message = if args.is_empty() {
1384 "".to_string()
1385 } else if args.len() == 1 {
1386 args[0].to_string()
1387 } else {
1388 args.iter()
1389 .map(|v| v.to_string())
1390 .collect::<Vec<_>>()
1391 .join(" ")
1392 };
1393
1394 println!("📋 {}", message);
1395 Ok(message)
1396 }
1397
1398 fn handle_update_function(&self, args: &[Value]) -> Result<String> {
1400 if let Some(arg) = args.first() {
1401 Ok(format!("Updated: {}", arg.to_string()))
1402 } else {
1403 Ok("Updated".to_string())
1404 }
1405 }
1406
1407 fn handle_timestamp_function(&self) -> Result<String> {
1409 use std::time::{SystemTime, UNIX_EPOCH};
1410 let timestamp = SystemTime::now()
1411 .duration_since(UNIX_EPOCH)
1412 .map_err(|e| RuleEngineError::EvaluationError {
1413 message: format!("Failed to get timestamp: {}", e),
1414 })?
1415 .as_secs();
1416 Ok(timestamp.to_string())
1417 }
1418
1419 fn handle_random_function(&self, args: &[Value]) -> Result<String> {
1421 use std::collections::hash_map::DefaultHasher;
1422 use std::hash::{Hash, Hasher};
1423
1424 let mut hasher = DefaultHasher::new();
1426 std::time::SystemTime::now().hash(&mut hasher);
1427 let random_value = hasher.finish();
1428
1429 if args.is_empty() {
1430 Ok((random_value % 100).to_string()) } else if let Some(Value::Number(max)) = args.first() {
1432 let max_val = *max as u64;
1433 Ok((random_value % max_val).to_string())
1434 } else {
1435 Ok(random_value.to_string())
1436 }
1437 }
1438
1439 fn handle_format_function(&self, args: &[Value]) -> Result<String> {
1441 if args.is_empty() {
1442 return Ok("".to_string());
1443 }
1444
1445 let template = args[0].to_string();
1446 let values: Vec<String> = args[1..].iter().map(|v| v.to_string()).collect();
1447
1448 let mut result = template;
1450 for (i, value) in values.iter().enumerate() {
1451 result = result.replace(&format!("{{{}}}", i), value);
1452 }
1453
1454 Ok(result)
1455 }
1456
1457 fn handle_length_function(&self, args: &[Value]) -> Result<String> {
1459 if let Some(arg) = args.first() {
1460 match arg {
1461 Value::String(s) => Ok(s.len().to_string()),
1462 Value::Array(arr) => Ok(arr.len().to_string()),
1463 Value::Object(obj) => Ok(obj.len().to_string()),
1464 _ => Ok("1".to_string()), }
1466 } else {
1467 Ok("0".to_string())
1468 }
1469 }
1470
1471 fn handle_sum_function(&self, args: &[Value]) -> Result<String> {
1473 let sum = args.iter().fold(0.0, |acc, val| match val {
1474 Value::Number(n) => acc + n,
1475 Value::Integer(i) => acc + (*i as f64),
1476 _ => acc,
1477 });
1478 Ok(sum.to_string())
1479 }
1480
1481 fn handle_max_function(&self, args: &[Value]) -> Result<String> {
1483 let max = args.iter().fold(f64::NEG_INFINITY, |acc, val| match val {
1484 Value::Number(n) => acc.max(*n),
1485 Value::Integer(i) => acc.max(*i as f64),
1486 _ => acc,
1487 });
1488 Ok(max.to_string())
1489 }
1490
1491 fn handle_min_function(&self, args: &[Value]) -> Result<String> {
1493 let min = args.iter().fold(f64::INFINITY, |acc, val| match val {
1494 Value::Number(n) => acc.min(*n),
1495 Value::Integer(i) => acc.min(*i as f64),
1496 _ => acc,
1497 });
1498 Ok(min.to_string())
1499 }
1500
1501 fn handle_average_function(&self, args: &[Value]) -> Result<String> {
1503 if args.is_empty() {
1504 return Ok("0".to_string());
1505 }
1506
1507 let (sum, count) = args.iter().fold((0.0, 0), |(sum, count), val| match val {
1508 Value::Number(n) => (sum + n, count + 1),
1509 Value::Integer(i) => (sum + (*i as f64), count + 1),
1510 _ => (sum, count),
1511 });
1512
1513 if count > 0 {
1514 Ok((sum / count as f64).to_string())
1515 } else {
1516 Ok("0".to_string())
1517 }
1518 }
1519
1520 fn handle_round_function(&self, args: &[Value]) -> Result<String> {
1522 if let Some(Value::Number(n)) = args.first() {
1523 Ok(n.round().to_string())
1524 } else if let Some(Value::Integer(i)) = args.first() {
1525 Ok(i.to_string())
1526 } else {
1527 Err(RuleEngineError::EvaluationError {
1528 message: "round() requires a numeric argument".to_string(),
1529 })
1530 }
1531 }
1532
1533 fn handle_floor_function(&self, args: &[Value]) -> Result<String> {
1534 if let Some(Value::Number(n)) = args.first() {
1535 Ok(n.floor().to_string())
1536 } else if let Some(Value::Integer(i)) = args.first() {
1537 Ok(i.to_string())
1538 } else {
1539 Err(RuleEngineError::EvaluationError {
1540 message: "floor() requires a numeric argument".to_string(),
1541 })
1542 }
1543 }
1544
1545 fn handle_ceil_function(&self, args: &[Value]) -> Result<String> {
1546 if let Some(Value::Number(n)) = args.first() {
1547 Ok(n.ceil().to_string())
1548 } else if let Some(Value::Integer(i)) = args.first() {
1549 Ok(i.to_string())
1550 } else {
1551 Err(RuleEngineError::EvaluationError {
1552 message: "ceil() requires a numeric argument".to_string(),
1553 })
1554 }
1555 }
1556
1557 fn handle_abs_function(&self, args: &[Value]) -> Result<String> {
1558 if let Some(Value::Number(n)) = args.first() {
1559 Ok(n.abs().to_string())
1560 } else if let Some(Value::Integer(i)) = args.first() {
1561 Ok(i.abs().to_string())
1562 } else {
1563 Err(RuleEngineError::EvaluationError {
1564 message: "abs() requires a numeric argument".to_string(),
1565 })
1566 }
1567 }
1568
1569 fn handle_contains_function(&self, args: &[Value]) -> Result<String> {
1571 if args.len() >= 2 {
1572 let haystack = args[0].to_string();
1573 let needle = args[1].to_string();
1574 Ok(haystack.contains(&needle).to_string())
1575 } else {
1576 Err(RuleEngineError::EvaluationError {
1577 message: "contains() requires 2 arguments".to_string(),
1578 })
1579 }
1580 }
1581
1582 fn handle_starts_with_function(&self, args: &[Value]) -> Result<String> {
1583 if args.len() >= 2 {
1584 let text = args[0].to_string();
1585 let prefix = args[1].to_string();
1586 Ok(text.starts_with(&prefix).to_string())
1587 } else {
1588 Err(RuleEngineError::EvaluationError {
1589 message: "startswith() requires 2 arguments".to_string(),
1590 })
1591 }
1592 }
1593
1594 fn handle_ends_with_function(&self, args: &[Value]) -> Result<String> {
1595 if args.len() >= 2 {
1596 let text = args[0].to_string();
1597 let suffix = args[1].to_string();
1598 Ok(text.ends_with(&suffix).to_string())
1599 } else {
1600 Err(RuleEngineError::EvaluationError {
1601 message: "endswith() requires 2 arguments".to_string(),
1602 })
1603 }
1604 }
1605
1606 fn handle_lowercase_function(&self, args: &[Value]) -> Result<String> {
1607 if let Some(arg) = args.first() {
1608 Ok(arg.to_string().to_lowercase())
1609 } else {
1610 Err(RuleEngineError::EvaluationError {
1611 message: "lowercase() requires 1 argument".to_string(),
1612 })
1613 }
1614 }
1615
1616 fn handle_uppercase_function(&self, args: &[Value]) -> Result<String> {
1617 if let Some(arg) = args.first() {
1618 Ok(arg.to_string().to_uppercase())
1619 } else {
1620 Err(RuleEngineError::EvaluationError {
1621 message: "uppercase() requires 1 argument".to_string(),
1622 })
1623 }
1624 }
1625
1626 fn handle_trim_function(&self, args: &[Value]) -> Result<String> {
1627 if let Some(arg) = args.first() {
1628 Ok(arg.to_string().trim().to_string())
1629 } else {
1630 Err(RuleEngineError::EvaluationError {
1631 message: "trim() requires 1 argument".to_string(),
1632 })
1633 }
1634 }
1635
1636 fn handle_split_function(&self, args: &[Value]) -> Result<String> {
1637 if args.len() >= 2 {
1638 let text = args[0].to_string();
1639 let delimiter = args[1].to_string();
1640 let parts: Vec<String> = text.split(&delimiter).map(|s| s.to_string()).collect();
1641 Ok(format!("{:?}", parts)) } else {
1643 Err(RuleEngineError::EvaluationError {
1644 message: "split() requires 2 arguments".to_string(),
1645 })
1646 }
1647 }
1648
1649 fn handle_join_function(&self, args: &[Value]) -> Result<String> {
1650 if args.len() >= 2 {
1651 let delimiter = args[0].to_string();
1652 let parts: Vec<String> = args[1..].iter().map(|v| v.to_string()).collect();
1653 Ok(parts.join(&delimiter))
1654 } else {
1655 Err(RuleEngineError::EvaluationError {
1656 message: "join() requires at least 2 arguments".to_string(),
1657 })
1658 }
1659 }
1660
1661 fn handle_custom_function(
1663 &self,
1664 function: &str,
1665 args: &[Value],
1666 facts: &Facts,
1667 ) -> Result<String> {
1668 if let Some(custom_func) = self.custom_functions.get(function) {
1670 if self.config.debug_mode {
1671 println!("🎯 Calling registered function: {}({:?})", function, args);
1672 }
1673
1674 match custom_func(args, facts) {
1675 Ok(result) => Ok(result.to_string()),
1676 Err(e) => Err(e),
1677 }
1678 } else {
1679 if self.config.debug_mode {
1681 println!("⚠️ Custom function '{}' not registered", function);
1682 }
1683
1684 Err(RuleEngineError::EvaluationError {
1685 message: format!("Function '{}' is not registered. Use engine.register_function() to add custom functions.", function),
1686 })
1687 }
1688 }
1689
1690 fn execute_method_call(
1692 &self,
1693 object_name: &str,
1694 method: &str,
1695 args: &[Value],
1696 facts: &Facts,
1697 ) -> Result<String> {
1698 let Some(object_value) = facts.get(object_name) else {
1700 return Err(RuleEngineError::EvaluationError {
1701 message: format!("Object '{}' not found in facts", object_name),
1702 });
1703 };
1704
1705 let method_lower = method.to_lowercase();
1706
1707 if method_lower.starts_with("set") && args.len() == 1 {
1709 return self.handle_setter_method(object_name, method, &args[0], object_value, facts);
1710 }
1711
1712 if method_lower.starts_with("get") && args.is_empty() {
1714 return self.handle_getter_method(object_name, method, &object_value);
1715 }
1716
1717 match method_lower.as_str() {
1719 "tostring" => Ok(object_value.to_string()),
1720 "update" => {
1721 facts.add_value(object_name, object_value)?;
1722 Ok(format!("Updated {}", object_name))
1723 }
1724 "reset" => self.handle_reset_method(object_name, object_value, facts),
1725 _ => self.handle_property_access_or_fallback(
1726 object_name,
1727 method,
1728 args.len(),
1729 &object_value,
1730 ),
1731 }
1732 }
1733
1734 fn handle_setter_method(
1736 &self,
1737 object_name: &str,
1738 method: &str,
1739 new_value: &Value,
1740 mut object_value: Value,
1741 facts: &Facts,
1742 ) -> Result<String> {
1743 let property_name = Self::extract_property_name_from_setter(method);
1744
1745 match object_value {
1746 Value::Object(ref mut obj) => {
1747 obj.insert(property_name.clone(), new_value.clone());
1748 facts.add_value(object_name, object_value)?;
1749 Ok(format!(
1750 "Set {} to {}",
1751 property_name,
1752 new_value.to_string()
1753 ))
1754 }
1755 _ => Err(RuleEngineError::EvaluationError {
1756 message: format!("Cannot call setter on non-object type: {}", object_name),
1757 }),
1758 }
1759 }
1760
1761 fn handle_getter_method(
1763 &self,
1764 object_name: &str,
1765 method: &str,
1766 object_value: &Value,
1767 ) -> Result<String> {
1768 let property_name = Self::extract_property_name_from_getter(method);
1769
1770 match object_value {
1771 Value::Object(obj) => {
1772 if let Some(value) = obj.get(&property_name) {
1773 Ok(value.to_string())
1774 } else {
1775 Err(RuleEngineError::EvaluationError {
1776 message: format!(
1777 "Property '{}' not found on object '{}'",
1778 property_name, object_name
1779 ),
1780 })
1781 }
1782 }
1783 _ => Err(RuleEngineError::EvaluationError {
1784 message: format!("Cannot call getter on non-object type: {}", object_name),
1785 }),
1786 }
1787 }
1788
1789 fn handle_reset_method(
1791 &self,
1792 object_name: &str,
1793 mut object_value: Value,
1794 facts: &Facts,
1795 ) -> Result<String> {
1796 match object_value {
1797 Value::Object(ref mut obj) => {
1798 obj.clear();
1799 facts.add_value(object_name, object_value)?;
1800 Ok(format!("Reset {}", object_name))
1801 }
1802 _ => Err(RuleEngineError::EvaluationError {
1803 message: format!("Cannot reset non-object type: {}", object_name),
1804 }),
1805 }
1806 }
1807
1808 fn handle_property_access_or_fallback(
1810 &self,
1811 object_name: &str,
1812 method: &str,
1813 arg_count: usize,
1814 object_value: &Value,
1815 ) -> Result<String> {
1816 if let Value::Object(obj) = object_value {
1817 if let Some(value) = obj.get(method) {
1819 return Ok(value.to_string());
1820 }
1821
1822 let capitalized_method = Self::capitalize_first_letter(method);
1824 if let Some(value) = obj.get(&capitalized_method) {
1825 return Ok(value.to_string());
1826 }
1827 }
1828
1829 Ok(format!(
1831 "Called {}.{} with {} args",
1832 object_name, method, arg_count
1833 ))
1834 }
1835
1836 fn extract_property_name_from_setter(method: &str) -> String {
1838 let property_name = &method[3..]; Self::capitalize_first_letter(property_name)
1840 }
1841
1842 fn extract_property_name_from_getter(method: &str) -> String {
1844 let property_name = &method[3..]; Self::capitalize_first_letter(property_name)
1846 }
1847
1848 fn capitalize_first_letter(s: &str) -> String {
1850 if s.is_empty() {
1851 return String::new();
1852 }
1853 let mut chars = s.chars();
1854 match chars.next() {
1855 None => String::new(),
1856 Some(first) => first.to_uppercase().collect::<String>() + chars.as_str(),
1857 }
1858 }
1859
1860 fn resolve_action_parameters(
1862 &self,
1863 params: &HashMap<String, Value>,
1864 facts: &Facts,
1865 ) -> Result<HashMap<String, Value>> {
1866 let mut resolved = HashMap::new();
1867
1868 for (key, value) in params {
1869 let resolved_value = match value {
1870 Value::String(s) => {
1871 if s.contains('.') {
1873 if let Some(fact_value) = facts.get_nested(s) {
1875 fact_value
1876 } else {
1877 value.clone()
1879 }
1880 } else {
1881 value.clone()
1882 }
1883 }
1884 _ => value.clone(),
1885 };
1886 resolved.insert(key.clone(), resolved_value);
1887 }
1888
1889 Ok(resolved)
1890 }
1891
1892 pub fn load_plugin(
1896 &mut self,
1897 plugin: std::sync::Arc<dyn crate::engine::plugin::RulePlugin>,
1898 ) -> Result<()> {
1899 plugin.register_actions(self)?;
1901 plugin.register_functions(self)?;
1902
1903 self.plugin_manager.load_plugin(plugin)
1905 }
1906
1907 pub fn unload_plugin(&mut self, name: &str) -> Result<()> {
1909 self.plugin_manager.unload_plugin(name)
1910 }
1911
1912 pub fn hot_reload_plugin(
1914 &mut self,
1915 name: &str,
1916 new_plugin: std::sync::Arc<dyn crate::engine::plugin::RulePlugin>,
1917 ) -> Result<()> {
1918 self.plugin_manager.unload_plugin(name)?;
1920
1921 new_plugin.register_actions(self)?;
1923 new_plugin.register_functions(self)?;
1924
1925 self.plugin_manager.load_plugin(new_plugin)
1927 }
1928
1929 pub fn get_plugin_info(&self, name: &str) -> Option<&crate::engine::plugin::PluginMetadata> {
1931 self.plugin_manager.get_plugin_info(name)
1932 }
1933
1934 pub fn list_plugins(&self) -> Vec<PluginInfo> {
1936 self.plugin_manager.list_plugins()
1937 }
1938
1939 pub fn get_plugin_stats(&self) -> PluginStats {
1941 self.plugin_manager.get_stats()
1942 }
1943
1944 pub fn plugin_health_check(&mut self) -> HashMap<String, crate::engine::plugin::PluginHealth> {
1946 self.plugin_manager.plugin_health_check()
1947 }
1948
1949 pub fn configure_plugins(&mut self, config: PluginConfig) {
1951 self.plugin_manager = PluginManager::new(config);
1952 }
1953}