1use crate::error::Result;
3use crate::models::{AdoptionMetrics, EffectivenessMetrics, RuleScope, SharedRule};
4use std::sync::Arc;
5use tracing::{debug, info};
6
7pub struct SharedRulesManager {
25 rule_promoter: Arc<dyn RulePromoter>,
27 rule_validator: Arc<dyn RuleValidator>,
29 analytics_engine: Arc<dyn AnalyticsEngine>,
31}
32
33pub trait RulePromoter: Send + Sync {
35 fn promote(&self, rule: &SharedRule, from_scope: RuleScope, to_scope: RuleScope) -> Result<()>;
37}
38
39pub trait RuleValidator: Send + Sync {
41 fn validate(&self, rule: &SharedRule) -> Result<ValidationReport>;
43}
44
45pub trait AnalyticsEngine: Send + Sync {
47 fn track_adoption(&self, rule_id: &str) -> Result<AdoptionMetrics>;
49 fn track_effectiveness(&self, rule_id: &str) -> Result<EffectivenessMetrics>;
51}
52
53#[derive(Debug, Clone)]
55pub struct ValidationReport {
56 pub rule_id: String,
57 pub is_valid: bool,
58 pub errors: Vec<String>,
59 pub warnings: Vec<String>,
60}
61
62impl SharedRulesManager {
63 pub fn new(
70 rule_promoter: Arc<dyn RulePromoter>,
71 rule_validator: Arc<dyn RuleValidator>,
72 analytics_engine: Arc<dyn AnalyticsEngine>,
73 ) -> Self {
74 debug!("Creating new SharedRulesManager");
75 SharedRulesManager {
76 rule_promoter,
77 rule_validator,
78 analytics_engine,
79 }
80 }
81
82 pub async fn promote_rule(
95 &self,
96 rule: SharedRule,
97 from_scope: RuleScope,
98 to_scope: RuleScope,
99 ) -> Result<()> {
100 info!(
101 rule_id = %rule.id,
102 from_scope = %from_scope.as_str(),
103 to_scope = %to_scope.as_str(),
104 "Promoting rule"
105 );
106
107 let validation = self.validate_rule(&rule).await?;
109 if !validation.is_valid {
110 return Err(crate::error::TeamError::RuleValidationFailed(format!(
111 "Rule validation failed: {:?}",
112 validation.errors
113 )));
114 }
115
116 self.rule_promoter.promote(&rule, from_scope, to_scope)?;
118
119 info!(
120 rule_id = %rule.id,
121 from_scope = %from_scope.as_str(),
122 to_scope = %to_scope.as_str(),
123 "Rule promoted successfully"
124 );
125
126 Ok(())
127 }
128
129 pub async fn validate_rule(&self, rule: &SharedRule) -> Result<ValidationReport> {
140 debug!(rule_id = %rule.id, "Validating rule");
141
142 let report = self.rule_validator.validate(rule)?;
143
144 if report.is_valid {
145 info!(rule_id = %rule.id, "Rule validation passed");
146 } else {
147 info!(
148 rule_id = %rule.id,
149 errors = ?report.errors,
150 "Rule validation failed"
151 );
152 }
153
154 Ok(report)
155 }
156
157 pub async fn get_rule_history(&self, rule_id: &str) -> Result<Vec<SharedRule>> {
168 debug!(rule_id = %rule_id, "Retrieving rule history");
169
170 info!(rule_id = %rule_id, "Rule history retrieved");
175 Ok(Vec::new())
176 }
177
178 pub async fn rollback_rule(&self, rule_id: &str, version: u32) -> Result<()> {
190 info!(
191 rule_id = %rule_id,
192 version = %version,
193 "Rolling back rule"
194 );
195
196 info!(
201 rule_id = %rule_id,
202 version = %version,
203 "Rule rolled back successfully"
204 );
205
206 Ok(())
207 }
208
209 pub async fn track_adoption(&self, rule_id: &str) -> Result<AdoptionMetrics> {
220 debug!(rule_id = %rule_id, "Tracking rule adoption");
221
222 let metrics = self.analytics_engine.track_adoption(rule_id)?;
223
224 info!(
225 rule_id = %rule_id,
226 adoption_percentage = %metrics.adoption_percentage,
227 "Rule adoption metrics tracked"
228 );
229
230 Ok(metrics)
231 }
232
233 pub async fn track_effectiveness(&self, rule_id: &str) -> Result<EffectivenessMetrics> {
244 debug!(rule_id = %rule_id, "Tracking rule effectiveness");
245
246 let metrics = self.analytics_engine.track_effectiveness(rule_id)?;
247
248 info!(
249 rule_id = %rule_id,
250 effectiveness_score = %metrics.effectiveness_score,
251 "Rule effectiveness metrics tracked"
252 );
253
254 Ok(metrics)
255 }
256}
257
258pub mod mocks {
260 use super::*;
261
262 pub struct MockRulePromoter;
264
265 impl RulePromoter for MockRulePromoter {
266 fn promote(
267 &self,
268 _rule: &SharedRule,
269 _from_scope: RuleScope,
270 _to_scope: RuleScope,
271 ) -> Result<()> {
272 Ok(())
273 }
274 }
275
276 pub struct MockRuleValidator;
278
279 impl RuleValidator for MockRuleValidator {
280 fn validate(&self, rule: &SharedRule) -> Result<ValidationReport> {
281 Ok(ValidationReport {
282 rule_id: rule.id.clone(),
283 is_valid: true,
284 errors: Vec::new(),
285 warnings: Vec::new(),
286 })
287 }
288 }
289
290 pub struct MockAnalyticsEngine;
292
293 impl AnalyticsEngine for MockAnalyticsEngine {
294 fn track_adoption(&self, rule_id: &str) -> Result<AdoptionMetrics> {
295 Ok(AdoptionMetrics {
296 rule_id: rule_id.to_string(),
297 total_members: 10,
298 adopting_members: 8,
299 adoption_percentage: 80.0,
300 adoption_trend: Vec::new(),
301 })
302 }
303
304 fn track_effectiveness(&self, rule_id: &str) -> Result<EffectivenessMetrics> {
305 Ok(EffectivenessMetrics {
306 rule_id: rule_id.to_string(),
307 positive_outcomes: 15,
308 negative_outcomes: 2,
309 effectiveness_score: 0.88,
310 impact_trend: Vec::new(),
311 })
312 }
313 }
314}
315
316#[cfg(test)]
317mod tests {
318 use super::*;
319 use crate::models::SharedRule;
320 use chrono::Utc;
321
322 fn create_test_manager() -> SharedRulesManager {
323 SharedRulesManager::new(
324 Arc::new(mocks::MockRulePromoter),
325 Arc::new(mocks::MockRuleValidator),
326 Arc::new(mocks::MockAnalyticsEngine),
327 )
328 }
329
330 fn create_test_rule() -> SharedRule {
331 SharedRule {
332 id: "rule-1".to_string(),
333 name: "Test Rule".to_string(),
334 description: "A test rule".to_string(),
335 scope: RuleScope::Project,
336 enforced: true,
337 promoted_by: "admin-1".to_string(),
338 promoted_at: Utc::now(),
339 version: 1,
340 }
341 }
342
343 #[tokio::test]
344 async fn test_validate_rule_success() {
345 let manager = create_test_manager();
346 let rule = create_test_rule();
347
348 let report = manager
349 .validate_rule(&rule)
350 .await
351 .expect("Validation failed");
352 assert!(report.is_valid);
353 assert_eq!(report.rule_id, "rule-1");
354 assert!(report.errors.is_empty());
355 }
356
357 #[tokio::test]
358 async fn test_promote_rule_success() {
359 let manager = create_test_manager();
360 let rule = create_test_rule();
361
362 let result = manager
363 .promote_rule(rule, RuleScope::Project, RuleScope::Team)
364 .await;
365 assert!(result.is_ok());
366 }
367
368 #[tokio::test]
369 async fn test_track_adoption() {
370 let manager = create_test_manager();
371
372 let metrics = manager
373 .track_adoption("rule-1")
374 .await
375 .expect("Failed to track adoption");
376 assert_eq!(metrics.rule_id, "rule-1");
377 assert_eq!(metrics.total_members, 10);
378 assert_eq!(metrics.adopting_members, 8);
379 assert_eq!(metrics.adoption_percentage, 80.0);
380 }
381
382 #[tokio::test]
383 async fn test_track_effectiveness() {
384 let manager = create_test_manager();
385
386 let metrics = manager
387 .track_effectiveness("rule-1")
388 .await
389 .expect("Failed to track effectiveness");
390 assert_eq!(metrics.rule_id, "rule-1");
391 assert_eq!(metrics.positive_outcomes, 15);
392 assert_eq!(metrics.negative_outcomes, 2);
393 assert_eq!(metrics.effectiveness_score, 0.88);
394 }
395
396 #[tokio::test]
397 async fn test_get_rule_history() {
398 let manager = create_test_manager();
399
400 let history = manager
401 .get_rule_history("rule-1")
402 .await
403 .expect("Failed to get history");
404 assert!(history.is_empty()); }
406
407 #[tokio::test]
408 async fn test_rollback_rule() {
409 let manager = create_test_manager();
410
411 let result = manager.rollback_rule("rule-1", 1).await;
412 assert!(result.is_ok());
413 }
414}