use renderreport::components::advanced::Grid;
use renderreport::components::{AuditTable, MetricCard, ScoreCard, TableColumn};
use renderreport::prelude::*;
use crate::output::report_model::*;
pub(super) fn build_summary_overview(summary: &SummaryBlock) -> Grid {
let score_card = serde_json::json!({
"type": "score-card",
"data": ScoreCard::new("Accessibility-Score", summary.score)
.with_description(format!("Grade {} — {}", summary.grade, summary.maturity_label))
.with_thresholds(70, 50)
.with_height("100%")
.inverted()
.to_data()
});
let mut grid = Grid::new(2)
.with_item_min_height("132pt")
.add_item(score_card);
for metric in summary.metrics.iter().take(3) {
let mut card = MetricCard::new(&metric.title, &metric.value).with_height("100%");
if let Some(ref color) = metric.accent_color {
card = card.with_accent_color(color);
}
grid = grid.add_item(serde_json::json!({
"type": "metric-card",
"data": card.to_data()
}));
}
grid
}
pub(super) enum WasJetztTunContent {
Table(AuditTable),
Empty(Callout),
}
pub(super) fn build_top_hebel_table(
findings: &FindingsBlock,
total_critical_high: usize,
) -> Option<AuditTable> {
let mut groups: Vec<&FindingGroup> = findings.top_findings.iter().collect();
if groups.is_empty() {
return None;
}
groups.sort_by(|a, b| b.occurrence_count.cmp(&a.occurrence_count));
let mut table = AuditTable::new(vec![
TableColumn::new("Problem").with_width("31%"),
TableColumn::new("Instanzen").with_width("11%"),
TableColumn::new("Elemente").with_width("11%"),
TableColumn::new("Anteil").with_width("12%"),
TableColumn::new("Wirkung").with_width("35%"),
]);
for group in groups.iter().take(5) {
let share = if total_critical_high > 0 {
let pct = group.occurrence_count * 100 / total_critical_high;
format!("{}%", pct.min(99))
} else {
"—".to_string()
};
let impact = &group.user_impact;
table = table.add_row(vec![
group.title.clone(),
group.occurrence_count.to_string(),
group.affected_elements.to_string(),
share,
if impact.is_empty() {
group.recommendation.clone()
} else {
impact.clone()
},
]);
}
Some(table)
}
pub(super) fn build_was_jetzt_tun_table(vm: &ReportViewModel) -> WasJetztTunContent {
let all_items: Vec<&RoadmapItemData> = vm
.actions
.roadmap_columns
.iter()
.flat_map(|col| col.items.iter())
.collect();
let mut sorted: Vec<&RoadmapItemData> = all_items;
sorted.sort_by_key(|i| {
let ep = i.execution_priority.as_str();
if ep.contains("Direkt") || ep.contains("Sofort") {
0u8
} else if ep.contains("Nächstes") || ep.contains("Wichtig") {
1
} else {
2
}
});
let selected: Vec<&RoadmapItemData> = sorted.into_iter().take(5).collect();
if selected.is_empty() {
return WasJetztTunContent::Empty(
Callout::success(
"Keine priorisierten Maßnahmen identifiziert — Qualität sichern und regelmäßige Audits einplanen.",
)
.with_title("Aktuell keine offenen Maßnahmen"),
);
}
let table_title = match selected.len() {
1 => "Maßnahmenplan (1 Maßnahme) — Executive View".to_string(),
n => format!("Maßnahmenplan ({n} Maßnahmen) — Executive View"),
};
let mut table = AuditTable::new(vec![
TableColumn::new("Maßnahme"),
TableColumn::new("Nutzer-Effekt"),
TableColumn::new("Risiko"),
TableColumn::new("Rolle / Aufwand"),
])
.with_title(&table_title);
for item in selected {
table = table.add_row(vec![
item.action.clone(),
item.user_effect.clone(),
item.risk_effect.clone(),
format!("{} / {}", item.role, item.effort),
]);
}
WasJetztTunContent::Table(table)
}