use nodedb_types::Value;
use super::arg::{ArgValues, arg_at};
use super::extremum::{extremum_direction, value_replaces};
use super::helpers::{order_keys_equal, set_window_col};
use super::spec::WindowFuncSpec;
use crate::numeric_sum::{ExactSum, sum_input};
pub(super) fn running_aggregate(
rows: &mut [(String, Value)],
indices: &[usize],
spec: &WindowFuncSpec,
arg_values: &ArgValues,
) -> Result<(), crate::expr::EvalError> {
let len = indices.len();
if len == 0 {
return Ok(());
}
let mut running_sum = ExactSum::new();
let mut running_count = 0u64;
let extremum_dir = extremum_direction(&spec.func_name);
let mut running_extreme: Option<Value> = None;
let mut peer_start = 0usize;
for pos in 0..len {
let i = indices[pos];
let val = arg_at(arg_values, pos);
if sum_input(&val).is_some_and(|n| running_sum.add_value(&n)) {
running_count += 1;
if let Some(want_max) = extremum_dir
&& value_replaces(&val, running_extreme.as_ref(), want_max)
{
running_extreme = Some(val);
}
} else if spec.func_name == "count" && (arg_values.is_none() || !val.is_null()) {
running_count += 1;
}
let is_last_in_group =
pos + 1 == len || !order_keys_equal(rows, i, indices[pos + 1], &spec.order_by)?;
if is_last_in_group {
let result = match spec.func_name.as_str() {
"sum" => running_sum.sum()?,
"count" => Value::from_u64(running_count),
"avg" => running_sum.avg()?,
"min" | "max" => running_extreme.clone().unwrap_or(Value::Null),
"first_value" => arg_at(arg_values, 0),
"last_value" => arg_at(arg_values, pos),
_ => Value::Null,
};
for &peer_idx in &indices[peer_start..=pos] {
set_window_col(&mut rows[peer_idx].1, &spec.alias, result.clone());
}
peer_start = pos + 1;
}
}
Ok(())
}