use crate::inspect::smp::profiles::*;

pub(in crate::inspect::smp) fn parse_classic_rehydrate_profile_probe(
    bytes: &[u8],
    runtime_post_span_probe: Option<&SmpRuntimePostSpanProbe>,
) -> Option<SmpClassicRehydrateProfileProbe> {
    let post_span = runtime_post_span_probe?;
    if post_span.profile_family != "rt3-classic-save-container-v1" {
        return None;
    }

    let progress_32dc_offset =
        parse_grounded_progress_hit_offset(&post_span.grounded_progress_hits, 0x32dc)?;
    let progress_3714_offset =
        parse_grounded_progress_hit_offset(&post_span.grounded_progress_hits, 0x3714)?;
    let progress_3715_offset =
        parse_grounded_progress_hit_offset(&post_span.grounded_progress_hits, 0x3715)?;
    let packed_profile_offset = progress_3714_offset + 4;
    let packed_profile_len = progress_3715_offset.checked_sub(packed_profile_offset)?;
    if packed_profile_len != 0x108 {
        return None;
    }

    let ascii_runs =
        collect_ascii_previews_in_range(bytes, packed_profile_offset, progress_3715_offset, 4);
    let packed_profile_block =
        parse_classic_packed_profile_block(bytes, packed_profile_offset, packed_profile_len)?;

    Some(SmpClassicRehydrateProfileProbe {
        profile_family: post_span.profile_family.clone(),
        progress_32dc_offset,
        progress_3714_offset,
        progress_3715_offset,
        packed_profile_offset,
        packed_profile_len,
        packed_profile_len_hex: format!("0x{packed_profile_len:03x}"),
        packed_profile_block,
        ascii_runs,
    })
}

pub(in crate::inspect::smp) fn parse_classic_packed_profile_block(
    bytes: &[u8],
    packed_profile_offset: usize,
    packed_profile_len: usize,
) -> Option<SmpClassicPackedProfileBlock> {
    let block_end = packed_profile_offset.checked_add(packed_profile_len)?;
    if block_end > bytes.len() || packed_profile_len != 0x108 {
        return None;
    }

    let leading_word_0 = read_u32_at(bytes, packed_profile_offset)?;
    let trailing_zero_word_count_after_leading_word = (1..4)
        .take_while(|index| {
            read_u32_at(bytes, packed_profile_offset + (index * 4)).is_some_and(|word| word == 0)
        })
        .count();
    let map_path_offset = 0x13;
    let display_name_offset = 0x46;
    let stable_nonzero_word_offsets = [0x00usize, 0x10, 0x78, 0x7c, 0x84, 0x88];
    let stable_nonzero_words = stable_nonzero_word_offsets
        .iter()
        .filter_map(|relative_offset| {
            let value = read_u32_at(bytes, packed_profile_offset + relative_offset)?;
            if value == 0 {
                return None;
            }

            Some(SmpPackedProfileWordLane {
                relative_offset: *relative_offset,
                relative_offset_hex: format!("0x{relative_offset:02x}"),
                value,
                value_hex: format!("0x{value:08x}"),
            })
        })
        .collect::<Vec<_>>();

    Some(SmpClassicPackedProfileBlock {
        relative_len: packed_profile_len,
        relative_len_hex: format!("0x{packed_profile_len:03x}"),
        leading_word_0,
        leading_word_0_hex: format!("0x{leading_word_0:08x}"),
        trailing_zero_word_count_after_leading_word,
        map_path_offset,
        map_path: read_c_string_in_range(bytes, packed_profile_offset + map_path_offset, block_end),
        display_name_offset,
        display_name: read_c_string_in_range(
            bytes,
            packed_profile_offset + display_name_offset,
            block_end,
        ),
        profile_byte_0x77: bytes[packed_profile_offset + 0x77],
        profile_byte_0x77_hex: format!("0x{:02x}", bytes[packed_profile_offset + 0x77]),
        profile_byte_0x82: bytes[packed_profile_offset + 0x82],
        profile_byte_0x82_hex: format!("0x{:02x}", bytes[packed_profile_offset + 0x82]),
        profile_byte_0x97: bytes[packed_profile_offset + 0x97],
        profile_byte_0x97_hex: format!("0x{:02x}", bytes[packed_profile_offset + 0x97]),
        profile_byte_0xc5: bytes[packed_profile_offset + 0xc5],
        profile_byte_0xc5_hex: format!("0x{:02x}", bytes[packed_profile_offset + 0xc5]),
        stable_nonzero_words,
    })
}
