use crate::inspect::smp::events::*;

pub(in crate::inspect::smp) fn parse_real_grouped_effect_row_summary(
    row_bytes: &[u8],
    group_index: usize,
    row_index: usize,
    locomotive_name: Option<String>,
) -> Option<SmpLoadedPackedEventGroupedEffectRowSummary> {
    let descriptor_id = read_u32_at(row_bytes, 0)?;
    let raw_scalar_value = read_u32_at(row_bytes, 4)? as i32;
    let opcode = read_u8_at(row_bytes, 8)?;
    let value_byte_0x09 = read_u8_at(row_bytes, 9)?;
    let value_dword_0x0d = read_u32_at(row_bytes, 0x0d)?;
    let value_byte_0x11 = read_u8_at(row_bytes, 0x11)?;
    let value_byte_0x12 = read_u8_at(row_bytes, 0x12)?;
    let value_word_0x14 = read_u16_at(row_bytes, 0x14)?;
    let value_word_0x16 = read_u16_at(row_bytes, 0x16)?;
    let descriptor_metadata = real_grouped_effect_descriptor_metadata(descriptor_id);
    let mut row_shape = classify_real_grouped_effect_row_shape(
        opcode,
        raw_scalar_value,
        value_byte_0x11,
        value_byte_0x12,
        value_word_0x14,
        value_word_0x16,
    )
    .to_string();
    let mut semantic_family = classify_real_grouped_effect_semantic_family(
        opcode,
        raw_scalar_value,
        value_byte_0x11,
        value_byte_0x12,
        value_word_0x14,
        value_word_0x16,
    )
    .to_string();
    if descriptor_metadata.is_some_and(|metadata| {
        matches!(
            metadata.parameter_family,
            "special_condition_scalar" | "candidate_availability_scalar"
        ) && opcode == 3
            && value_byte_0x11 == 0
            && value_byte_0x12 == 0
            && value_word_0x14 == 0
            && value_word_0x16 == 0
    }) {
        row_shape = "scalar_assignment".to_string();
        semantic_family = "scalar_assignment".to_string();
    }
    if descriptor_metadata
        .is_some_and(|metadata| metadata.parameter_family == "world_building_spawn")
    {
        row_shape = "building_spawn_batch".to_string();
        semantic_family = "building_spawn_batch".to_string();
    }

    let mut notes = Vec::new();
    if locomotive_name.is_some() {
        notes.push("grouped effect row carries locomotive-name side string".to_string());
    }
    if let Some(metadata) = descriptor_metadata {
        if metadata.runtime_status != RealGroupedEffectRuntimeStatus::Executable {
            notes.push(format!(
                "descriptor is recovered in the checked-in effect table as {} parity",
                real_grouped_effect_runtime_status_name(metadata.runtime_status)
            ));
        }
    } else {
        notes.push("descriptor id not yet recovered in the checked-in effect table".to_string());
    }
    if let Some(loco_id) = recovered_locomotive_availability_loco_id(descriptor_id) {
        notes.push(format!(
            "locomotive availability descriptor maps to live locomotive id {loco_id}"
        ));
    }
    if let Some(loco_id) = recovered_locomotive_cost_loco_id(descriptor_id) {
        notes.push(format!(
            "locomotive cost descriptor maps to live locomotive id {loco_id}"
        ));
    }
    if let Some(cargo_slot) = recovered_cargo_production_slot(descriptor_id) {
        notes.push(format!(
            "cargo-production descriptor maps to world production slot {cargo_slot}"
        ));
    }
    if let Some(cargo_label) = grounded_named_cargo_production_label(descriptor_id) {
        notes.push(format!(
            "named cargo production descriptor maps to cargo {cargo_label}"
        ));
    }
    if descriptor_metadata.is_some_and(|metadata| metadata.parameter_family == "cargo_price_scalar")
    {
        if let Some(cargo_label) = grounded_named_cargo_price_label(descriptor_id) {
            notes.push(format!(
                "named cargo price descriptor maps to cargo {cargo_label}"
            ));
        }
    }
    if descriptor_metadata
        .is_some_and(|metadata| metadata.parameter_family == "world_building_spawn")
    {
        let candidate_id = descriptor_id.saturating_sub(503);
        notes.push(format!(
            "add-building descriptor maps to live candidate id {candidate_id}"
        ));
        notes.push(
            "0x430270 add-building consumer uses placement count byte 0x11, center words 0x12/0x14, and radius word 0x16 after the descriptor_id - 503 candidate bridge; it clamps radius to at least 1 and retries up to 200 randomized placements without branching directly on grouped opcode".to_string(),
        );
        if candidate_id > 66 {
            notes.push(
                "current non-hook candidate-name catalogs only ground concrete add-building names through candidate id 66, so this descriptor remains on the checked-in candidate-slot boundary beyond the live RT3 1.05 table".to_string(),
            );
        }
    }

    Some(SmpLoadedPackedEventGroupedEffectRowSummary {
        group_index,
        row_index,
        descriptor_id,
        descriptor_label: descriptor_metadata.map(|metadata| metadata.label.to_string()),
        target_mask_bits: descriptor_metadata.map(|metadata| metadata.target_mask_bits),
        parameter_family: descriptor_metadata.map(|metadata| metadata.parameter_family.to_string()),
        grouped_target_subject: None,
        grouped_target_scope: None,
        opcode,
        raw_scalar_value,
        value_byte_0x09,
        value_dword_0x0d,
        value_byte_0x11,
        value_byte_0x12,
        value_word_0x14,
        value_word_0x16,
        row_shape,
        semantic_family: Some(semantic_family.clone()),
        semantic_preview: Some(build_real_grouped_effect_semantic_preview(
            descriptor_metadata.map(|metadata| metadata.label),
            &semantic_family,
            raw_scalar_value,
            value_byte_0x11,
            value_byte_0x12,
            value_word_0x14,
            value_word_0x16,
        )),
        recovered_cargo_slot: recovered_cargo_production_slot(descriptor_id),
        recovered_cargo_class: recovered_cargo_production_slot(descriptor_id)
            .and_then(known_cargo_slot_definition)
            .map(|definition| runtime_cargo_class_name(definition.cargo_class).to_string()),
        recovered_cargo_label: grounded_named_cargo_production_label(descriptor_id)
            .or_else(|| {
                descriptor_metadata
                    .filter(|metadata| metadata.parameter_family == "cargo_price_scalar")
                    .and_then(|_| grounded_named_cargo_price_label(descriptor_id))
            })
            .map(ToString::to_string),
        recovered_locomotive_id: recovered_locomotive_availability_loco_id(descriptor_id)
            .or_else(|| recovered_locomotive_cost_loco_id(descriptor_id)),
        locomotive_name,
        notes,
    })
}
