use crate::inspect::smp::bundle::{SmpPreamble, SmpPreambleWord, SmpSharedHeader};
use crate::inspect::smp::catalog::offsets::bundle::{
    PREAMBLE_U32_WORD_COUNT, SHARED_SIGNATURE_WORDS_1_TO_7,
};

pub(in crate::inspect::smp) fn parse_preamble(bytes: &[u8]) -> SmpPreamble {
    let byte_len = bytes.len().min(PREAMBLE_U32_WORD_COUNT * 4);
    let words = bytes[..byte_len]
        .chunks_exact(4)
        .enumerate()
        .map(|(index, chunk)| {
            let value_le = u32::from_le_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]);
            SmpPreambleWord {
                index,
                offset: index * 4,
                value_le,
                value_hex: format!("0x{value_le:08x}"),
            }
        })
        .collect::<Vec<_>>();

    SmpPreamble {
        byte_len,
        word_count: words.len(),
        words,
    }
}

pub(in crate::inspect::smp) fn parse_shared_header(bytes: &[u8]) -> Option<SmpSharedHeader> {
    let words = read_preamble_words(bytes)?;
    let shared_signature_words_1_to_7 = words[1..=7].to_vec();
    let payload_window_words_8_to_9 = words[8..=9].to_vec();
    let reserved_words_10_to_14 = words[10..=14].to_vec();
    let final_flag_word = words[15];

    Some(SmpSharedHeader {
        byte_len: PREAMBLE_U32_WORD_COUNT * 4,
        root_kind_word: words[0],
        root_kind_word_hex: format!("0x{:08x}", words[0]),
        primary_family_tag: words[1],
        primary_family_tag_hex: format!("0x{:08x}", words[1]),
        shared_signature_hex_words_1_to_7: shared_signature_words_1_to_7
            .iter()
            .map(|word| format!("0x{word:08x}"))
            .collect(),
        matches_grounded_common_signature: shared_signature_words_1_to_7
            == SHARED_SIGNATURE_WORDS_1_TO_7,
        shared_signature_words_1_to_7,
        payload_window_hex_words_8_to_9: payload_window_words_8_to_9
            .iter()
            .map(|word| format!("0x{word:08x}"))
            .collect(),
        payload_window_words_8_to_9,
        reserved_words_10_to_14_all_zero: reserved_words_10_to_14.iter().all(|word| *word == 0),
        reserved_words_10_to_14,
        final_flag_word,
        final_flag_word_hex: format!("0x{final_flag_word:08x}"),
    })
}

pub(in crate::inspect::smp) fn read_preamble_words(
    bytes: &[u8],
) -> Option<[u32; PREAMBLE_U32_WORD_COUNT]> {
    if bytes.len() < PREAMBLE_U32_WORD_COUNT * 4 {
        return None;
    }

    let mut words = [0u32; PREAMBLE_U32_WORD_COUNT];
    for (index, chunk) in bytes[..PREAMBLE_U32_WORD_COUNT * 4]
        .chunks_exact(4)
        .enumerate()
    {
        words[index] = u32::from_le_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]);
    }
    Some(words)
}
