use crate::asciigraph::{Bounds, Cell};
use crate::options::{StatAnnotations, DEFAULT_CHAR_SET};
pub(crate) fn render_stat_annotations(
plot: &mut Vec<Vec<Cell>>,
data: &[Vec<f64>],
bounds: &Bounds,
offset: usize,
annotations: &StatAnnotations,
) {
let series_idx = if annotations.series_index < data.len() {
annotations.series_index
} else {
0
};
let finite: Vec<f64> = data[series_idx].iter()
.filter(|v| v.is_finite())
.copied()
.collect();
if finite.is_empty() { return; }
let sum: f64 = finite.iter().sum();
let mean = sum / finite.len() as f64;
let mut sorted = finite.clone();
sorted.sort_by(|a, b| a.partial_cmp(b).unwrap());
let mid = sorted.len() / 2;
let median = if sorted.len() % 2 == 0 {
(sorted[mid - 1] + sorted[mid]) / 2.0
} else {
sorted[mid]
};
let variance = finite.iter()
.map(|v| (v - mean).powi(2))
.sum::<f64>() / finite.len() as f64;
let std_dev = variance.sqrt();
let mut lines_to_draw: Vec<(f64, char, &str)> = Vec::new();
if annotations.show_min {
lines_to_draw.push((bounds.minimum, DEFAULT_CHAR_SET.dash_horizontal, "min"))
}
if annotations.show_max {
lines_to_draw.push((bounds.maximum, DEFAULT_CHAR_SET.dash_horizontal, "max"));
}
if annotations.show_mean {
lines_to_draw.push((mean, DEFAULT_CHAR_SET.double_dash_horizontal, "mean"));
}
if annotations.show_median {
lines_to_draw.push((median, DEFAULT_CHAR_SET.heavy_dash_horizontal, "med"));
}
if annotations.show_std_dev {
lines_to_draw.push((mean + std_dev, DEFAULT_CHAR_SET.dot_horizontal, "+σ"));
lines_to_draw.push((mean - std_dev, DEFAULT_CHAR_SET.dot_horizontal, "-σ"));
}
let mut row_labels: std::collections::HashMap<usize, String> =
std::collections::HashMap::new();
for (value, character, label) in &lines_to_draw {
let scaled = (value * bounds.ratio).round() as isize - bounds.intmin2;
if scaled < 0 || scaled as usize > bounds.rows { continue; }
let row = bounds.rows - scaled as usize;
for col in offset..plot[row].len() {
if plot[row][col].text == " " {
plot[row][col].text = character.to_string();
plot[row][col].color = annotations.color;
}
}
let new_label = format!(" {} {:.2}", label, value);
let entry = row_labels.entry(row).or_insert_with(String::new);
if !entry.is_empty() {
entry.push_str(&format!(", {} {:.2}", label, value));
} else {
*entry = new_label;
}
}
for (row, label_text) in &row_labels {
if let Some(last_cell) = plot[*row].last_mut() {
last_cell.text = label_text.clone();
last_cell.color = annotations.color;
}
}
}