use super::control_lane::build_control_lane_analysis;
use super::live_ids::decode_live_entry_ids_from_tombstone_bitset;
use super::records::parse_event_runtime_record_summaries;
use crate::inspect::smp::bundle::SmpContainerProfile;
use crate::inspect::smp::events::*;
use crate::inspect::smp::save_load::SmpSaveLoadSummary;
use crate::inspect::smp::*;

pub(in crate::inspect::smp) fn parse_event_runtime_collection_summary(
    bytes: &[u8],
    container_profile: Option<&SmpContainerProfile>,
    save_load_summary: Option<&SmpSaveLoadSummary>,
) -> Option<SmpLoadedEventRuntimeCollectionSummary> {
    parse_event_runtime_collection_summary_with_tag_width(
        bytes,
        container_profile,
        save_load_summary,
        2,
    )
    .or_else(|| {
        parse_event_runtime_collection_summary_with_tag_width(
            bytes,
            container_profile,
            save_load_summary,
            4,
        )
    })
}

pub(in crate::inspect::smp) fn parse_event_runtime_collection_summary_with_tag_width(
    bytes: &[u8],
    container_profile: Option<&SmpContainerProfile>,
    save_load_summary: Option<&SmpSaveLoadSummary>,
    tag_width: usize,
) -> Option<SmpLoadedEventRuntimeCollectionSummary> {
    let (metadata_offsets, record_offsets, close_offsets) = match tag_width {
        2 => (
            find_u16_le_offsets(bytes, EVENT_RUNTIME_COLLECTION_METADATA_TAG),
            find_u16_le_offsets(bytes, EVENT_RUNTIME_COLLECTION_RECORDS_TAG),
            find_u16_le_offsets(bytes, EVENT_RUNTIME_COLLECTION_CLOSE_TAG),
        ),
        4 => (
            find_u32_le_offsets(bytes, EVENT_RUNTIME_COLLECTION_METADATA_TAG as u32),
            find_u32_le_offsets(bytes, EVENT_RUNTIME_COLLECTION_RECORDS_TAG as u32),
            find_u32_le_offsets(bytes, EVENT_RUNTIME_COLLECTION_CLOSE_TAG as u32),
        ),
        _ => return None,
    };

    for metadata_tag_offset in metadata_offsets {
        let packed_state_version = read_u32_at(bytes, metadata_tag_offset + tag_width)?;
        if packed_state_version != EVENT_RUNTIME_COLLECTION_PACKED_STATE_VERSION {
            continue;
        }

        let records_tag_offset = record_offsets
            .iter()
            .copied()
            .find(|offset| *offset > metadata_tag_offset + tag_width + 4)?;
        let close_tag_offset = close_offsets
            .iter()
            .copied()
            .find(|offset| *offset > records_tag_offset)?;
        let metadata_payload =
            bytes.get(metadata_tag_offset + tag_width + 4..records_tag_offset)?;
        if metadata_payload.len() < INDEXED_COLLECTION_SERIALIZED_HEADER_LEN {
            continue;
        }

        let header_words = (0..INDEXED_COLLECTION_SERIALIZED_HEADER_DWORD_COUNT)
            .map(|index| read_u32_at(metadata_payload, index * 4))
            .collect::<Option<Vec<_>>>()?;
        let direct_collection_flag = header_words[0];
        let direct_record_stride = usize::try_from(header_words[1]).ok()?;
        let live_id_bound = header_words[4];
        let live_record_count = usize::try_from(header_words[5]).ok()?;

        let records_payload = bytes.get(records_tag_offset + tag_width..close_tag_offset)?;
        let (source_kind, live_entry_ids) = if direct_collection_flag == 0 && tag_width == 4 {
            (
                "packed-event-runtime-collection-nondirect".to_string(),
                (1..=u32::try_from(live_record_count).ok()?).collect::<Vec<_>>(),
            )
        } else {
            if direct_collection_flag == 0 || direct_record_stride == 0 {
                continue;
            }

            let bitset_len = ((usize::try_from(live_id_bound).ok()?).saturating_add(15)) / 8;
            let payload_bytes = direct_record_stride.checked_mul(live_record_count)?;
            if metadata_payload.len() < INDEXED_COLLECTION_SERIALIZED_HEADER_LEN + bitset_len {
                continue;
            }
            if metadata_payload.len() < bitset_len + payload_bytes {
                continue;
            }

            let bitset_offset = metadata_payload.len() - bitset_len - payload_bytes;
            if bitset_offset < INDEXED_COLLECTION_SERIALIZED_HEADER_LEN {
                continue;
            }
            let bitset = metadata_payload.get(bitset_offset..bitset_offset + bitset_len)?;
            let live_entry_ids =
                decode_live_entry_ids_from_tombstone_bitset(bitset, live_id_bound)?;
            if live_entry_ids.len() != live_record_count {
                continue;
            }
            (
                "packed-event-runtime-collection".to_string(),
                live_entry_ids,
            )
        };

        let records = if source_kind == "packed-event-runtime-collection-nondirect" {
            try_parse_nondirect_event_runtime_record_summaries(
                records_payload,
                records_tag_offset + tag_width,
                &live_entry_ids,
            )
            .unwrap_or_else(|| {
                parse_event_runtime_record_summaries(
                    records_payload,
                    records_tag_offset + tag_width,
                    &live_entry_ids,
                )
            })
        } else {
            parse_event_runtime_record_summaries(
                records_payload,
                records_tag_offset + tag_width,
                &live_entry_ids,
            )
        };

        let decoded_record_count = records
            .iter()
            .filter(|record| record.decode_status != "unsupported_framing")
            .count();
        let imported_runtime_record_count = records
            .iter()
            .filter(|record| record.executable_import_ready)
            .count();
        let control_lane = build_control_lane_analysis(&records);

        return Some(SmpLoadedEventRuntimeCollectionSummary {
            source_kind,
            mechanism_family: save_load_summary
                .map(|summary| summary.mechanism_family.clone())
                .unwrap_or_else(|| "unknown".to_string()),
            mechanism_confidence: save_load_summary
                .map(|summary| summary.mechanism_confidence.clone())
                .unwrap_or_else(|| "inferred".to_string()),
            container_profile_family: container_profile
                .map(|profile| profile.profile_family.clone()),
            metadata_tag_offset,
            records_tag_offset,
            close_tag_offset,
            packed_state_version,
            packed_state_version_hex: format!("0x{packed_state_version:08x}"),
            live_id_bound,
            live_record_count,
            live_entry_ids,
            decoded_record_count,
            imported_runtime_record_count,
            records_with_trigger_kind: control_lane.records_with_trigger_kind,
            records_missing_trigger_kind: control_lane.records_missing_trigger_kind,
            nondirect_compact_record_count: control_lane.nondirect_compact_record_count,
            nondirect_compact_records_missing_trigger_kind: control_lane
                .nondirect_compact_records_missing_trigger_kind,
            trigger_kinds_present: control_lane.trigger_kinds_present,
            add_building_dispatch_strip_record_indexes: control_lane
                .add_building_dispatch_strip_record_indexes,
            add_building_dispatch_strip_descriptor_labels: control_lane
                .add_building_dispatch_strip_descriptor_labels,
            add_building_dispatch_strip_records_with_trigger_kind: control_lane
                .add_building_dispatch_strip_records_with_trigger_kind,
            add_building_dispatch_strip_records_missing_trigger_kind: control_lane
                .add_building_dispatch_strip_records_missing_trigger_kind,
            add_building_dispatch_strip_row_shape_families: control_lane
                .add_building_dispatch_strip_row_shape_families,
            add_building_dispatch_strip_signature_families: control_lane
                .add_building_dispatch_strip_signature_families,
            add_building_dispatch_strip_condition_tuple_families: control_lane
                .add_building_dispatch_strip_condition_tuple_families,
            add_building_dispatch_strip_signature_condition_clusters: control_lane
                .add_building_dispatch_strip_signature_condition_clusters,
            control_lane_notes: control_lane.control_lane_notes,
            records,
        });
    }

    None
}
