1use crate::engine::{
2 agenda::{ActivationGroupManager, AgendaManager},
3 analytics::RuleAnalytics,
4 facts::Facts,
5 knowledge_base::KnowledgeBase,
6 plugin::{PluginConfig, PluginHealth, PluginInfo, PluginManager, PluginStats, RulePlugin},
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::sync::Arc;
14use std::time::{Duration, Instant};
15
16pub type CustomFunction = Box<dyn Fn(&[Value], &Facts) -> Result<Value> + Send + Sync>;
18
19pub type ActionHandler = Box<dyn Fn(&HashMap<String, Value>, &Facts) -> Result<()> + Send + Sync>;
21
22#[derive(Debug, Clone)]
24pub struct EngineConfig {
25 pub max_cycles: usize,
27 pub timeout: Option<Duration>,
29 pub enable_stats: bool,
31 pub debug_mode: bool,
33}
34
35impl Default for EngineConfig {
36 fn default() -> Self {
37 Self {
38 max_cycles: 100,
39 timeout: Some(Duration::from_secs(30)),
40 enable_stats: true,
41 debug_mode: false,
42 }
43 }
44}
45
46#[derive(Debug, Clone)]
48pub struct GruleExecutionResult {
49 pub cycle_count: usize,
51 pub rules_evaluated: usize,
53 pub rules_fired: usize,
55 pub execution_time: Duration,
57}
58
59pub struct RustRuleEngine {
61 knowledge_base: KnowledgeBase,
62 config: EngineConfig,
63 custom_functions: HashMap<String, CustomFunction>,
64 action_handlers: HashMap<String, ActionHandler>,
65 analytics: Option<RuleAnalytics>,
66 agenda_manager: AgendaManager,
67 activation_group_manager: ActivationGroupManager,
68 fired_rules_global: std::collections::HashSet<String>,
70 workflow_engine: WorkflowEngine,
72 plugin_manager: PluginManager,
74}
75
76impl RustRuleEngine {
77 pub fn execute_with_callback<F>(&mut self, facts: &Facts, mut on_rule_fired: F) -> Result<GruleExecutionResult>
79 where
80 F: FnMut(&str, &str),
81 {
82 use chrono::Utc;
83 let timestamp = Utc::now();
84 let start_time = std::time::Instant::now();
85 let mut cycle_count = 0;
86 let mut rules_evaluated = 0;
87 let mut rules_fired = 0;
88
89 self.sync_workflow_agenda_activations();
90
91 for cycle in 0..self.config.max_cycles {
92 cycle_count = cycle + 1;
93 let mut any_rule_fired = false;
94 let mut fired_rules_in_cycle = std::collections::HashSet::new();
95 self.activation_group_manager.reset_cycle();
96
97 if let Some(timeout) = self.config.timeout {
98 if start_time.elapsed() > timeout {
99 return Err(crate::errors::RuleEngineError::EvaluationError {
100 message: "Execution timeout exceeded".to_string(),
101 });
102 }
103 }
104
105 let mut rules = self.knowledge_base.get_rules().clone();
106 rules.sort_by(|a, b| b.salience.cmp(&a.salience));
107 let rules: Vec<_> = rules
108 .iter()
109 .filter(|rule| self.agenda_manager.should_evaluate_rule(rule))
110 .collect();
111
112 for rule in &rules {
113 if !rule.enabled {
114 continue;
115 }
116 if !rule.is_active_at(timestamp) {
117 continue;
118 }
119 if !self.agenda_manager.can_fire_rule(rule) {
120 continue;
121 }
122 if !self.activation_group_manager.can_fire(rule) {
123 continue;
124 }
125 if rule.no_loop && self.fired_rules_global.contains(&rule.name) {
126 continue;
127 }
128 rules_evaluated += 1;
129 let condition_result = self.evaluate_conditions(&rule.conditions, facts)?;
130 if condition_result {
131 for action in &rule.actions {
132 self.execute_action(action, facts)?;
133 }
134 rules_fired += 1;
135 any_rule_fired = true;
136 fired_rules_in_cycle.insert(rule.name.clone());
137 if rule.no_loop {
138 self.fired_rules_global.insert(rule.name.clone());
139 }
140 self.agenda_manager.mark_rule_fired(rule);
141 self.activation_group_manager.mark_fired(rule);
142 on_rule_fired(&rule.name, "facts"); }
145 }
146 if !any_rule_fired {
147 break;
148 }
149 self.sync_workflow_agenda_activations();
150 }
151 let execution_time = start_time.elapsed();
152 Ok(crate::engine::GruleExecutionResult {
153 cycle_count,
154 rules_evaluated,
155 rules_fired,
156 execution_time,
157 })
158 }
159 pub fn new(knowledge_base: KnowledgeBase) -> Self {
161 Self {
162 knowledge_base,
163 config: EngineConfig::default(),
164 custom_functions: HashMap::new(),
165 action_handlers: HashMap::new(),
166 analytics: None,
167 agenda_manager: AgendaManager::new(),
168 activation_group_manager: ActivationGroupManager::new(),
169 fired_rules_global: std::collections::HashSet::new(),
170 workflow_engine: WorkflowEngine::new(),
171 plugin_manager: PluginManager::with_default_config(),
172 }
173 }
174
175 pub fn with_config(knowledge_base: KnowledgeBase, config: EngineConfig) -> Self {
177 Self {
178 knowledge_base,
179 config,
180 custom_functions: HashMap::new(),
181 action_handlers: HashMap::new(),
182 analytics: None,
183 agenda_manager: AgendaManager::new(),
184 activation_group_manager: ActivationGroupManager::new(),
185 fired_rules_global: std::collections::HashSet::new(),
186 workflow_engine: WorkflowEngine::new(),
187 plugin_manager: PluginManager::with_default_config(),
188 }
189 }
190
191 pub fn register_function<F>(&mut self, name: &str, func: F)
193 where
194 F: Fn(&[Value], &Facts) -> Result<Value> + Send + Sync + 'static,
195 {
196 self.custom_functions
197 .insert(name.to_string(), Box::new(func));
198 }
199
200 pub fn register_action_handler<F>(&mut self, action_type: &str, handler: F)
202 where
203 F: Fn(&HashMap<String, Value>, &Facts) -> Result<()> + Send + Sync + 'static,
204 {
205 self.action_handlers
206 .insert(action_type.to_string(), Box::new(handler));
207 }
208
209 pub fn enable_analytics(&mut self, analytics: RuleAnalytics) {
211 self.analytics = Some(analytics);
212 }
213
214 pub fn reset_no_loop_tracking(&mut self) {
216 self.fired_rules_global.clear();
217 }
218
219 pub fn disable_analytics(&mut self) {
221 self.analytics = None;
222 }
223
224 pub fn analytics(&self) -> Option<&RuleAnalytics> {
226 self.analytics.as_ref()
227 }
228
229 pub fn set_debug_mode(&mut self, enabled: bool) {
231 self.config.debug_mode = enabled;
232 }
233
234 pub fn has_function(&self, name: &str) -> bool {
236 self.custom_functions.contains_key(name)
237 }
238
239 pub fn has_action_handler(&self, action_type: &str) -> bool {
241 self.action_handlers.contains_key(action_type)
242 }
243
244 pub fn get_ready_tasks(&mut self) -> Vec<crate::engine::workflow::ScheduledTask> {
246 self.workflow_engine.get_ready_tasks()
247 }
248
249 pub fn execute_scheduled_tasks(&mut self, facts: &Facts) -> Result<()> {
251 let ready_tasks = self.get_ready_tasks();
252 for task in ready_tasks {
253 if let Some(rule) = self
254 .knowledge_base
255 .get_rules()
256 .iter()
257 .find(|r| r.name == task.rule_name)
258 {
259 if self.config.debug_mode {
260 println!("⚡ Executing scheduled task: {}", task.rule_name);
261 }
262
263 if self.evaluate_conditions(&rule.conditions, facts)? {
265 for action in &rule.actions {
266 self.execute_action(action, facts)?;
267 }
268 }
269 }
270 }
271 Ok(())
272 }
273
274 pub fn activate_agenda_group(&mut self, group: String) {
276 self.workflow_engine.activate_agenda_group(group.clone());
277 self.agenda_manager.set_focus(&group);
278 }
279
280 pub fn knowledge_base(&self) -> &KnowledgeBase {
282 &self.knowledge_base
283 }
284
285 pub fn knowledge_base_mut(&mut self) -> &mut KnowledgeBase {
287 &mut self.knowledge_base
288 }
289
290 fn sync_workflow_agenda_activations(&mut self) {
292 while let Some(agenda_group) = self.workflow_engine.get_next_pending_agenda_activation() {
294 if self.config.debug_mode {
295 println!("🔄 Syncing workflow agenda activation: {}", agenda_group);
296 }
297 self.agenda_manager.set_focus(&agenda_group);
298 }
299 }
300
301 pub fn set_agenda_focus(&mut self, group: &str) {
303 self.agenda_manager.set_focus(group);
304 }
305
306 pub fn get_active_agenda_group(&self) -> &str {
308 self.agenda_manager.get_active_group()
309 }
310
311 pub fn pop_agenda_focus(&mut self) -> Option<String> {
313 self.agenda_manager.pop_focus()
314 }
315
316 pub fn clear_agenda_focus(&mut self) {
318 self.agenda_manager.clear_focus();
319 }
320
321 pub fn get_agenda_groups(&self) -> Vec<String> {
323 self.agenda_manager
324 .get_agenda_groups(&self.knowledge_base.get_rules())
325 }
326
327 pub fn get_activation_groups(&self) -> Vec<String> {
329 self.activation_group_manager
330 .get_activation_groups(&self.knowledge_base.get_rules())
331 }
332
333 pub fn start_workflow(&mut self, workflow_name: Option<String>) -> String {
337 self.workflow_engine.start_workflow(workflow_name)
338 }
339
340 pub fn get_workflow_stats(&self) -> crate::engine::workflow::WorkflowStats {
342 self.workflow_engine.get_workflow_stats()
343 }
344
345 pub fn get_workflow(
347 &self,
348 workflow_id: &str,
349 ) -> Option<&crate::engine::workflow::WorkflowState> {
350 self.workflow_engine.get_workflow(workflow_id)
351 }
352
353 pub fn cleanup_completed_workflows(&mut self, older_than: Duration) {
355 self.workflow_engine.cleanup_completed_workflows(older_than);
356 }
357
358 pub fn execute_workflow_step(
360 &mut self,
361 agenda_group: &str,
362 facts: &Facts,
363 ) -> Result<GruleExecutionResult> {
364 self.set_agenda_focus(agenda_group);
366
367 let result = self.execute(facts)?;
369
370 self.process_workflow_actions(facts)?;
372
373 Ok(result)
374 }
375
376 pub fn execute_workflow(
378 &mut self,
379 agenda_groups: Vec<&str>,
380 facts: &Facts,
381 ) -> Result<crate::engine::workflow::WorkflowResult> {
382 let start_time = Instant::now();
383 let mut total_steps = 0;
384
385 if self.config.debug_mode {
386 println!(
387 "🔄 Starting workflow execution with {} steps",
388 agenda_groups.len()
389 );
390 }
391
392 for (i, group) in agenda_groups.iter().enumerate() {
393 if self.config.debug_mode {
394 println!("📋 Executing workflow step {}: {}", i + 1, group);
395 }
396
397 let step_result = self.execute_workflow_step(group, facts)?;
398 total_steps += 1;
399
400 if step_result.rules_fired == 0 {
401 if self.config.debug_mode {
402 println!("⏸️ No rules fired in step '{}', stopping workflow", group);
403 }
404 break;
405 }
406 }
407
408 let execution_time = start_time.elapsed();
409
410 Ok(crate::engine::workflow::WorkflowResult::success(
411 total_steps,
412 execution_time,
413 ))
414 }
415
416 fn process_workflow_actions(&mut self, facts: &Facts) -> Result<()> {
418 while let Some(group) = self.workflow_engine.get_next_agenda_group() {
420 self.set_agenda_focus(&group);
421 }
422
423 let ready_tasks = self.workflow_engine.get_ready_tasks();
425 for task in ready_tasks {
426 if self.config.debug_mode {
427 println!("⚡ Executing scheduled task: {}", task.rule_name);
428 }
429
430 if let Some(rule) = self
432 .knowledge_base
433 .get_rules()
434 .iter()
435 .find(|r| r.name == task.rule_name)
436 {
437 if self.evaluate_conditions(&rule.conditions, facts)? {
439 for action in &rule.actions {
440 self.execute_action(action, facts)?;
441 }
442 }
443 }
444 }
445
446 Ok(())
447 }
448
449 pub fn execute(&mut self, facts: &Facts) -> Result<GruleExecutionResult> {
451 self.execute_at_time(facts, Utc::now())
452 }
453
454 pub fn execute_at_time(
456 &mut self,
457 facts: &Facts,
458 timestamp: DateTime<Utc>,
459 ) -> Result<GruleExecutionResult> {
460 let start_time = Instant::now();
461 let mut cycle_count = 0;
462 let mut rules_evaluated = 0;
463 let mut rules_fired = 0;
464
465 self.sync_workflow_agenda_activations();
467
468 if self.config.debug_mode {
469 println!(
470 "🚀 Starting rule execution with {} rules (agenda group: {})",
471 self.knowledge_base.get_rules().len(),
472 self.agenda_manager.get_active_group()
473 );
474 }
475
476 for cycle in 0..self.config.max_cycles {
477 cycle_count = cycle + 1;
478 let mut any_rule_fired = false;
479 let mut fired_rules_in_cycle = std::collections::HashSet::new();
480
481 self.activation_group_manager.reset_cycle();
483
484 if let Some(timeout) = self.config.timeout {
486 if start_time.elapsed() > timeout {
487 return Err(RuleEngineError::EvaluationError {
488 message: "Execution timeout exceeded".to_string(),
489 });
490 }
491 }
492
493 let mut rules = self.knowledge_base.get_rules().clone();
495 rules.sort_by(|a, b| b.salience.cmp(&a.salience));
496
497 let rules: Vec<_> = rules
499 .iter()
500 .filter(|rule| self.agenda_manager.should_evaluate_rule(rule))
501 .collect();
502
503 for rule in &rules {
504 if !rule.enabled {
505 continue;
506 }
507
508 if !rule.is_active_at(timestamp) {
510 continue;
511 }
512
513 if !self.agenda_manager.can_fire_rule(rule) {
515 continue;
516 }
517
518 if !self.activation_group_manager.can_fire(rule) {
520 continue;
521 }
522
523 if rule.no_loop && self.fired_rules_global.contains(&rule.name) {
525 if self.config.debug_mode {
526 println!("⛔ Skipping '{}' due to no_loop (already fired)", rule.name);
527 }
528 continue;
529 }
530
531 rules_evaluated += 1;
532 let rule_start = Instant::now();
533
534 if self.config.debug_mode {
535 println!("📝 Evaluating rule: {} (no_loop={})", rule.name, rule.no_loop);
536 }
537
538 let condition_result = self.evaluate_conditions(&rule.conditions, facts)?;
540 if self.config.debug_mode {
541 println!(
542 " 🔍 Condition result for '{}': {}",
543 rule.name, condition_result
544 );
545 }
546
547 if condition_result {
548 if self.config.debug_mode {
549 println!(
550 "🔥 Rule '{}' fired (salience: {})",
551 rule.name, rule.salience
552 );
553 }
554
555 for action in &rule.actions {
557 self.execute_action(action, facts)?;
558 }
559
560 let rule_duration = rule_start.elapsed();
561
562 if let Some(analytics) = &mut self.analytics {
564 analytics.record_execution(&rule.name, rule_duration, true, true, None, 0);
565 }
566
567 rules_fired += 1;
568 any_rule_fired = true;
569
570 fired_rules_in_cycle.insert(rule.name.clone());
572
573 if rule.no_loop {
575 self.fired_rules_global.insert(rule.name.clone());
576 if self.config.debug_mode {
577 println!(" 🔒 Marked '{}' as fired (no_loop tracking)", rule.name);
578 }
579 }
580
581 self.agenda_manager.mark_rule_fired(rule);
583 self.activation_group_manager.mark_fired(rule);
584 } else {
585 let rule_duration = rule_start.elapsed();
586
587 if let Some(analytics) = &mut self.analytics {
589 analytics.record_execution(
590 &rule.name,
591 rule_duration,
592 false,
593 false,
594 None,
595 0,
596 );
597 }
598 }
599 }
600
601 if !any_rule_fired {
603 break;
604 }
605
606 self.sync_workflow_agenda_activations();
608 }
609
610 let execution_time = start_time.elapsed();
611
612 Ok(GruleExecutionResult {
613 cycle_count,
614 rules_evaluated,
615 rules_fired,
616 execution_time,
617 })
618 }
619
620 fn evaluate_conditions(
622 &self,
623 conditions: &crate::engine::rule::ConditionGroup,
624 facts: &Facts,
625 ) -> Result<bool> {
626 use crate::engine::pattern_matcher::PatternMatcher;
627 use crate::engine::rule::ConditionGroup;
628
629 match conditions {
630 ConditionGroup::Single(condition) => self.evaluate_single_condition(condition, facts),
631 ConditionGroup::Compound {
632 left,
633 operator,
634 right,
635 } => {
636 let left_result = self.evaluate_conditions(left, facts)?;
637 let right_result = self.evaluate_conditions(right, facts)?;
638
639 match operator {
640 crate::types::LogicalOperator::And => Ok(left_result && right_result),
641 crate::types::LogicalOperator::Or => Ok(left_result || right_result),
642 crate::types::LogicalOperator::Not => Err(RuleEngineError::EvaluationError {
643 message: "NOT operator should not appear in compound conditions"
644 .to_string(),
645 }),
646 }
647 }
648 ConditionGroup::Not(condition) => {
649 let result = self.evaluate_conditions(condition, facts)?;
650 Ok(!result)
651 }
652 ConditionGroup::Exists(condition) => {
654 Ok(PatternMatcher::evaluate_exists(condition, facts))
655 }
656 ConditionGroup::Forall(condition) => {
657 Ok(PatternMatcher::evaluate_forall(condition, facts))
658 }
659 ConditionGroup::Accumulate {
660 result_var,
661 source_pattern,
662 extract_field,
663 source_conditions,
664 function,
665 function_arg,
666 } => {
667 self.evaluate_accumulate(
669 result_var,
670 source_pattern,
671 extract_field,
672 source_conditions,
673 function,
674 function_arg,
675 facts,
676 )?;
677 Ok(true)
679 }
680 }
681 }
682
683 fn evaluate_accumulate(
685 &self,
686 result_var: &str,
687 source_pattern: &str,
688 extract_field: &str,
689 source_conditions: &[String],
690 function: &str,
691 function_arg: &str,
692 facts: &Facts,
693 ) -> Result<()> {
694 use crate::rete::accumulate::*;
695
696 let all_facts = facts.get_all_facts();
698 let mut matching_values = Vec::new();
699
700 let pattern_prefix = format!("{}.", source_pattern);
702
703 let mut instances: HashMap<String, HashMap<String, Value>> = HashMap::new();
705
706 for (key, value) in &all_facts {
707 if key.starts_with(&pattern_prefix) {
708 let parts: Vec<&str> = key.strip_prefix(&pattern_prefix).unwrap().split('.').collect();
710
711 if parts.len() >= 2 {
712 let instance_id = parts[0];
714 let field_name = parts[1..].join(".");
715
716 instances
717 .entry(instance_id.to_string())
718 .or_insert_with(HashMap::new)
719 .insert(field_name, value.clone());
720 } else if parts.len() == 1 {
721 instances
723 .entry("default".to_string())
724 .or_insert_with(HashMap::new)
725 .insert(parts[0].to_string(), value.clone());
726 }
727 }
728 }
729
730 for (_instance_id, instance_facts) in instances {
732 let mut matches = true;
734
735 for condition_str in source_conditions {
736 if !self.evaluate_condition_string(condition_str, &instance_facts) {
738 matches = false;
739 break;
740 }
741 }
742
743 if matches {
744 if let Some(value) = instance_facts.get(extract_field) {
746 matching_values.push(value.clone());
747 }
748 }
749 }
750
751 let result = match function {
753 "sum" => {
754 let mut state = SumFunction.init();
755 for value in &matching_values {
756 state.accumulate(&self.value_to_fact_value(value));
757 }
758 self.fact_value_to_value(&state.get_result())
759 }
760 "count" => {
761 let mut state = CountFunction.init();
762 for value in &matching_values {
763 state.accumulate(&self.value_to_fact_value(value));
764 }
765 self.fact_value_to_value(&state.get_result())
766 }
767 "average" | "avg" => {
768 let mut state = AverageFunction.init();
769 for value in &matching_values {
770 state.accumulate(&self.value_to_fact_value(value));
771 }
772 self.fact_value_to_value(&state.get_result())
773 }
774 "min" => {
775 let mut state = MinFunction.init();
776 for value in &matching_values {
777 state.accumulate(&self.value_to_fact_value(value));
778 }
779 self.fact_value_to_value(&state.get_result())
780 }
781 "max" => {
782 let mut state = MaxFunction.init();
783 for value in &matching_values {
784 state.accumulate(&self.value_to_fact_value(value));
785 }
786 self.fact_value_to_value(&state.get_result())
787 }
788 _ => {
789 return Err(RuleEngineError::EvaluationError {
790 message: format!("Unknown accumulate function: {}", function),
791 });
792 }
793 };
794
795 let result_key = format!("{}.{}", source_pattern, function);
798
799 facts.set(&result_key, result);
800
801 if self.config.debug_mode {
802 println!(" 🧮 Accumulate result: {} = {:?}", result_key, facts.get(&result_key));
803 }
804
805 Ok(())
806 }
807
808 fn value_to_fact_value(&self, value: &Value) -> crate::rete::facts::FactValue {
810 use crate::rete::facts::FactValue;
811 match value {
812 Value::Integer(i) => FactValue::Integer(*i),
813 Value::Number(n) => FactValue::Float(*n),
814 Value::String(s) => FactValue::String(s.clone()),
815 Value::Boolean(b) => FactValue::Boolean(*b),
816 _ => FactValue::String(value.to_string()),
817 }
818 }
819
820 fn fact_value_to_value(&self, fact_value: &crate::rete::facts::FactValue) -> Value {
822 use crate::rete::facts::FactValue;
823 match fact_value {
824 FactValue::Integer(i) => Value::Integer(*i),
825 FactValue::Float(f) => Value::Number(*f),
826 FactValue::String(s) => Value::String(s.clone()),
827 FactValue::Boolean(b) => Value::Boolean(*b),
828 FactValue::Array(_) => Value::String(format!("{:?}", fact_value)),
829 FactValue::Null => Value::String("null".to_string()),
830 }
831 }
832
833 fn evaluate_condition_string(&self, condition: &str, facts: &HashMap<String, Value>) -> bool {
835 let condition = condition.trim();
837
838 let operators = ["==", "!=", ">=", "<=", ">", "<"];
840
841 for op in &operators {
842 if let Some(pos) = condition.find(op) {
843 let field = condition[..pos].trim();
844 let value_str = condition[pos + op.len()..].trim()
845 .trim_matches('"')
846 .trim_matches('\'');
847
848 if let Some(field_value) = facts.get(field) {
849 return self.compare_values(field_value, op, value_str);
850 } else {
851 return false;
852 }
853 }
854 }
855
856 false
857 }
858
859 fn compare_values(&self, field_value: &Value, operator: &str, value_str: &str) -> bool {
861 match field_value {
862 Value::String(s) => {
863 match operator {
864 "==" => s == value_str,
865 "!=" => s != value_str,
866 _ => false,
867 }
868 }
869 Value::Integer(i) => {
870 if let Ok(num) = value_str.parse::<i64>() {
871 match operator {
872 "==" => *i == num,
873 "!=" => *i != num,
874 ">" => *i > num,
875 "<" => *i < num,
876 ">=" => *i >= num,
877 "<=" => *i <= num,
878 _ => false,
879 }
880 } else {
881 false
882 }
883 }
884 Value::Number(n) => {
885 if let Ok(num) = value_str.parse::<f64>() {
886 match operator {
887 "==" => (*n - num).abs() < f64::EPSILON,
888 "!=" => (*n - num).abs() >= f64::EPSILON,
889 ">" => *n > num,
890 "<" => *n < num,
891 ">=" => *n >= num,
892 "<=" => *n <= num,
893 _ => false,
894 }
895 } else {
896 false
897 }
898 }
899 Value::Boolean(b) => {
900 if let Ok(bool_val) = value_str.parse::<bool>() {
901 match operator {
902 "==" => *b == bool_val,
903 "!=" => *b != bool_val,
904 _ => false,
905 }
906 } else {
907 false
908 }
909 }
910 _ => false,
911 }
912 }
913
914 fn evaluate_rule_conditions(
916 &self,
917 rule: &crate::engine::rule::Rule,
918 facts: &Facts,
919 ) -> Result<bool> {
920 self.evaluate_conditions(&rule.conditions, facts)
921 }
922
923 fn is_retracted(&self, object_name: &str, facts: &Facts) -> bool {
925 let retract_key = format!("_retracted_{}", object_name);
926 matches!(facts.get(&retract_key), Some(Value::Boolean(true)))
927 }
928
929 fn evaluate_single_condition(
931 &self,
932 condition: &crate::engine::rule::Condition,
933 facts: &Facts,
934 ) -> Result<bool> {
935 use crate::engine::rule::ConditionExpression;
936
937 let result = match &condition.expression {
938 ConditionExpression::Field(field_name) => {
939 if let Some(object_name) = field_name.split('.').next() {
942 if self.is_retracted(object_name, facts) {
943 if self.config.debug_mode {
944 println!(" 🗑️ Skipping retracted fact: {}", object_name);
945 }
946 return Ok(false);
947 }
948 }
949
950 let field_value = facts
952 .get_nested(field_name)
953 .or_else(|| facts.get(field_name));
954
955 if self.config.debug_mode {
956 println!(
957 " 🔎 Evaluating field condition: {} {} {:?}",
958 field_name,
959 format!("{:?}", condition.operator).to_lowercase(),
960 condition.value
961 );
962 println!(" Field value: {:?}", field_value);
963 }
964
965 if let Some(value) = field_value {
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(&value, &rhs)
1000 } else {
1001 false
1002 }
1003 }
1004 ConditionExpression::FunctionCall { name, args } => {
1005 if self.config.debug_mode {
1007 println!(
1008 " 🔎 Evaluating function condition: {}({:?}) {} {:?}",
1009 name,
1010 args,
1011 format!("{:?}", condition.operator).to_lowercase(),
1012 condition.value
1013 );
1014 }
1015
1016 if let Some(function) = self.custom_functions.get(name) {
1017 let arg_values: Vec<Value> = args
1019 .iter()
1020 .map(|arg| {
1021 facts
1022 .get_nested(arg)
1023 .or_else(|| facts.get(arg))
1024 .unwrap_or(Value::String(arg.clone()))
1025 })
1026 .collect();
1027
1028 match function(&arg_values, facts) {
1030 Ok(result_value) => {
1031 if self.config.debug_mode {
1032 println!(" Function result: {:?}", result_value);
1033 }
1034 condition.operator.evaluate(&result_value, &condition.value)
1035 }
1036 Err(e) => {
1037 if self.config.debug_mode {
1038 println!(" Function error: {}", e);
1039 }
1040 false
1041 }
1042 }
1043 } else {
1044 if self.config.debug_mode {
1045 println!(" Function '{}' not found", name);
1046 }
1047 false
1048 }
1049 }
1050 ConditionExpression::Test { name, args } => {
1051 if self.config.debug_mode {
1053 println!(" 🧪 Evaluating test CE: test({}({:?}))", name, args);
1054 }
1055
1056 if let Some(function) = self.custom_functions.get(name) {
1058 let arg_values: Vec<Value> = args
1060 .iter()
1061 .map(|arg| {
1062 let resolved = facts
1063 .get_nested(arg)
1064 .or_else(|| facts.get(arg))
1065 .unwrap_or(Value::String(arg.clone()));
1066 if self.config.debug_mode {
1067 println!(" Resolving arg '{}' -> {:?}", arg, resolved);
1068 }
1069 resolved
1070 })
1071 .collect();
1072
1073 match function(&arg_values, facts) {
1075 Ok(result_value) => {
1076 if self.config.debug_mode {
1077 println!(" Test result: {:?}", result_value);
1078 }
1079 match result_value {
1081 Value::Boolean(b) => b,
1082 Value::Integer(i) => i != 0,
1083 Value::Number(f) => f != 0.0,
1084 Value::String(s) => !s.is_empty(),
1085 _ => false,
1086 }
1087 }
1088 Err(e) => {
1089 if self.config.debug_mode {
1090 println!(" Test function error: {}", e);
1091 }
1092 false
1093 }
1094 }
1095 } else {
1096 if self.config.debug_mode {
1099 println!(" Trying to evaluate '{}' as arithmetic expression", name);
1100 }
1101
1102 match self.evaluate_arithmetic_condition(name, facts) {
1104 Ok(result) => {
1105 if self.config.debug_mode {
1106 println!(" Arithmetic expression result: {}", result);
1107 }
1108 result
1109 }
1110 Err(e) => {
1111 if self.config.debug_mode {
1112 println!(" Failed to evaluate expression: {}", e);
1113 println!(" Test function '{}' not found", name);
1114 }
1115 false
1116 }
1117 }
1118 }
1119 }
1120 ConditionExpression::MultiField { field, operation, variable: _ } => {
1121 if self.config.debug_mode {
1123 println!(" 📦 Evaluating multi-field: {}.{}", field, operation);
1124 }
1125
1126 let field_value = facts.get_nested(field).or_else(|| facts.get(field));
1128
1129 if let Some(value) = field_value {
1130 match operation.as_str() {
1131 "empty" => {
1132 matches!(value, Value::Array(arr) if arr.is_empty())
1133 }
1134 "not_empty" => {
1135 matches!(value, Value::Array(arr) if !arr.is_empty())
1136 }
1137 "count" => {
1138 if let Value::Array(arr) = value {
1139 let count = Value::Integer(arr.len() as i64);
1140 condition.operator.evaluate(&count, &condition.value)
1141 } else {
1142 false
1143 }
1144 }
1145 "contains" => {
1146 condition.operator.evaluate(&value, &condition.value)
1148 }
1149 _ => {
1150 if self.config.debug_mode {
1153 println!(" ⚠️ Operation '{}' not fully implemented yet", operation);
1154 }
1155 true
1156 }
1157 }
1158 } else {
1159 false
1160 }
1161 }
1162 };
1163
1164 if self.config.debug_mode {
1165 println!(" Result: {}", result);
1166 }
1167
1168 Ok(result)
1169 }
1170
1171 fn execute_action(&mut self, action: &ActionType, facts: &Facts) -> Result<()> {
1173 match action {
1174 ActionType::Set { field, value } => {
1175 let evaluated_value = match value {
1177 Value::Expression(expr) => {
1178 crate::expression::evaluate_expression(expr, facts)?
1180 }
1181 _ => value.clone(),
1182 };
1183
1184 if let Err(_) = facts.set_nested(field, evaluated_value.clone()) {
1186 facts.set(field, evaluated_value.clone());
1188 }
1189 if self.config.debug_mode {
1190 println!(" ✅ Set {field} = {evaluated_value:?}");
1191 }
1192 }
1193 ActionType::Log { message } => {
1194 println!("📋 LOG: {}", message);
1195 }
1196 ActionType::Call { function, args } => {
1197 let result = self.execute_function_call(function, args, facts)?;
1198 if self.config.debug_mode {
1199 println!(" 📞 Called {function}({args:?}) -> {result}");
1200 }
1201 }
1202 ActionType::MethodCall {
1203 object,
1204 method,
1205 args,
1206 } => {
1207 let result = self.execute_method_call(object, method, args, facts)?;
1208 if self.config.debug_mode {
1209 println!(" 🔧 Called {object}.{method}({args:?}) -> {result}");
1210 }
1211 }
1212 ActionType::Update { object } => {
1213 if self.config.debug_mode {
1214 println!(" 🔄 Updated {object}");
1215 }
1216 }
1219 ActionType::Retract { object } => {
1220 if self.config.debug_mode {
1221 println!(" 🗑️ Retracted {object}");
1222 }
1223 facts.set(&format!("_retracted_{}", object), Value::Boolean(true));
1225 }
1226 ActionType::Custom {
1227 action_type,
1228 params,
1229 } => {
1230 if let Some(handler) = self.action_handlers.get(action_type) {
1231 if self.config.debug_mode {
1232 println!(
1233 " 🎯 Executing custom action: {action_type} with params: {params:?}"
1234 );
1235 }
1236
1237 let resolved_params = self.resolve_action_parameters(params, facts)?;
1239
1240 handler(&resolved_params, facts)?;
1242 } else {
1243 if self.config.debug_mode {
1244 println!(" ⚠️ No handler registered for custom action: {action_type}");
1245 println!(
1246 " Available handlers: {:?}",
1247 self.action_handlers.keys().collect::<Vec<_>>()
1248 );
1249 }
1250
1251 return Err(RuleEngineError::EvaluationError {
1253 message: format!(
1254 "No action handler registered for '{action_type}'. Use engine.register_action_handler() to add custom action handlers."
1255 ),
1256 });
1257 }
1258 }
1259 ActionType::ActivateAgendaGroup { group } => {
1261 if self.config.debug_mode {
1262 println!(" 🎯 Activating agenda group: {}", group);
1263 }
1264 self.workflow_engine.activate_agenda_group(group.clone());
1266 self.agenda_manager.set_focus(group);
1267 }
1268 ActionType::ScheduleRule {
1269 rule_name,
1270 delay_ms,
1271 } => {
1272 if self.config.debug_mode {
1273 println!(
1274 " ⏰ Scheduling rule '{}' to execute in {}ms",
1275 rule_name, delay_ms
1276 );
1277 }
1278 self.workflow_engine
1279 .schedule_rule(rule_name.clone(), *delay_ms, None);
1280 }
1281 ActionType::CompleteWorkflow { workflow_name } => {
1282 if self.config.debug_mode {
1283 println!(" ✅ Completing workflow: {}", workflow_name);
1284 }
1285 self.workflow_engine
1286 .complete_workflow(workflow_name.clone());
1287 }
1288 ActionType::SetWorkflowData { key, value } => {
1289 if self.config.debug_mode {
1290 println!(" 💾 Setting workflow data: {} = {:?}", key, value);
1291 }
1292 let workflow_id = "default_workflow";
1295 self.workflow_engine
1296 .set_workflow_data(workflow_id, key.clone(), value.clone());
1297 }
1298 }
1299 Ok(())
1300 }
1301
1302 fn evaluate_arithmetic_condition(&self, expr: &str, facts: &Facts) -> Result<bool> {
1304 let operators = [">=", "<=", "==", "!=", ">", "<"];
1308 let mut split_pos = None;
1309 let mut found_op = "";
1310
1311 for op in &operators {
1312 if let Some(pos) = expr.rfind(op) {
1313 split_pos = Some(pos);
1314 found_op = op;
1315 break;
1316 }
1317 }
1318
1319 if split_pos.is_none() {
1320 return Err(RuleEngineError::EvaluationError {
1321 message: format!("No comparison operator found in expression: {}", expr),
1322 });
1323 }
1324
1325 let pos = split_pos.unwrap();
1326 let left_expr = expr[..pos].trim();
1327 let right_value = expr[pos + found_op.len()..].trim();
1328
1329 let left_result = crate::expression::evaluate_expression(left_expr, facts)?;
1331
1332 let right_val = if let Ok(i) = right_value.parse::<i64>() {
1334 Value::Integer(i)
1335 } else if let Ok(f) = right_value.parse::<f64>() {
1336 Value::Number(f)
1337 } else {
1338 match crate::expression::evaluate_expression(right_value, facts) {
1340 Ok(v) => v,
1341 Err(_) => Value::String(right_value.to_string()),
1342 }
1343 };
1344
1345 let operator = Operator::from_str(found_op).ok_or_else(|| {
1347 RuleEngineError::InvalidOperator {
1348 operator: found_op.to_string(),
1349 }
1350 })?;
1351
1352 Ok(operator.evaluate(&left_result, &right_val))
1353 }
1354
1355 fn execute_function_call(
1357 &self,
1358 function: &str,
1359 args: &[Value],
1360 facts: &Facts,
1361 ) -> Result<String> {
1362 let function_lower = function.to_lowercase();
1363
1364 match function_lower.as_str() {
1366 "log" | "print" | "println" => self.handle_log_function(args),
1367 "update" | "refresh" => self.handle_update_function(args),
1368 "now" | "timestamp" => self.handle_timestamp_function(),
1369 "random" => self.handle_random_function(args),
1370 "format" | "sprintf" => self.handle_format_function(args),
1371 "length" | "size" | "count" => self.handle_length_function(args),
1372 "sum" | "add" => self.handle_sum_function(args),
1373 "max" | "maximum" => self.handle_max_function(args),
1374 "min" | "minimum" => self.handle_min_function(args),
1375 "avg" | "average" => self.handle_average_function(args),
1376 "round" => self.handle_round_function(args),
1377 "floor" => self.handle_floor_function(args),
1378 "ceil" | "ceiling" => self.handle_ceil_function(args),
1379 "abs" | "absolute" => self.handle_abs_function(args),
1380 "contains" | "includes" => self.handle_contains_function(args),
1381 "startswith" | "begins_with" => self.handle_starts_with_function(args),
1382 "endswith" | "ends_with" => self.handle_ends_with_function(args),
1383 "lowercase" | "tolower" => self.handle_lowercase_function(args),
1384 "uppercase" | "toupper" => self.handle_uppercase_function(args),
1385 "trim" | "strip" => self.handle_trim_function(args),
1386 "split" => self.handle_split_function(args),
1387 "join" => self.handle_join_function(args),
1388 _ => {
1389 self.handle_custom_function(function, args, facts)
1391 }
1392 }
1393 }
1394
1395 fn handle_log_function(&self, args: &[Value]) -> Result<String> {
1397 let message = if args.is_empty() {
1398 "".to_string()
1399 } else if args.len() == 1 {
1400 args[0].to_string()
1401 } else {
1402 args.iter()
1403 .map(|v| v.to_string())
1404 .collect::<Vec<_>>()
1405 .join(" ")
1406 };
1407
1408 println!("📋 {}", message);
1409 Ok(message)
1410 }
1411
1412 fn handle_update_function(&self, args: &[Value]) -> Result<String> {
1414 if let Some(arg) = args.first() {
1415 Ok(format!("Updated: {}", arg.to_string()))
1416 } else {
1417 Ok("Updated".to_string())
1418 }
1419 }
1420
1421 fn handle_timestamp_function(&self) -> Result<String> {
1423 use std::time::{SystemTime, UNIX_EPOCH};
1424 let timestamp = SystemTime::now()
1425 .duration_since(UNIX_EPOCH)
1426 .map_err(|e| RuleEngineError::EvaluationError {
1427 message: format!("Failed to get timestamp: {}", e),
1428 })?
1429 .as_secs();
1430 Ok(timestamp.to_string())
1431 }
1432
1433 fn handle_random_function(&self, args: &[Value]) -> Result<String> {
1435 use std::collections::hash_map::DefaultHasher;
1436 use std::hash::{Hash, Hasher};
1437
1438 let mut hasher = DefaultHasher::new();
1440 std::time::SystemTime::now().hash(&mut hasher);
1441 let random_value = hasher.finish();
1442
1443 if args.is_empty() {
1444 Ok((random_value % 100).to_string()) } else if let Some(Value::Number(max)) = args.first() {
1446 let max_val = *max as u64;
1447 Ok((random_value % max_val).to_string())
1448 } else {
1449 Ok(random_value.to_string())
1450 }
1451 }
1452
1453 fn handle_format_function(&self, args: &[Value]) -> Result<String> {
1455 if args.is_empty() {
1456 return Ok("".to_string());
1457 }
1458
1459 let template = args[0].to_string();
1460 let values: Vec<String> = args[1..].iter().map(|v| v.to_string()).collect();
1461
1462 let mut result = template;
1464 for (i, value) in values.iter().enumerate() {
1465 result = result.replace(&format!("{{{}}}", i), value);
1466 }
1467
1468 Ok(result)
1469 }
1470
1471 fn handle_length_function(&self, args: &[Value]) -> Result<String> {
1473 if let Some(arg) = args.first() {
1474 match arg {
1475 Value::String(s) => Ok(s.len().to_string()),
1476 Value::Array(arr) => Ok(arr.len().to_string()),
1477 Value::Object(obj) => Ok(obj.len().to_string()),
1478 _ => Ok("1".to_string()), }
1480 } else {
1481 Ok("0".to_string())
1482 }
1483 }
1484
1485 fn handle_sum_function(&self, args: &[Value]) -> Result<String> {
1487 let sum = args.iter().fold(0.0, |acc, val| match val {
1488 Value::Number(n) => acc + n,
1489 Value::Integer(i) => acc + (*i as f64),
1490 _ => acc,
1491 });
1492 Ok(sum.to_string())
1493 }
1494
1495 fn handle_max_function(&self, args: &[Value]) -> Result<String> {
1497 let max = args.iter().fold(f64::NEG_INFINITY, |acc, val| match val {
1498 Value::Number(n) => acc.max(*n),
1499 Value::Integer(i) => acc.max(*i as f64),
1500 _ => acc,
1501 });
1502 Ok(max.to_string())
1503 }
1504
1505 fn handle_min_function(&self, args: &[Value]) -> Result<String> {
1507 let min = args.iter().fold(f64::INFINITY, |acc, val| match val {
1508 Value::Number(n) => acc.min(*n),
1509 Value::Integer(i) => acc.min(*i as f64),
1510 _ => acc,
1511 });
1512 Ok(min.to_string())
1513 }
1514
1515 fn handle_average_function(&self, args: &[Value]) -> Result<String> {
1517 if args.is_empty() {
1518 return Ok("0".to_string());
1519 }
1520
1521 let (sum, count) = args.iter().fold((0.0, 0), |(sum, count), val| match val {
1522 Value::Number(n) => (sum + n, count + 1),
1523 Value::Integer(i) => (sum + (*i as f64), count + 1),
1524 _ => (sum, count),
1525 });
1526
1527 if count > 0 {
1528 Ok((sum / count as f64).to_string())
1529 } else {
1530 Ok("0".to_string())
1531 }
1532 }
1533
1534 fn handle_round_function(&self, args: &[Value]) -> Result<String> {
1536 if let Some(Value::Number(n)) = args.first() {
1537 Ok(n.round().to_string())
1538 } else if let Some(Value::Integer(i)) = args.first() {
1539 Ok(i.to_string())
1540 } else {
1541 Err(RuleEngineError::EvaluationError {
1542 message: "round() requires a numeric argument".to_string(),
1543 })
1544 }
1545 }
1546
1547 fn handle_floor_function(&self, args: &[Value]) -> Result<String> {
1548 if let Some(Value::Number(n)) = args.first() {
1549 Ok(n.floor().to_string())
1550 } else if let Some(Value::Integer(i)) = args.first() {
1551 Ok(i.to_string())
1552 } else {
1553 Err(RuleEngineError::EvaluationError {
1554 message: "floor() requires a numeric argument".to_string(),
1555 })
1556 }
1557 }
1558
1559 fn handle_ceil_function(&self, args: &[Value]) -> Result<String> {
1560 if let Some(Value::Number(n)) = args.first() {
1561 Ok(n.ceil().to_string())
1562 } else if let Some(Value::Integer(i)) = args.first() {
1563 Ok(i.to_string())
1564 } else {
1565 Err(RuleEngineError::EvaluationError {
1566 message: "ceil() requires a numeric argument".to_string(),
1567 })
1568 }
1569 }
1570
1571 fn handle_abs_function(&self, args: &[Value]) -> Result<String> {
1572 if let Some(Value::Number(n)) = args.first() {
1573 Ok(n.abs().to_string())
1574 } else if let Some(Value::Integer(i)) = args.first() {
1575 Ok(i.abs().to_string())
1576 } else {
1577 Err(RuleEngineError::EvaluationError {
1578 message: "abs() requires a numeric argument".to_string(),
1579 })
1580 }
1581 }
1582
1583 fn handle_contains_function(&self, args: &[Value]) -> Result<String> {
1585 if args.len() >= 2 {
1586 let haystack = args[0].to_string();
1587 let needle = args[1].to_string();
1588 Ok(haystack.contains(&needle).to_string())
1589 } else {
1590 Err(RuleEngineError::EvaluationError {
1591 message: "contains() requires 2 arguments".to_string(),
1592 })
1593 }
1594 }
1595
1596 fn handle_starts_with_function(&self, args: &[Value]) -> Result<String> {
1597 if args.len() >= 2 {
1598 let text = args[0].to_string();
1599 let prefix = args[1].to_string();
1600 Ok(text.starts_with(&prefix).to_string())
1601 } else {
1602 Err(RuleEngineError::EvaluationError {
1603 message: "startswith() requires 2 arguments".to_string(),
1604 })
1605 }
1606 }
1607
1608 fn handle_ends_with_function(&self, args: &[Value]) -> Result<String> {
1609 if args.len() >= 2 {
1610 let text = args[0].to_string();
1611 let suffix = args[1].to_string();
1612 Ok(text.ends_with(&suffix).to_string())
1613 } else {
1614 Err(RuleEngineError::EvaluationError {
1615 message: "endswith() requires 2 arguments".to_string(),
1616 })
1617 }
1618 }
1619
1620 fn handle_lowercase_function(&self, args: &[Value]) -> Result<String> {
1621 if let Some(arg) = args.first() {
1622 Ok(arg.to_string().to_lowercase())
1623 } else {
1624 Err(RuleEngineError::EvaluationError {
1625 message: "lowercase() requires 1 argument".to_string(),
1626 })
1627 }
1628 }
1629
1630 fn handle_uppercase_function(&self, args: &[Value]) -> Result<String> {
1631 if let Some(arg) = args.first() {
1632 Ok(arg.to_string().to_uppercase())
1633 } else {
1634 Err(RuleEngineError::EvaluationError {
1635 message: "uppercase() requires 1 argument".to_string(),
1636 })
1637 }
1638 }
1639
1640 fn handle_trim_function(&self, args: &[Value]) -> Result<String> {
1641 if let Some(arg) = args.first() {
1642 Ok(arg.to_string().trim().to_string())
1643 } else {
1644 Err(RuleEngineError::EvaluationError {
1645 message: "trim() requires 1 argument".to_string(),
1646 })
1647 }
1648 }
1649
1650 fn handle_split_function(&self, args: &[Value]) -> Result<String> {
1651 if args.len() >= 2 {
1652 let text = args[0].to_string();
1653 let delimiter = args[1].to_string();
1654 let parts: Vec<String> = text.split(&delimiter).map(|s| s.to_string()).collect();
1655 Ok(format!("{:?}", parts)) } else {
1657 Err(RuleEngineError::EvaluationError {
1658 message: "split() requires 2 arguments".to_string(),
1659 })
1660 }
1661 }
1662
1663 fn handle_join_function(&self, args: &[Value]) -> Result<String> {
1664 if args.len() >= 2 {
1665 let delimiter = args[0].to_string();
1666 let parts: Vec<String> = args[1..].iter().map(|v| v.to_string()).collect();
1667 Ok(parts.join(&delimiter))
1668 } else {
1669 Err(RuleEngineError::EvaluationError {
1670 message: "join() requires at least 2 arguments".to_string(),
1671 })
1672 }
1673 }
1674
1675 fn handle_custom_function(
1677 &self,
1678 function: &str,
1679 args: &[Value],
1680 facts: &Facts,
1681 ) -> Result<String> {
1682 if let Some(custom_func) = self.custom_functions.get(function) {
1684 if self.config.debug_mode {
1685 println!("🎯 Calling registered function: {}({:?})", function, args);
1686 }
1687
1688 match custom_func(args, facts) {
1689 Ok(result) => Ok(result.to_string()),
1690 Err(e) => Err(e),
1691 }
1692 } else {
1693 if self.config.debug_mode {
1695 println!("⚠️ Custom function '{}' not registered", function);
1696 }
1697
1698 Err(RuleEngineError::EvaluationError {
1699 message: format!("Function '{}' is not registered. Use engine.register_function() to add custom functions.", function),
1700 })
1701 }
1702 }
1703
1704 fn execute_method_call(
1706 &self,
1707 object_name: &str,
1708 method: &str,
1709 args: &[Value],
1710 facts: &Facts,
1711 ) -> Result<String> {
1712 let Some(object_value) = facts.get(object_name) else {
1714 return Err(RuleEngineError::EvaluationError {
1715 message: format!("Object '{}' not found in facts", object_name),
1716 });
1717 };
1718
1719 let method_lower = method.to_lowercase();
1720
1721 if method_lower.starts_with("set") && args.len() == 1 {
1723 return self.handle_setter_method(object_name, method, &args[0], object_value, facts);
1724 }
1725
1726 if method_lower.starts_with("get") && args.is_empty() {
1728 return self.handle_getter_method(object_name, method, &object_value);
1729 }
1730
1731 match method_lower.as_str() {
1733 "tostring" => Ok(object_value.to_string()),
1734 "update" => {
1735 facts.add_value(object_name, object_value)?;
1736 Ok(format!("Updated {}", object_name))
1737 }
1738 "reset" => self.handle_reset_method(object_name, object_value, facts),
1739 _ => self.handle_property_access_or_fallback(
1740 object_name,
1741 method,
1742 args.len(),
1743 &object_value,
1744 ),
1745 }
1746 }
1747
1748 fn handle_setter_method(
1750 &self,
1751 object_name: &str,
1752 method: &str,
1753 new_value: &Value,
1754 mut object_value: Value,
1755 facts: &Facts,
1756 ) -> Result<String> {
1757 let property_name = Self::extract_property_name_from_setter(method);
1758
1759 match object_value {
1760 Value::Object(ref mut obj) => {
1761 obj.insert(property_name.clone(), new_value.clone());
1762 facts.add_value(object_name, object_value)?;
1763 Ok(format!(
1764 "Set {} to {}",
1765 property_name,
1766 new_value.to_string()
1767 ))
1768 }
1769 _ => Err(RuleEngineError::EvaluationError {
1770 message: format!("Cannot call setter on non-object type: {}", object_name),
1771 }),
1772 }
1773 }
1774
1775 fn handle_getter_method(
1777 &self,
1778 object_name: &str,
1779 method: &str,
1780 object_value: &Value,
1781 ) -> Result<String> {
1782 let property_name = Self::extract_property_name_from_getter(method);
1783
1784 match object_value {
1785 Value::Object(obj) => {
1786 if let Some(value) = obj.get(&property_name) {
1787 Ok(value.to_string())
1788 } else {
1789 Err(RuleEngineError::EvaluationError {
1790 message: format!(
1791 "Property '{}' not found on object '{}'",
1792 property_name, object_name
1793 ),
1794 })
1795 }
1796 }
1797 _ => Err(RuleEngineError::EvaluationError {
1798 message: format!("Cannot call getter on non-object type: {}", object_name),
1799 }),
1800 }
1801 }
1802
1803 fn handle_reset_method(
1805 &self,
1806 object_name: &str,
1807 mut object_value: Value,
1808 facts: &Facts,
1809 ) -> Result<String> {
1810 match object_value {
1811 Value::Object(ref mut obj) => {
1812 obj.clear();
1813 facts.add_value(object_name, object_value)?;
1814 Ok(format!("Reset {}", object_name))
1815 }
1816 _ => Err(RuleEngineError::EvaluationError {
1817 message: format!("Cannot reset non-object type: {}", object_name),
1818 }),
1819 }
1820 }
1821
1822 fn handle_property_access_or_fallback(
1824 &self,
1825 object_name: &str,
1826 method: &str,
1827 arg_count: usize,
1828 object_value: &Value,
1829 ) -> Result<String> {
1830 if let Value::Object(obj) = object_value {
1831 if let Some(value) = obj.get(method) {
1833 return Ok(value.to_string());
1834 }
1835
1836 let capitalized_method = Self::capitalize_first_letter(method);
1838 if let Some(value) = obj.get(&capitalized_method) {
1839 return Ok(value.to_string());
1840 }
1841 }
1842
1843 Ok(format!(
1845 "Called {}.{} with {} args",
1846 object_name, method, arg_count
1847 ))
1848 }
1849
1850 fn extract_property_name_from_setter(method: &str) -> String {
1852 let property_name = &method[3..]; Self::capitalize_first_letter(property_name)
1854 }
1855
1856 fn extract_property_name_from_getter(method: &str) -> String {
1858 let property_name = &method[3..]; Self::capitalize_first_letter(property_name)
1860 }
1861
1862 fn capitalize_first_letter(s: &str) -> String {
1864 if s.is_empty() {
1865 return String::new();
1866 }
1867 let mut chars = s.chars();
1868 match chars.next() {
1869 None => String::new(),
1870 Some(first) => first.to_uppercase().collect::<String>() + chars.as_str(),
1871 }
1872 }
1873
1874 fn resolve_action_parameters(
1876 &self,
1877 params: &HashMap<String, Value>,
1878 facts: &Facts,
1879 ) -> Result<HashMap<String, Value>> {
1880 let mut resolved = HashMap::new();
1881
1882 for (key, value) in params {
1883 let resolved_value = match value {
1884 Value::String(s) => {
1885 if s.contains('.') {
1887 if let Some(fact_value) = facts.get_nested(s) {
1889 fact_value
1890 } else {
1891 value.clone()
1893 }
1894 } else {
1895 value.clone()
1896 }
1897 }
1898 _ => value.clone(),
1899 };
1900 resolved.insert(key.clone(), resolved_value);
1901 }
1902
1903 Ok(resolved)
1904 }
1905
1906 pub fn load_plugin(
1910 &mut self,
1911 plugin: std::sync::Arc<dyn crate::engine::plugin::RulePlugin>,
1912 ) -> Result<()> {
1913 plugin.register_actions(self)?;
1915 plugin.register_functions(self)?;
1916
1917 self.plugin_manager.load_plugin(plugin)
1919 }
1920
1921 pub fn unload_plugin(&mut self, name: &str) -> Result<()> {
1923 self.plugin_manager.unload_plugin(name)
1924 }
1925
1926 pub fn hot_reload_plugin(
1928 &mut self,
1929 name: &str,
1930 new_plugin: std::sync::Arc<dyn crate::engine::plugin::RulePlugin>,
1931 ) -> Result<()> {
1932 self.plugin_manager.unload_plugin(name)?;
1934
1935 new_plugin.register_actions(self)?;
1937 new_plugin.register_functions(self)?;
1938
1939 self.plugin_manager.load_plugin(new_plugin)
1941 }
1942
1943 pub fn get_plugin_info(&self, name: &str) -> Option<&crate::engine::plugin::PluginMetadata> {
1945 self.plugin_manager.get_plugin_info(name)
1946 }
1947
1948 pub fn list_plugins(&self) -> Vec<PluginInfo> {
1950 self.plugin_manager.list_plugins()
1951 }
1952
1953 pub fn get_plugin_stats(&self) -> PluginStats {
1955 self.plugin_manager.get_stats()
1956 }
1957
1958 pub fn plugin_health_check(&mut self) -> HashMap<String, crate::engine::plugin::PluginHealth> {
1960 self.plugin_manager.plugin_health_check()
1961 }
1962
1963 pub fn configure_plugins(&mut self, config: PluginConfig) {
1965 self.plugin_manager = PluginManager::new(config);
1966 }
1967}