use super::rows::PayloadEnvelopeRow;
use std::collections::BTreeMap;

pub(crate) struct PayloadEnvelopeSpanStats {
    pub(in crate::inspect::smp) row_count_with_policy_tag_before_next_name: usize,
    pub(in crate::inspect::smp) row_count_with_complete_0x55f1_0x55f2_0x55f3_envelope: usize,
    pub(in crate::inspect::smp) row_count_missing_policy_tag_before_next_name: usize,
    pub(in crate::inspect::smp) row_count_missing_profile_tag_after_policy: usize,
    pub(in crate::inspect::smp) unique_policy_chunk_lens: Vec<usize>,
    pub(in crate::inspect::smp) unique_profile_chunk_lens: Vec<usize>,
    pub(in crate::inspect::smp) dominant_policy_chunk_len: Option<(usize, usize)>,
    pub(in crate::inspect::smp) dominant_profile_chunk_len: Option<(usize, usize)>,
}

pub(crate) fn summarize_payload_envelope_spans(
    payload_envelope_rows: &[PayloadEnvelopeRow],
) -> PayloadEnvelopeSpanStats {
    let row_count_with_policy_tag_before_next_name = payload_envelope_rows
        .iter()
        .filter(|row| row.policy_tag_relative_offset.is_some())
        .count();
    let row_count_with_complete_0x55f1_0x55f2_0x55f3_envelope = payload_envelope_rows
        .iter()
        .filter(|row| {
            row.policy_tag_relative_offset.is_some() && row.profile_tag_relative_offset.is_some()
        })
        .count();
    let row_count_missing_policy_tag_before_next_name = payload_envelope_rows
        .iter()
        .filter(|row| row.policy_tag_relative_offset.is_none())
        .count();
    let row_count_missing_profile_tag_after_policy = payload_envelope_rows
        .iter()
        .filter(|row| {
            row.policy_tag_relative_offset.is_some() && row.profile_tag_relative_offset.is_none()
        })
        .count();
    let mut policy_chunk_len_counts = BTreeMap::<usize, usize>::new();
    let mut profile_chunk_len_counts = BTreeMap::<usize, usize>::new();
    for row in payload_envelope_rows {
        if let Some(policy_chunk_len) = row.policy_chunk_len {
            *policy_chunk_len_counts.entry(policy_chunk_len).or_default() += 1;
        }
        if let Some(profile_chunk_len_to_next_name_or_end) =
            row.profile_chunk_len_to_next_name_or_end
        {
            *profile_chunk_len_counts
                .entry(profile_chunk_len_to_next_name_or_end)
                .or_default() += 1;
        }
    }
    let unique_policy_chunk_lens = policy_chunk_len_counts.keys().copied().collect::<Vec<_>>();
    let unique_profile_chunk_lens = profile_chunk_len_counts.keys().copied().collect::<Vec<_>>();
    let dominant_policy_chunk_len = policy_chunk_len_counts
        .iter()
        .max_by(|(left_len, left_count), (right_len, right_count)| {
            left_count
                .cmp(right_count)
                .then_with(|| right_len.cmp(left_len))
        })
        .map(|(len, count)| (*len, *count));
    let dominant_profile_chunk_len = profile_chunk_len_counts
        .iter()
        .max_by(|(left_len, left_count), (right_len, right_count)| {
            left_count
                .cmp(right_count)
                .then_with(|| right_len.cmp(left_len))
        })
        .map(|(len, count)| (*len, *count));
    PayloadEnvelopeSpanStats {
        row_count_with_policy_tag_before_next_name,
        row_count_with_complete_0x55f1_0x55f2_0x55f3_envelope,
        row_count_missing_policy_tag_before_next_name,
        row_count_missing_profile_tag_after_policy,
        unique_policy_chunk_lens,
        unique_profile_chunk_lens,
        dominant_policy_chunk_len,
        dominant_profile_chunk_len,
    }
}
