1use crate::EvaluationRequest;
4use std::collections::HashMap;
5
6pub struct EvaluationContext {
8 fields: HashMap<String, FieldValue>,
10}
11
12impl EvaluationContext {
13 pub fn from_request(request: &EvaluationRequest) -> Self {
15 let mut ctx = EvaluationContext {
16 fields: HashMap::new(),
17 };
18
19 ctx.set_field("agent.id", FieldValue::String(request.agent_id.clone()));
21 ctx.set_field("agent.org", FieldValue::String(request.agent_org.clone()));
22 ctx.set_field("agent.level", FieldValue::String(request.agent_level.clone()));
23 ctx.set_field("agent.requests_last_hour", FieldValue::Number(request.requests_last_hour as i64));
24 ctx.set_field("agent.requests_last_24h", FieldValue::Number(request.requests_last_24h as i64));
25
26 if let Some(mission_id) = &request.mission_id {
28 ctx.set_field("mission.id", FieldValue::String(mission_id.clone()));
29 }
30 if let Some(mission_type) = &request.mission_type {
31 ctx.set_field("mission.type", FieldValue::String(mission_type.clone()));
32 }
33
34 if let Some(query_type) = &request.query_type {
36 ctx.set_field("request.query_type", FieldValue::String(query_type.clone()));
37 }
38 if let Some(justification) = &request.justification {
39 ctx.set_field("request.justification", FieldValue::String(justification.clone()));
40 ctx.set_field("request.justification_length", FieldValue::Number(justification.len() as i64));
41 }
42 if let Some(export_format) = &request.export_format {
43 ctx.set_field("request.export_format", FieldValue::String(export_format.clone()));
44 }
45 if let Some(limit) = request.result_limit {
46 ctx.set_field("request.result_limit", FieldValue::Number(limit as i64));
47 }
48
49 ctx.set_field("request.results_last_query", FieldValue::Number(request.results_last_query as i64));
51
52 if let Some(dept) = &request.account_department {
54 ctx.set_field("account.department", FieldValue::String(dept.clone()));
55 }
56
57 for (i, dept) in request.allowed_departments.iter().enumerate() {
59 ctx.set_field(
60 &format!("agent.allowed_departments[{}]", i),
61 FieldValue::Number(*dept as i64),
62 );
63 }
64
65 ctx.set_field("context.request_hour", FieldValue::Number(request.request_hour as i64));
67 ctx.set_field("context.is_within_mission_hours", FieldValue::Boolean(request.is_within_mission_hours));
68
69 ctx
70 }
71
72 pub fn get_field(&self, path: &str) -> Option<&FieldValue> {
74 self.fields.get(path)
75 }
76
77 pub fn set_field(&mut self, path: &str, value: FieldValue) {
79 self.fields.insert(path.to_string(), value);
80 }
81
82 pub fn fields(&self) -> &HashMap<String, FieldValue> {
84 &self.fields
85 }
86}
87
88#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
90pub enum FieldValue {
91 Number(i64),
92 Float(f64),
93 String(String),
94 Boolean(bool),
95}
96
97impl FieldValue {
98 pub fn compare(&self, op: &str, other: &FieldValue) -> bool {
100 match (self, other) {
101 (FieldValue::Number(a), FieldValue::Number(b)) => {
102 match op {
103 ">" => a > b,
104 "<" => a < b,
105 ">=" => a >= b,
106 "<=" => a <= b,
107 "==" => a == b,
108 "!=" => a != b,
109 _ => false,
110 }
111 }
112 (FieldValue::String(a), FieldValue::String(b)) => {
113 match op {
114 "==" => a == b,
115 "!=" => a != b,
116 _ => false,
117 }
118 }
119 (FieldValue::Boolean(a), FieldValue::Boolean(b)) => {
120 match op {
121 "==" => a == b,
122 "!=" => a != b,
123 _ => false,
124 }
125 }
126 _ => false,
127 }
128 }
129}
130
131#[cfg(test)]
132mod tests {
133 use super::*;
134
135 #[test]
136 fn test_context_creation() {
137 let request = EvaluationRequest {
138 request_id: "test".to_string(),
139 agent_id: "AGENT_001".to_string(),
140 agent_org: "DGFiP".to_string(),
141 agent_level: "standard".to_string(),
142 mission_id: Some("MIS_001".to_string()),
143 mission_type: None,
144 query_type: None,
145 justification: None,
146 export_format: None,
147 result_limit: None,
148 requests_last_hour: 10,
149 requests_last_24h: 100,
150 results_last_query: 5,
151 account_department: None,
152 allowed_departments: vec![],
153 request_hour: 14,
154 is_within_mission_hours: true,
155 };
156
157 let ctx = EvaluationContext::from_request(&request);
158
159 assert_eq!(
160 ctx.get_field("agent.id"),
161 Some(&FieldValue::String("AGENT_001".to_string()))
162 );
163 assert_eq!(
164 ctx.get_field("agent.requests_last_hour"),
165 Some(&FieldValue::Number(10))
166 );
167 }
168
169 #[test]
170 fn test_field_comparison() {
171 assert!(FieldValue::Number(10).compare(">", &FieldValue::Number(5)));
172 assert!(FieldValue::Number(10).compare(">=", &FieldValue::Number(10)));
173 assert!(FieldValue::String("test".to_string()).compare("==", &FieldValue::String("test".to_string())));
174 }
175}