use crate::inspect::smp::special_conditions::*;

pub(in crate::inspect::smp) fn parse_smp_aligned_runtime_rule_band_probe(
    bytes: &[u8],
    file_extension_hint: Option<&str>,
    container_profile: Option<&SmpContainerProfile>,
    special_conditions_probe: Option<&SmpSpecialConditionsProbe>,
) -> Option<SmpAlignedRuntimeRuleBandProbe> {
    special_conditions_probe?;
    if SMP_ALIGNED_RUNTIME_RULE_END_OFFSET > bytes.len() {
        return None;
    }

    let source_kind = match file_extension_hint.unwrap_or("") {
        "gmp" => "map-smp-aligned-runtime-rule-band",
        "gms" => "save-smp-aligned-runtime-rule-band",
        "gmx" => "sandbox-smp-aligned-runtime-rule-band",
        _ => "smp-aligned-runtime-rule-band",
    }
    .to_string();
    let profile_family = container_profile
        .map(|profile| profile.profile_family.clone())
        .unwrap_or_else(|| "unknown".to_string());

    let mut nonzero_lanes = Vec::new();
    for band_index in 0..SMP_ALIGNED_RUNTIME_RULE_DWORD_COUNT {
        let absolute_offset = SPECIAL_CONDITIONS_OFFSET + band_index * 4;
        let value = read_u32_at(bytes, absolute_offset)?;
        if value == 0 {
            continue;
        }
        let lane_kind = if band_index < SPECIAL_CONDITION_COUNT {
            "known-special-condition-dword"
        } else if band_index < SMP_ALIGNED_RUNTIME_RULE_KNOWN_EDITOR_RULE_COUNT {
            "unlabeled-editor-rule-dword"
        } else {
            "trailing-runtime-scalar"
        }
        .to_string();
        let known_label = if band_index < SPECIAL_CONDITION_COUNT {
            Some(
                KNOWN_SPECIAL_CONDITION_DEFINITIONS[band_index]
                    .label
                    .to_string(),
            )
        } else {
            None
        };
        nonzero_lanes.push(SmpAlignedRuntimeRuleBandLane {
            band_index,
            absolute_offset,
            relative_offset: absolute_offset - SPECIAL_CONDITIONS_OFFSET,
            absolute_offset_hex: format!("0x{absolute_offset:04x}"),
            relative_offset_hex: format!("0x{:x}", absolute_offset - SPECIAL_CONDITIONS_OFFSET),
            lane_kind,
            known_label,
            value,
            value_hex: format!("0x{value:08x}"),
            probable_f32_le: probable_normal_f32_string(value),
        });
    }

    let nonzero_band_indices = nonzero_lanes
        .iter()
        .map(|lane| lane.band_index)
        .collect::<Vec<_>>();
    let nonzero_post_window_overlap_band_indices = nonzero_lanes
        .iter()
        .filter(|lane| {
            lane.band_index >= SMP_ALIGNED_RUNTIME_RULE_POST_WINDOW_OVERLAP_START_INDEX
                && lane.band_index
                    < SMP_ALIGNED_RUNTIME_RULE_POST_WINDOW_OVERLAP_START_INDEX
                        + SMP_ALIGNED_RUNTIME_RULE_POST_WINDOW_OVERLAP_DWORD_COUNT
        })
        .map(|lane| lane.band_index)
        .collect::<Vec<_>>();
    let nonzero_post_window_overlap_post_relative_offset_hexes = nonzero_lanes
        .iter()
        .filter(|lane| {
            lane.band_index >= SMP_ALIGNED_RUNTIME_RULE_POST_WINDOW_OVERLAP_START_INDEX
                && lane.band_index
                    < SMP_ALIGNED_RUNTIME_RULE_POST_WINDOW_OVERLAP_START_INDEX
                        + SMP_ALIGNED_RUNTIME_RULE_POST_WINDOW_OVERLAP_DWORD_COUNT
        })
        .map(|lane| {
            format!(
                "0x{:x}",
                (lane.band_index - SMP_ALIGNED_RUNTIME_RULE_POST_WINDOW_OVERLAP_START_INDEX) * 4
            )
        })
        .collect::<Vec<_>>();
    let nonzero_relative_offset_hexes = nonzero_lanes
        .iter()
        .map(|lane| lane.relative_offset_hex.clone())
        .collect::<Vec<_>>();
    let mut evidence = vec![
        format!(
            "fixed `.smp`-aligned runtime-rule band at 0x{SPECIAL_CONDITIONS_OFFSET:04x}..0x{SMP_ALIGNED_RUNTIME_RULE_END_OFFSET:04x}"
        ),
        format!(
            "band spans {} known editor rule dwords plus one trailing scalar",
            SMP_ALIGNED_RUNTIME_RULE_KNOWN_EDITOR_RULE_COUNT
        ),
        "first 36 dwords overlap the older fixed matrix probe rooted at 0x0d64".to_string(),
        format!(
            "trailing band indices {}..{} alias the leading post-sentinel window offsets {}..{}",
            SMP_ALIGNED_RUNTIME_RULE_POST_WINDOW_OVERLAP_START_INDEX,
            SMP_ALIGNED_RUNTIME_RULE_POST_WINDOW_OVERLAP_START_INDEX
                + SMP_ALIGNED_RUNTIME_RULE_POST_WINDOW_OVERLAP_DWORD_COUNT
                - 1,
            "0x00",
            format!(
                "0x{:x}",
                (SMP_ALIGNED_RUNTIME_RULE_POST_WINDOW_OVERLAP_DWORD_COUNT - 1) * 4
            )
        ),
        "band matches the grounded `.smp` save/load copy into `[world+0x4a7f..+0x4b43]`"
            .to_string(),
    ];
    if nonzero_lanes.is_empty() {
        evidence
            .push("all dwords in the aligned runtime-rule band are zero for this file".to_string());
    } else {
        evidence.push(format!(
            "observed {} nonzero lanes at band indices {:?}",
            nonzero_lanes.len(),
            nonzero_band_indices
        ));
        if !nonzero_post_window_overlap_band_indices.is_empty() {
            evidence.push(format!(
                "nonzero overlap lanes mirror post-window offsets {:?}",
                nonzero_post_window_overlap_post_relative_offset_hexes
            ));
        }
    }

    Some(SmpAlignedRuntimeRuleBandProbe {
        profile_family,
        source_kind,
        band_offset: SPECIAL_CONDITIONS_OFFSET,
        band_end_offset: SMP_ALIGNED_RUNTIME_RULE_END_OFFSET,
        band_len: SMP_ALIGNED_RUNTIME_RULE_END_OFFSET - SPECIAL_CONDITIONS_OFFSET,
        band_len_hex: format!(
            "0x{:x}",
            SMP_ALIGNED_RUNTIME_RULE_END_OFFSET - SPECIAL_CONDITIONS_OFFSET
        ),
        dword_count: SMP_ALIGNED_RUNTIME_RULE_DWORD_COUNT,
        known_editor_rule_dword_count: SMP_ALIGNED_RUNTIME_RULE_KNOWN_EDITOR_RULE_COUNT,
        trailing_scalar_index: SMP_ALIGNED_RUNTIME_RULE_DWORD_COUNT - 1,
        trailing_scalar_offset: SPECIAL_CONDITIONS_OFFSET
            + (SMP_ALIGNED_RUNTIME_RULE_DWORD_COUNT - 1) * 4,
        trailing_scalar_offset_hex: format!(
            "0x{:04x}",
            SPECIAL_CONDITIONS_OFFSET + (SMP_ALIGNED_RUNTIME_RULE_DWORD_COUNT - 1) * 4
        ),
        post_window_overlap_start_index: SMP_ALIGNED_RUNTIME_RULE_POST_WINDOW_OVERLAP_START_INDEX,
        post_window_overlap_dword_count: SMP_ALIGNED_RUNTIME_RULE_POST_WINDOW_OVERLAP_DWORD_COUNT,
        post_window_overlap_end_index: SMP_ALIGNED_RUNTIME_RULE_POST_WINDOW_OVERLAP_START_INDEX
            + SMP_ALIGNED_RUNTIME_RULE_POST_WINDOW_OVERLAP_DWORD_COUNT
            - 1,
        post_window_overlap_post_relative_offset_start_hex: "0x0".to_string(),
        post_window_overlap_post_relative_offset_end_hex: format!(
            "0x{:x}",
            (SMP_ALIGNED_RUNTIME_RULE_POST_WINDOW_OVERLAP_DWORD_COUNT - 1) * 4
        ),
        nonzero_post_window_overlap_band_indices,
        nonzero_post_window_overlap_post_relative_offset_hexes,
        nonzero_lane_count: nonzero_lanes.len(),
        nonzero_band_indices,
        nonzero_relative_offset_hexes,
        nonzero_lanes,
        evidence,
    })
}
