use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use uuid::Uuid;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PatternUsage {
pub pattern_id: Uuid,
pub retrieval_count: usize,
pub application_count: usize,
pub success_count: usize,
pub failure_count: usize,
pub last_retrieved: Option<DateTime<Utc>>,
pub last_applied: Option<DateTime<Utc>>,
pub created_at: DateTime<Utc>,
pub effectiveness_score: f32,
}
impl PatternUsage {
#[must_use]
pub fn new(pattern_id: Uuid) -> Self {
Self {
pattern_id,
retrieval_count: 0,
application_count: 0,
success_count: 0,
failure_count: 0,
last_retrieved: None,
last_applied: None,
created_at: Utc::now(),
effectiveness_score: 0.5, }
}
#[must_use]
pub fn success_rate(&self) -> f32 {
if self.application_count == 0 {
return 0.5; }
self.success_count as f32 / self.application_count as f32
}
#[must_use]
pub fn application_rate(&self) -> f32 {
if self.retrieval_count == 0 {
return 0.0;
}
self.application_count as f32 / self.retrieval_count as f32
}
#[must_use]
pub fn recency_factor(&self, now: DateTime<Utc>) -> f32 {
let last_use = self
.last_applied
.or(self.last_retrieved)
.unwrap_or(self.created_at);
let days_since_use = (now - last_use).num_days().max(0) as f32;
let decay_rate = (days_since_use / 30.0).min(10.0);
(-decay_rate * 0.693).exp() }
pub fn update_effectiveness_score(&mut self) {
let now = Utc::now();
let success_weight = 0.4;
let application_weight = 0.3;
let recency_weight = 0.2;
let confidence_weight = 0.1;
let success_score = self.success_rate();
let application_score = self.application_rate();
let recency_score = self.recency_factor(now);
let confidence_score = (self.application_count.min(20) as f32 / 20.0).min(1.0);
self.effectiveness_score = (success_score * success_weight)
+ (application_score * application_weight)
+ (recency_score * recency_weight)
+ (confidence_score * confidence_weight);
}
#[must_use]
pub fn should_keep(&self, min_effectiveness: f32) -> bool {
self.effectiveness_score >= min_effectiveness
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UsageStats {
pub retrieval_count: usize,
pub application_count: usize,
pub success_rate: f32,
pub application_rate: f32,
pub effectiveness_score: f32,
pub days_since_last_use: i64,
pub usage_count: usize,
}
#[cfg(test)]
mod tests {
use super::*;
use chrono::Duration;
#[test]
fn test_pattern_usage_creation() {
let pattern_id = Uuid::new_v4();
let usage = PatternUsage::new(pattern_id);
assert_eq!(usage.pattern_id, pattern_id);
assert_eq!(usage.retrieval_count, 0);
assert_eq!(usage.application_count, 0);
assert_eq!(usage.success_count, 0);
assert_eq!(usage.effectiveness_score, 0.5);
}
#[test]
fn test_success_rate_calculation() {
let mut usage = PatternUsage::new(Uuid::new_v4());
assert_eq!(usage.success_rate(), 0.5);
usage.application_count = 10;
usage.success_count = 8;
assert_eq!(usage.success_rate(), 0.8);
usage.success_count = 0;
assert_eq!(usage.success_rate(), 0.0);
}
#[test]
fn test_application_rate() {
let mut usage = PatternUsage::new(Uuid::new_v4());
usage.retrieval_count = 10;
usage.application_count = 5;
assert_eq!(usage.application_rate(), 0.5);
usage.retrieval_count = 0;
assert_eq!(usage.application_rate(), 0.0);
}
#[test]
fn test_recency_factor() {
let mut usage = PatternUsage::new(Uuid::new_v4());
let now = Utc::now();
let recency = usage.recency_factor(now);
assert!(recency > 0.95);
usage.last_applied = Some(now - Duration::days(30));
let recency = usage.recency_factor(now);
assert!(recency < 0.6 && recency > 0.4);
usage.last_applied = Some(now - Duration::days(90));
let recency = usage.recency_factor(now);
assert!(recency < 0.2); }
#[test]
fn test_effectiveness_score_update() {
let mut usage = PatternUsage::new(Uuid::new_v4());
usage.retrieval_count = 10;
usage.application_count = 8;
usage.success_count = 7;
usage.last_applied = Some(Utc::now());
usage.update_effectiveness_score();
assert!(usage.effectiveness_score > 0.6);
usage.application_count = 1;
usage.success_count = 0;
usage.last_applied = Some(Utc::now() - Duration::days(60));
usage.update_effectiveness_score();
assert!(usage.effectiveness_score < 0.4);
}
#[test]
fn test_should_keep_pattern() {
let mut usage = PatternUsage::new(Uuid::new_v4());
usage.effectiveness_score = 0.8;
assert!(usage.should_keep(0.3));
usage.effectiveness_score = 0.2;
assert!(!usage.should_keep(0.3));
usage.effectiveness_score = 0.3;
assert!(usage.should_keep(0.3));
}
}