use super::super::super::super::*;
use super::super::super::mode_family::classify_side_buffer_mode_family;
use super::super::candidate_rows::NamePreludeCandidateRow;
use std::collections::BTreeMap;

pub(in crate::inspect::smp) fn build_profile_span_correlations(
    name_prelude_candidate_rows: &[NamePreludeCandidateRow],
) -> Vec<SmpSavePlacedStructureDynamicSideBufferNamePreludeProfileSpanCorrelation> {
    let mut name_prelude_profile_span_groups = BTreeMap::<
        usize,
        Vec<(usize, Option<String>, Option<String>, u32, u16, u8, u16, u8)>,
    >::new();
    for (
        name_tag_relative_offset,
        primary_name,
        secondary_name,
        prefix_leading_dword,
        prefix_trailing_word,
        prefix_separator_byte,
        child_count_candidate,
        saved_primary_child_byte_candidate,
        previous_span,
        _previous_short_profile_flag_pair,
    ) in name_prelude_candidate_rows
    {
        if let Some(previous_span) = previous_span {
            name_prelude_profile_span_groups
                .entry(*previous_span)
                .or_default()
                .push((
                    *name_tag_relative_offset,
                    primary_name.clone(),
                    secondary_name.clone(),
                    *prefix_leading_dword,
                    *prefix_trailing_word,
                    *prefix_separator_byte,
                    *child_count_candidate,
                    *saved_primary_child_byte_candidate,
                ));
        }
    }
    name_prelude_profile_span_groups
        .into_iter()
        .map(|(previous_profile_chunk_len_to_next_name_or_end, rows)| {
            let mut pattern_counts = BTreeMap::<(u16, u8), usize>::new();
            let mut child_count_counts = BTreeMap::<u16, usize>::new();
            let mut saved_primary_counts = BTreeMap::<u8, usize>::new();
            let mut mode_family_counts = BTreeMap::<String, usize>::new();
            let mut prefix_counts = BTreeMap::<(u32, u16, u8), usize>::new();
            for (
                _name_tag_relative_offset,
                primary_name,
                secondary_name,
                prefix_leading_dword,
                prefix_trailing_word,
                prefix_separator_byte,
                child_count_candidate,
                saved_primary_child_byte_candidate,
            ) in &rows
            {
                *pattern_counts
                    .entry((*child_count_candidate, *saved_primary_child_byte_candidate))
                    .or_default() += 1;
                *child_count_counts.entry(*child_count_candidate).or_default() += 1;
                *saved_primary_counts.entry(*saved_primary_child_byte_candidate).or_default() += 1;
                *prefix_counts
                    .entry((*prefix_leading_dword, *prefix_trailing_word, *prefix_separator_byte))
                    .or_default() += 1;
                *mode_family_counts
                    .entry(
                        classify_side_buffer_mode_family(
                            primary_name.as_deref(),
                            secondary_name.as_deref(),
                        )
                        .to_string(),
                    )
                    .or_default() += 1;
            }
            let dominant_pattern = pattern_counts
                .iter()
                .max_by(|(left_key, left_count), (right_key, right_count)| {
                    left_count
                        .cmp(right_count)
                        .then_with(|| right_key.cmp(left_key))
                })
                .map(|((child_count_candidate, saved_primary_child_byte_candidate), count)| {
                    SmpSavePlacedStructureDynamicSideBufferNamePreludeCandidatePattern {
                        child_count_candidate: *child_count_candidate,
                        child_count_candidate_hex: format!("0x{child_count_candidate:04x}"),
                        saved_primary_child_byte_candidate: *saved_primary_child_byte_candidate,
                        saved_primary_child_byte_candidate_hex: format!(
                            "0x{saved_primary_child_byte_candidate:02x}"
                        ),
                        count: *count,
                    }
                });
            let dominant_child_count = child_count_counts
                .iter()
                .max_by(|(left_key, left_count), (right_key, right_count)| {
                    left_count
                        .cmp(right_count)
                        .then_with(|| right_key.cmp(left_key))
                })
                .map(|(value, count)| (*value, *count));
            let dominant_saved_primary = saved_primary_counts
                .iter()
                .max_by(|(left_key, left_count), (right_key, right_count)| {
                    left_count
                        .cmp(right_count)
                        .then_with(|| right_key.cmp(left_key))
                })
                .map(|(value, count)| (*value, *count));
            let dominant_mode_family = mode_family_counts
                .iter()
                .max_by(|(left_key, left_count), (right_key, right_count)| {
                    left_count
                        .cmp(right_count)
                        .then_with(|| right_key.cmp(left_key))
                })
                .map(|(mode_family, count)| (mode_family.clone(), *count));
            SmpSavePlacedStructureDynamicSideBufferNamePreludeProfileSpanCorrelation {
                previous_profile_chunk_len_to_next_name_or_end,
                row_count: rows.len(),
                dominant_child_count_candidate: dominant_child_count.map(|(value, _)| value),
                dominant_child_count_candidate_count: dominant_child_count
                    .map(|(_, count)| count)
                    .unwrap_or_default(),
                dominant_saved_primary_child_byte_candidate: dominant_saved_primary
                    .map(|(value, _)| value),
                dominant_saved_primary_child_byte_candidate_hex: dominant_saved_primary
                    .map(|(value, _)| format!("0x{value:02x}")),
                dominant_saved_primary_child_byte_candidate_count: dominant_saved_primary
                    .map(|(_, count)| count)
                    .unwrap_or_default(),
                dominant_candidate_pattern: dominant_pattern,
                dominant_mode_family: dominant_mode_family
                    .as_ref()
                    .map(|(mode_family, _)| mode_family.clone()),
                dominant_mode_family_count: dominant_mode_family
                    .map(|(_, count)| count)
                    .unwrap_or_default(),
                mode_family_counts: mode_family_counts
                    .into_iter()
                    .map(|(mode_family, count)| {
                        SmpSavePlacedStructureDynamicSideBufferNamePreludeModeFamilyCount {
                            mode_family,
                            count,
                        }
                    })
                    .collect(),
                compact_prefix_pattern_summaries: prefix_counts
                    .into_iter()
                    .map(
                        |((prefix_leading_dword, prefix_trailing_word, prefix_separator_byte), count)| {
                            SmpSavePlacedStructureDynamicSideBufferNamePreludeProfileSpanPrefixSummary {
                                prefix_leading_dword,
                                prefix_leading_dword_hex: format!("0x{prefix_leading_dword:08x}"),
                                prefix_trailing_word,
                                prefix_trailing_word_hex: format!("0x{prefix_trailing_word:04x}"),
                                prefix_separator_byte,
                                prefix_separator_byte_hex: format!("0x{prefix_separator_byte:02x}"),
                                count,
                            }
                        },
                    )
                    .collect(),
                sample_rows: rows
                    .iter()
                    .take(8)
                    .enumerate()
                    .map(
                        |(
                            sample_index,
                            (
                                name_tag_relative_offset,
                                primary_name,
                                secondary_name,
                                prefix_leading_dword,
                                prefix_trailing_word,
                                prefix_separator_byte,
                                child_count_candidate,
                                saved_primary_child_byte_candidate,
                            ),
                        )| {
                            SmpSavePlacedStructureDynamicSideBufferNamePreludeProfileSpanSample {
                                sample_index,
                                name_tag_relative_offset: *name_tag_relative_offset,
                                primary_name: primary_name.clone(),
                                secondary_name: secondary_name.clone(),
                                prefix_leading_dword: *prefix_leading_dword,
                                prefix_leading_dword_hex: format!(
                                    "0x{prefix_leading_dword:08x}"
                                ),
                                prefix_trailing_word: *prefix_trailing_word,
                                prefix_trailing_word_hex: format!(
                                    "0x{prefix_trailing_word:04x}"
                                ),
                                prefix_separator_byte: *prefix_separator_byte,
                                prefix_separator_byte_hex: format!(
                                    "0x{prefix_separator_byte:02x}"
                                ),
                                child_count_candidate: *child_count_candidate,
                                child_count_candidate_hex: format!(
                                    "0x{child_count_candidate:04x}"
                                ),
                                saved_primary_child_byte_candidate:
                                    *saved_primary_child_byte_candidate,
                                saved_primary_child_byte_candidate_hex: format!(
                                    "0x{saved_primary_child_byte_candidate:02x}"
                                ),
                            }
                        },
                    )
                    .collect(),
            }
        })
        .take(8)
        .collect::<Vec<_>>()
}
