1use serde::{Deserialize, Serialize};
2
3use crate::profile::DomainMismatch;
4
5#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
10pub enum RiskLevel {
11 Low,
12 Medium,
13 High,
14 Critical,
15}
16
17impl RiskLevel {
18 pub fn label(&self) -> &str {
19 match self {
20 RiskLevel::Low => "LOW",
21 RiskLevel::Medium => "MEDIUM",
22 RiskLevel::High => "HIGH",
23 RiskLevel::Critical => "CRITICAL",
24 }
25 }
26}
27
28#[derive(Debug, Clone, Serialize, Deserialize)]
29pub struct RiskScore {
30 pub level: RiskLevel,
31 pub reasons: Vec<String>,
32 pub recommendations: Vec<String>,
33}
34
35impl Default for RiskScore {
36 fn default() -> Self {
37 RiskScore {
38 level: RiskLevel::Low,
39 reasons: vec![],
40 recommendations: vec![],
41 }
42 }
43}
44
45#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
50pub enum ConfidenceLevel {
51 High, Medium, Low, }
55
56impl ConfidenceLevel {
57 pub fn label(&self) -> &str {
58 match self {
59 ConfidenceLevel::High => "HIGH",
60 ConfidenceLevel::Medium => "MEDIUM",
61 ConfidenceLevel::Low => "LOW",
62 }
63 }
64}
65
66#[derive(Debug, Clone, Default, Serialize, Deserialize)]
71pub struct ConversionReport {
72 pub source_vendor: String,
73 pub target_vendor: String,
74 pub summary: ReportSummary,
75 pub items: Vec<ReportItem>,
76 pub risk: RiskScore,
77 pub domain_mismatches: Vec<DomainMismatch>,
81}
82
83#[derive(Debug, Clone, Default, Serialize, Deserialize)]
84pub struct ReportSummary {
85 pub total_commands: usize,
86 pub exact: usize,
87 pub approximate: usize,
88 pub manual_required: usize,
89 pub unknown: usize,
90}
91
92impl ReportSummary {
93 pub fn exact_pct(&self) -> f32 {
94 if self.total_commands == 0 {
95 return 0.0;
96 }
97 self.exact as f32 / self.total_commands as f32 * 100.0
98 }
99
100 pub fn coverage_pct(&self) -> f32 {
101 if self.total_commands == 0 {
102 return 0.0;
103 }
104 (self.exact + self.approximate) as f32 / self.total_commands as f32 * 100.0
105 }
106}
107
108#[derive(Debug, Clone, Serialize, Deserialize)]
109pub struct ReportItem {
110 pub severity: Severity,
111 pub category: String,
112 pub source_snippet: String,
113 pub target_snippet: Option<String>,
114 pub message: String,
115 pub recommendation: Option<String>,
116}
117
118#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
119pub enum Severity {
120 Ok,
122 Warn,
124 Error,
126 Info,
128}
129
130impl ConversionReport {
131 pub fn new(source_vendor: &str, target_vendor: &str) -> Self {
132 ConversionReport {
133 source_vendor: source_vendor.to_string(),
134 target_vendor: target_vendor.to_string(),
135 ..Default::default()
136 }
137 }
138
139 pub fn add_exact(&mut self, category: &str, source: &str, target: &str) {
140 self.summary.exact += 1;
141 self.summary.total_commands += 1;
142 self.items.push(ReportItem {
143 severity: Severity::Ok,
144 category: category.to_string(),
145 source_snippet: source.to_string(),
146 target_snippet: Some(target.to_string()),
147 message: "Точное соответствие".to_string(),
148 recommendation: None,
149 });
150 }
151
152 pub fn add_approximate(&mut self, category: &str, source: &str, target: &str, note: &str) {
153 self.summary.approximate += 1;
154 self.summary.total_commands += 1;
155 self.items.push(ReportItem {
156 severity: Severity::Warn,
157 category: category.to_string(),
158 source_snippet: source.to_string(),
159 target_snippet: Some(target.to_string()),
160 message: note.to_string(),
161 recommendation: None,
162 });
163 }
164
165 pub fn add_manual(&mut self, category: &str, source: &str, reason: &str, rec: Option<&str>) {
166 self.summary.manual_required += 1;
167 self.summary.total_commands += 1;
168 self.items.push(ReportItem {
169 severity: Severity::Error,
170 category: category.to_string(),
171 source_snippet: source.to_string(),
172 target_snippet: None,
173 message: reason.to_string(),
174 recommendation: rec.map(|s| s.to_string()),
175 });
176 }
177
178 pub fn add_unknown(&mut self, raw: &str, context: &str) {
179 self.summary.unknown += 1;
180 self.summary.total_commands += 1;
181 self.items.push(ReportItem {
182 severity: Severity::Info,
183 category: "unknown".to_string(),
184 source_snippet: raw.to_string(),
185 target_snippet: None,
186 message: format!("Нераспознанная команда в контексте: {}", context),
187 recommendation: None,
188 });
189 }
190
191 pub fn warnings_and_errors(&self) -> Vec<&ReportItem> {
193 self.items
194 .iter()
195 .filter(|i| i.severity != Severity::Ok && i.severity != Severity::Info)
196 .collect()
197 }
198}