use super::embedded_names::*;
use super::evidence::*;
use super::live_entry_prelude::*;
use super::name_prelude::*;
use super::payload_envelope::*;
use super::prefix_patterns::*;
use crate::inspect::smp::structures::*;

pub(in crate::inspect::smp) fn parse_save_placed_structure_dynamic_side_buffer_probe(
    bytes: &[u8],
    file_extension_hint: Option<&str>,
    container_profile: Option<&SmpContainerProfile>,
) -> Option<SmpSavePlacedStructureDynamicSideBufferProbe> {
    if file_extension_hint != Some("gms") {
        return None;
    }
    let profile = container_profile?;
    if !matches!(
        profile.profile_family.as_str(),
        "rt3-classic-save-container-v1"
            | "rt3-105-save-container-v1"
            | "rt3-105-scenario-save-container-v1"
            | "rt3-105-alt-save-container-v1"
    ) {
        return None;
    }

    let metadata_offsets = find_u32_le_offsets(bytes, 0x000038a5);
    let records_offsets = find_u32_le_offsets(bytes, 0x000038a6);
    let close_offsets = find_u32_le_offsets(bytes, 0x000038a7);
    for metadata_tag_offset in metadata_offsets {
        let Some(records_tag_offset) = records_offsets
            .iter()
            .copied()
            .find(|offset| *offset > metadata_tag_offset)
        else {
            continue;
        };
        let Some(close_tag_offset) = close_offsets
            .iter()
            .copied()
            .find(|offset| *offset > records_tag_offset)
        else {
            continue;
        };
        let Some(payload) = bytes.get(metadata_tag_offset + 4..records_tag_offset) else {
            continue;
        };
        if payload.len() < INDEXED_COLLECTION_SERIALIZED_HEADER_LEN {
            continue;
        }
        let Some(header_words) = (0..INDEXED_COLLECTION_SERIALIZED_HEADER_DWORD_COUNT)
            .map(|index| read_u32_at(payload, index * 4))
            .collect::<Option<Vec<_>>>()
        else {
            continue;
        };
        let Some(header_words): Option<[u32; INDEXED_COLLECTION_SERIALIZED_HEADER_DWORD_COUNT]> =
            header_words.try_into().ok()
        else {
            continue;
        };
        let summary = IndexedCollectionHeaderSummary {
            metadata_tag_offset,
            records_tag_offset,
            close_tag_offset,
            direct_collection_flag: header_words[0],
            direct_record_stride: header_words[1],
            live_id_bound: header_words[4],
            live_record_count: header_words[5],
            header_words,
        };
        if !(summary.direct_collection_flag == 0
            && summary.direct_record_stride == 0x06
            && summary.header_words.get(2) == Some(&1000)
            && summary.header_words.get(3) == Some(&500)
            && summary.header_words.get(6) == Some(&0)
            && summary.header_words.get(7) == Some(&1)
            && summary.live_id_bound >= 0x100
            && summary.live_id_bound <= 0x1000
            && summary.live_record_count >= 0x100
            && summary.live_record_count <= summary.live_id_bound)
        {
            continue;
        }
        let Some(records_payload) = bytes.get(records_tag_offset + 4..close_tag_offset) else {
            continue;
        };
        let embedded_name_tag_offsets =
            find_u16_le_offsets(records_payload, SAVE_REGION_RECORD_NAME_TAG);
        let Some(&first_embedded_name_tag_relative_offset) = embedded_name_tag_offsets.first()
        else {
            continue;
        };
        let Some(prefix_payload) = records_payload.get(..first_embedded_name_tag_relative_offset)
        else {
            continue;
        };
        if prefix_payload.len() < 7 {
            continue;
        }
        let Some(FirstRecordNamePrelude {
            owner_shared_dword,
            owner_shared_dword_relative_offset,
            first_record_child_count_after_owner_shared,
            first_record_saved_primary_child_byte_after_owner_shared,
            first_record_first_name_tag_relative_offset_after_owner_shared,
            prefix_leading_dword,
            prefix_trailing_word,
            prefix_separator_byte,
            first_embedded_primary_name,
            first_embedded_secondary_name,
            first_embedded_tertiary_name,
        }) = parse_first_record_name_prelude(
            records_payload,
            first_embedded_name_tag_relative_offset,
        )
        else {
            continue;
        };
        let embedded_name_rows =
            parse_embedded_name_rows(records_payload, &embedded_name_tag_offsets);
        let policy_tag_offsets =
            find_u16_le_offsets(records_payload, SAVE_REGION_RECORD_POLICY_TAG);
        let profile_tag_offsets =
            find_u16_le_offsets(records_payload, SAVE_REGION_RECORD_PROFILE_TAG);
        let payload_envelope_rows = build_payload_envelope_rows(
            records_payload,
            &embedded_name_tag_offsets,
            &embedded_name_rows,
            &policy_tag_offsets,
            &profile_tag_offsets,
        );
        let embedded_name_row_samples = embedded_name_rows
            .iter()
            .take(8)
            .enumerate()
            .map(
                |(sample_index, row)| SmpSavePlacedStructureDynamicSideBufferSampleEntry {
                    sample_index,
                    name_tag_relative_offset: row.name_tag_relative_offset,
                    prefix_leading_dword: row.prefix_leading_dword,
                    prefix_leading_dword_hex: format!("0x{:08x}", row.prefix_leading_dword),
                    prefix_trailing_word: row.prefix_trailing_word,
                    prefix_trailing_word_hex: format!("0x{:04x}", row.prefix_trailing_word),
                    prefix_separator_byte: row.prefix_separator_byte,
                    prefix_separator_byte_hex: format!("0x{:02x}", row.prefix_separator_byte),
                    primary_name: row.primary_name.clone(),
                    secondary_name: row.secondary_name.clone(),
                    tertiary_name: row.tertiary_name.clone(),
                },
            )
            .collect::<Vec<_>>();
        let PrefixAndNamePairSummary {
            compact_prefix_pattern_summaries,
            name_pair_summaries,
            prefix_leading_dword_matching_embedded_profile_tag_count,
        } = summarize_prefix_and_name_pairs(&embedded_name_rows);
        let 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,
        } = summarize_payload_envelope_spans(&payload_envelope_rows);
        let short_profile_flag_pair_summary =
            build_short_profile_flag_pair_summary(&payload_envelope_rows);
        let fixed_policy_summary = build_fixed_policy_summary(
            records_payload,
            &payload_envelope_rows,
            &embedded_name_rows,
        );
        let name_prelude_candidate_summary = build_name_prelude_candidate_summary(
            records_payload,
            &payload_envelope_rows,
            &embedded_name_rows,
        );
        let dominant_profile_span_class_summary = build_dominant_profile_span_class_summary(
            records_payload,
            &payload_envelope_rows,
            &embedded_name_rows,
            dominant_profile_chunk_len,
        );
        let payload_envelope_summary = Some(
            SmpSavePlacedStructureDynamicSideBufferPayloadEnvelopeSummary {
                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_policy_chunk_len.map(|(len, _)| len),
                dominant_policy_chunk_len_count: dominant_policy_chunk_len
                    .map(|(_, count)| count)
                    .unwrap_or_default(),
                dominant_profile_chunk_len: dominant_profile_chunk_len.map(|(len, _)| len),
                dominant_profile_chunk_len_count: dominant_profile_chunk_len
                    .map(|(_, count)| count)
                    .unwrap_or_default(),
                short_profile_flag_pair_summary: short_profile_flag_pair_summary.clone(),
                fixed_policy_summary: fixed_policy_summary.clone(),
                name_prelude_candidate_summary: name_prelude_candidate_summary.clone(),
                dominant_profile_span_class_summary: dominant_profile_span_class_summary.clone(),
                sample_rows: payload_envelope_rows
                    .iter()
                    .take(8)
                    .enumerate()
                    .map(|(sample_index, row)| {
                        SmpSavePlacedStructureDynamicSideBufferPayloadEnvelopeSample {
                            sample_index,
                            name_tag_relative_offset: row.name_tag_relative_offset,
                            primary_name: row.primary_name.clone(),
                            secondary_name: row.secondary_name.clone(),
                            name_payload_end_relative_offset: row.name_payload_end_relative_offset,
                            policy_tag_relative_offset: row.policy_tag_relative_offset,
                            profile_tag_relative_offset: row.profile_tag_relative_offset,
                            next_name_tag_relative_offset: row.next_name_tag_relative_offset,
                            name_to_policy_gap_len: row.name_to_policy_gap_len,
                            policy_chunk_len: row.policy_chunk_len,
                            profile_chunk_len_to_next_name_or_end: row
                                .profile_chunk_len_to_next_name_or_end,
                        }
                    })
                    .collect(),
            },
        );
        let live_entry_prelude_summary = build_live_entry_prelude_summary(
            payload,
            records_payload,
            summary.live_id_bound,
            summary.live_record_count,
        );
        let unique_embedded_name_pair_count = name_pair_summaries.len();
        let dominant_compact_prefix_pattern = compact_prefix_pattern_summaries.first().cloned();
        let decoded_embedded_name_row_count = embedded_name_rows
            .iter()
            .filter(|row| row.primary_name.is_some() && row.secondary_name.is_some())
            .count();
        let decoded_embedded_name_row_with_tertiary_name_count = embedded_name_rows
            .iter()
            .filter(|row| {
                row.primary_name.is_some()
                    && row.secondary_name.is_some()
                    && row.tertiary_name.is_some()
            })
            .count();
        let first_record_saved_primary_child_byte_after_owner_shared_hex =
            first_record_saved_primary_child_byte_after_owner_shared
                .map(|value| format!("0x{value:02x}"));
        return Some(SmpSavePlacedStructureDynamicSideBufferProbe {
            profile_family: profile.profile_family.clone(),
            source_kind: "save-placed-structure-dynamic-side-buffer-records".to_string(),
            semantic_family: "scenario-save-placed-structure-dynamic-side-buffer-records"
                .to_string(),
            metadata_tag_offset,
            records_tag_offset,
            close_tag_offset,
            records_span_len: close_tag_offset.saturating_sub(records_tag_offset + 4),
            direct_record_stride: summary.direct_record_stride,
            direct_record_stride_hex: format!("0x{:08x}", summary.direct_record_stride),
            live_id_bound: summary.live_id_bound,
            live_id_bound_hex: format!("0x{:08x}", summary.live_id_bound),
            live_record_count: summary.live_record_count,
            live_record_count_hex: format!("0x{:08x}", summary.live_record_count),
            owner_shared_dword,
            owner_shared_dword_hex: format!("0x{owner_shared_dword:08x}"),
            owner_shared_dword_relative_offset,
            owner_shared_dword_matches_first_compact_prefix_leading_dword: owner_shared_dword
                == prefix_leading_dword,
            first_record_child_count_after_owner_shared,
            first_record_child_count_after_owner_shared_hex:
                first_record_child_count_after_owner_shared.map(|value| format!("0x{value:04x}")),
            first_record_saved_primary_child_byte_after_owner_shared,
            first_record_saved_primary_child_byte_after_owner_shared_hex:
                first_record_saved_primary_child_byte_after_owner_shared
                    .map(|value| format!("0x{value:02x}")),
            first_record_first_name_tag_relative_offset_after_owner_shared,
            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}"),
            first_embedded_name_tag_relative_offset,
            embedded_name_tag_count: embedded_name_tag_offsets.len(),
            decoded_embedded_name_row_count,
            decoded_embedded_name_row_with_tertiary_name_count,
            unique_compact_prefix_pattern_count: compact_prefix_pattern_summaries.len(),
            prefix_leading_dword_matching_embedded_profile_tag_count,
            unique_embedded_name_pair_count,
            first_embedded_primary_name: Some(first_embedded_primary_name.clone()),
            first_embedded_secondary_name: Some(first_embedded_secondary_name.clone()),
            first_embedded_tertiary_name: first_embedded_tertiary_name.clone(),
            embedded_name_row_samples,
            compact_prefix_pattern_summaries,
            name_pair_summaries,
            payload_envelope_summary,
            live_entry_prelude_summary: live_entry_prelude_summary.clone(),
            evidence: build_dynamic_side_buffer_evidence(DynamicSideBufferEvidenceInputs {
                owner_shared_dword,
                first_record_child_count_after_owner_shared,
                first_record_saved_primary_child_byte_after_owner_shared_hex:
                    first_record_saved_primary_child_byte_after_owner_shared_hex.as_deref(),
                first_record_first_name_tag_relative_offset_after_owner_shared,
                first_embedded_primary_name: &first_embedded_primary_name,
                first_embedded_secondary_name: &first_embedded_secondary_name,
                first_embedded_tertiary_name: first_embedded_tertiary_name.as_ref(),
                embedded_name_tag_count: embedded_name_tag_offsets.len(),
                embedded_name_row_count: embedded_name_rows.len(),
                prefix_leading_dword_matching_embedded_profile_tag_count,
                decoded_embedded_name_row_count,
                unique_embedded_name_pair_count,
                decoded_embedded_name_row_with_tertiary_name_count,
                row_count_with_complete_0x55f1_0x55f2_0x55f3_envelope,
                row_count_missing_policy_tag_before_next_name,
                row_count_missing_profile_tag_after_policy,
                dominant_policy_chunk_len,
                dominant_profile_chunk_len,
                short_profile_flag_pair_summary: short_profile_flag_pair_summary.as_ref(),
                fixed_policy_summary: fixed_policy_summary.as_ref(),
                live_entry_prelude_summary: live_entry_prelude_summary.as_ref(),
                dominant_compact_prefix_pattern: dominant_compact_prefix_pattern.as_ref(),
            }),
        });
    }
    None
}
