use crate::inspect::smp::bundle::{
    SmpRuntimePostSpanHeaderCandidate, SmpRuntimePostSpanProbe, SmpRuntimeTrailerBlock,
};
use crate::inspect::smp::common::{find_next_nonzero_offset, read_u32_at, read_u32_window};

pub(in crate::inspect::smp) fn parse_runtime_post_span_probe(
    bytes: &[u8],
    runtime_trailer_block: Option<&SmpRuntimeTrailerBlock>,
) -> Option<SmpRuntimePostSpanProbe> {
    let trailer = runtime_trailer_block?;
    let span_target_offset = trailer.trailer_offset + trailer.length_high_u16 as usize;
    let next_nonzero_offset = find_next_nonzero_offset(bytes, span_target_offset);
    let header_candidates =
        collect_runtime_post_span_header_candidates(bytes, span_target_offset, 0x8000);
    let next_aligned_candidate_offset = header_candidates.first().map(|candidate| candidate.offset);
    let next_aligned_candidate_words = header_candidates
        .first()
        .map(|candidate| candidate.words.clone())
        .unwrap_or_default();
    let grounded_progress_hits =
        find_grounded_progress_high16_hits(bytes, span_target_offset, 0x8000);

    Some(SmpRuntimePostSpanProbe {
        profile_family: trailer.profile_family.clone(),
        span_target_offset,
        next_nonzero_offset,
        next_aligned_candidate_offset,
        next_aligned_candidate_hex_words: next_aligned_candidate_words
            .iter()
            .map(|word| format!("0x{word:08x}"))
            .collect(),
        next_aligned_candidate_words,
        header_candidates,
        grounded_progress_hits,
    })
}

pub(in crate::inspect::smp) fn collect_runtime_post_span_header_candidates(
    bytes: &[u8],
    start: usize,
    search_len: usize,
) -> Vec<SmpRuntimePostSpanHeaderCandidate> {
    let end = bytes.len().min(start + search_len);
    let mut offset = start & !0x3;
    let mut candidates = Vec::new();

    while offset + 16 <= end && candidates.len() < 8 {
        if let Some(candidate) = build_runtime_post_span_header_candidate(bytes, offset) {
            let mut cluster_end = offset + 4;
            while cluster_end + 16 <= end
                && build_runtime_post_span_header_candidate(bytes, cluster_end).is_some()
            {
                cluster_end += 4;
            }
            candidates.push(candidate);
            offset = cluster_end;
        } else {
            offset += 4;
        }
    }

    candidates
}

pub(in crate::inspect::smp) fn build_runtime_post_span_header_candidate(
    bytes: &[u8],
    offset: usize,
) -> Option<SmpRuntimePostSpanHeaderCandidate> {
    let words = read_u32_window(bytes, offset, 4);
    if words.len() < 4 {
        return None;
    }

    let dense_words = words
        .iter()
        .copied()
        .filter(|word| (word & 0xffff) == 0 && (word >> 16) != 0)
        .collect::<Vec<_>>();
    if dense_words.len() < 3 {
        return None;
    }

    let high_u16_words = words
        .iter()
        .map(|word| (word >> 16) as u16)
        .collect::<Vec<_>>();
    let mut grounded_alignments = Vec::new();
    for high in &high_u16_words {
        if let Some(alignment) = classify_runtime_post_span_high16_grounded_alignment(*high) {
            if !grounded_alignments
                .iter()
                .any(|existing| existing == alignment)
            {
                grounded_alignments.push(alignment.to_string());
            }
        }
    }

    Some(SmpRuntimePostSpanHeaderCandidate {
        offset,
        hex_words: words.iter().map(|word| format!("0x{word:08x}")).collect(),
        dense_word_count: dense_words.len(),
        high_hex_words: high_u16_words
            .iter()
            .map(|word| format!("0x{word:04x}"))
            .collect(),
        high_u16_words,
        grounded_alignments,
        words,
    })
}

pub(in crate::inspect::smp) fn classify_runtime_post_span_high16_grounded_alignment(
    high_u16: u16,
) -> Option<&'static str> {
    match high_u16 {
        0x32dc => Some(
            "High-16 value 0x32dc matches the grounded late rehydrate progress id posted during world_entry_transition_and_runtime_bringup.",
        ),
        0x3714 => Some(
            "High-16 value 0x3714 matches the grounded late rehydrate progress id posted during world_entry_transition_and_runtime_bringup.",
        ),
        0x3715 => Some(
            "High-16 value 0x3715 matches the grounded late rehydrate progress id posted during world_entry_transition_and_runtime_bringup.",
        ),
        _ => None,
    }
}

pub(in crate::inspect::smp) fn find_grounded_progress_high16_hits(
    bytes: &[u8],
    start: usize,
    search_len: usize,
) -> Vec<String> {
    let end = bytes.len().min(start + search_len);
    let mut hits = Vec::new();
    let mut offset = start & !0x3;
    while offset + 4 <= end {
        if let Some(word) = read_u32_at(bytes, offset) {
            let high = (word >> 16) as u16;
            if matches!(high, 0x32dc | 0x3714 | 0x3715) {
                hits.push(format!("0x{high:04x}@0x{offset:08x}"));
            }
        }
        offset += 4;
    }
    hits
}

pub(in crate::inspect::smp) fn parse_grounded_progress_hit_offset(
    hits: &[String],
    high_u16: u16,
) -> Option<usize> {
    let needle = format!("0x{high_u16:04x}@0x");
    let hit = hits.iter().find(|hit| hit.starts_with(&needle))?;
    let offset_hex = hit.split("@0x").nth(1)?;
    usize::from_str_radix(offset_hex, 16).ok()
}
