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

pub(super) struct ControlLaneAnalysis {
    pub(super) records_with_trigger_kind: usize,
    pub(super) records_missing_trigger_kind: usize,
    pub(super) nondirect_compact_record_count: usize,
    pub(super) nondirect_compact_records_missing_trigger_kind: usize,
    pub(super) trigger_kinds_present: Vec<u8>,
    pub(super) add_building_dispatch_strip_record_indexes: Vec<usize>,
    pub(super) add_building_dispatch_strip_descriptor_labels: Vec<String>,
    pub(super) add_building_dispatch_strip_records_with_trigger_kind: usize,
    pub(super) add_building_dispatch_strip_records_missing_trigger_kind: usize,
    pub(super) add_building_dispatch_strip_row_shape_families: Vec<String>,
    pub(super) add_building_dispatch_strip_signature_families: Vec<String>,
    pub(super) add_building_dispatch_strip_condition_tuple_families: Vec<String>,
    pub(super) add_building_dispatch_strip_signature_condition_clusters: Vec<String>,
    pub(super) control_lane_notes: Vec<String>,
}

pub(super) fn build_control_lane_analysis(
    records: &[SmpLoadedPackedEventRecordSummary],
) -> ControlLaneAnalysis {
    let records_with_trigger_kind = records
        .iter()
        .filter(|record| record.trigger_kind.is_some())
        .count();
    let records_missing_trigger_kind = records.len().saturating_sub(records_with_trigger_kind);
    let nondirect_compact_record_count = records
        .iter()
        .filter(|record| record.payload_family == "real_packed_nondirect_compact_v1")
        .count();
    let nondirect_compact_records_missing_trigger_kind = records
        .iter()
        .filter(|record| {
            record.payload_family == "real_packed_nondirect_compact_v1"
                && record.trigger_kind.is_none()
        })
        .count();
    let mut trigger_kinds_present = records
        .iter()
        .filter_map(|record| record.trigger_kind)
        .collect::<Vec<_>>();
    trigger_kinds_present.sort_unstable();
    trigger_kinds_present.dedup();
    let mut mutation_candidate_record_indexes = records
        .iter()
        .filter(|record| {
            record.grouped_effect_rows.iter().any(|row| {
                opcode_reaches_world_apply_compact_runtime_effect_dispatch_strip(row.opcode)
            })
        })
        .map(|record| record.record_index)
        .collect::<Vec<_>>();
    mutation_candidate_record_indexes.sort_unstable();
    mutation_candidate_record_indexes.dedup();
    let mut mutation_candidate_opcodes = records
        .iter()
        .flat_map(|record| record.grouped_effect_rows.iter().map(|row| row.opcode))
        .filter(|opcode| opcode_reaches_world_apply_compact_runtime_effect_dispatch_strip(*opcode))
        .collect::<Vec<_>>();
    mutation_candidate_opcodes.sort_unstable();
    mutation_candidate_opcodes.dedup();
    let mut opcode_0x08_record_indexes = records
        .iter()
        .filter(|record| {
            record
                .grouped_effect_rows
                .iter()
                .any(|row| row.opcode == 0x08)
        })
        .map(|record| record.record_index)
        .collect::<Vec<_>>();
    opcode_0x08_record_indexes.sort_unstable();
    opcode_0x08_record_indexes.dedup();
    let mut add_building_dispatch_strip_record_indexes = records
        .iter()
        .filter(|record| {
            record.grouped_effect_rows.iter().any(|row| {
                opcode_reaches_world_apply_compact_runtime_effect_dispatch_strip(row.opcode)
                    && compact_event_dispatch_add_building_descriptor_id(row.descriptor_id)
            })
        })
        .map(|record| record.record_index)
        .collect::<Vec<_>>();
    add_building_dispatch_strip_record_indexes.sort_unstable();
    add_building_dispatch_strip_record_indexes.dedup();
    let add_building_dispatch_strip_records_with_trigger_kind = records
        .iter()
        .filter(|record| {
            record.trigger_kind.is_some()
                && record.grouped_effect_rows.iter().any(|row| {
                    opcode_reaches_world_apply_compact_runtime_effect_dispatch_strip(row.opcode)
                        && compact_event_dispatch_add_building_descriptor_id(row.descriptor_id)
                })
        })
        .count();
    let add_building_dispatch_strip_records_missing_trigger_kind = records
        .iter()
        .filter(|record| {
            record.trigger_kind.is_none()
                && record.grouped_effect_rows.iter().any(|row| {
                    opcode_reaches_world_apply_compact_runtime_effect_dispatch_strip(row.opcode)
                        && compact_event_dispatch_add_building_descriptor_id(row.descriptor_id)
                })
        })
        .count();
    let mut mutation_candidate_descriptor_labels = records
        .iter()
        .flat_map(|record| record.grouped_effect_rows.iter())
        .filter(|row| opcode_reaches_world_apply_compact_runtime_effect_dispatch_strip(row.opcode))
        .filter_map(|row| row.descriptor_label.clone())
        .collect::<Vec<_>>();
    mutation_candidate_descriptor_labels.sort_unstable();
    mutation_candidate_descriptor_labels.dedup();
    let mut add_building_dispatch_strip_descriptor_labels = records
        .iter()
        .flat_map(|record| record.grouped_effect_rows.iter())
        .filter(|row| {
            opcode_reaches_world_apply_compact_runtime_effect_dispatch_strip(row.opcode)
                && compact_event_dispatch_add_building_descriptor_id(row.descriptor_id)
        })
        .filter_map(|row| row.descriptor_label.clone())
        .collect::<Vec<_>>();
    add_building_dispatch_strip_descriptor_labels.sort_unstable();
    add_building_dispatch_strip_descriptor_labels.dedup();
    let mut add_building_dispatch_strip_row_shape_families = records
        .iter()
        .filter(|record| {
            record.grouped_effect_rows.iter().any(|row| {
                opcode_reaches_world_apply_compact_runtime_effect_dispatch_strip(row.opcode)
                    && compact_event_dispatch_add_building_descriptor_id(row.descriptor_id)
            })
        })
        .map(|record| {
            compact_event_dispatch_row_shape_family_from_summary_rows(&record.grouped_effect_rows)
        })
        .collect::<Vec<_>>();
    add_building_dispatch_strip_row_shape_families.sort_unstable();
    add_building_dispatch_strip_row_shape_families.dedup();
    let mut add_building_dispatch_strip_signature_families = records
        .iter()
        .filter(|record| {
            record.grouped_effect_rows.iter().any(|row| {
                opcode_reaches_world_apply_compact_runtime_effect_dispatch_strip(row.opcode)
                    && compact_event_dispatch_add_building_descriptor_id(row.descriptor_id)
            })
        })
        .map(|record| {
            compact_event_signature_family_from_notes(&record.notes)
                .unwrap_or_else(|| "unknown-signature-family".to_string())
        })
        .collect::<Vec<_>>();
    add_building_dispatch_strip_signature_families.sort_unstable();
    add_building_dispatch_strip_signature_families.dedup();
    let mut add_building_dispatch_strip_condition_tuple_families = records
        .iter()
        .filter(|record| {
            record.grouped_effect_rows.iter().any(|row| {
                opcode_reaches_world_apply_compact_runtime_effect_dispatch_strip(row.opcode)
                    && compact_event_dispatch_add_building_descriptor_id(row.descriptor_id)
            })
        })
        .map(|record| {
            compact_event_dispatch_condition_tuple_family_from_summary_rows(
                &record.standalone_condition_rows,
            )
        })
        .collect::<Vec<_>>();
    add_building_dispatch_strip_condition_tuple_families.sort_unstable();
    add_building_dispatch_strip_condition_tuple_families.dedup();
    let mut add_building_dispatch_strip_signature_condition_clusters = records
        .iter()
        .filter(|record| {
            record.grouped_effect_rows.iter().any(|row| {
                opcode_reaches_world_apply_compact_runtime_effect_dispatch_strip(row.opcode)
                    && compact_event_dispatch_add_building_descriptor_id(row.descriptor_id)
            })
        })
        .map(|record| {
            compact_event_dispatch_signature_condition_cluster_from_summary_rows(
                compact_event_signature_family_from_notes(&record.notes).as_deref(),
                &record.standalone_condition_rows,
            )
        })
        .collect::<Vec<_>>();
    add_building_dispatch_strip_signature_condition_clusters.sort_unstable();
    add_building_dispatch_strip_signature_condition_clusters.dedup();
    let mut mutation_candidate_unknown_descriptor_ids = records
        .iter()
        .flat_map(|record| record.grouped_effect_rows.iter())
        .filter(|row| {
            opcode_reaches_world_apply_compact_runtime_effect_dispatch_strip(row.opcode)
                && row.descriptor_label.is_none()
        })
        .map(|row| row.descriptor_id)
        .collect::<Vec<_>>();
    mutation_candidate_unknown_descriptor_ids.sort_unstable();
    mutation_candidate_unknown_descriptor_ids.dedup();
    let mut mutation_candidate_special_condition_label_matches =
        mutation_candidate_unknown_descriptor_ids
            .iter()
            .filter_map(|descriptor_id| {
                known_special_condition_label_for_compact_descriptor_id(*descriptor_id)
                    .map(|label| format!("{descriptor_id} -> {label}"))
            })
            .collect::<Vec<_>>();
    mutation_candidate_special_condition_label_matches.sort();
    mutation_candidate_special_condition_label_matches.dedup();
    let mut dispatch_strip_unknown_condition_ids = records
        .iter()
        .filter(|record| {
            record.grouped_effect_rows.iter().any(|row| {
                opcode_reaches_world_apply_compact_runtime_effect_dispatch_strip(row.opcode)
            })
        })
        .flat_map(|record| record.standalone_condition_rows.iter())
        .filter(|row| row.raw_condition_id >= 0 && row.metric.is_none())
        .map(|row| row.raw_condition_id)
        .collect::<Vec<_>>();
    dispatch_strip_unknown_condition_ids.sort_unstable();
    dispatch_strip_unknown_condition_ids.dedup();

    let control_lane_notes = build_control_lane_notes(
        records,
        records_with_trigger_kind,
        nondirect_compact_record_count,
        nondirect_compact_records_missing_trigger_kind,
        &trigger_kinds_present,
        &mutation_candidate_record_indexes,
        &mutation_candidate_opcodes,
        &mutation_candidate_descriptor_labels,
        &mutation_candidate_unknown_descriptor_ids,
        &mutation_candidate_special_condition_label_matches,
        &dispatch_strip_unknown_condition_ids,
        &opcode_0x08_record_indexes,
        &add_building_dispatch_strip_record_indexes,
        &add_building_dispatch_strip_descriptor_labels,
        &add_building_dispatch_strip_row_shape_families,
        &add_building_dispatch_strip_signature_families,
        &add_building_dispatch_strip_condition_tuple_families,
        &add_building_dispatch_strip_signature_condition_clusters,
        add_building_dispatch_strip_records_with_trigger_kind,
    );

    ControlLaneAnalysis {
        records_with_trigger_kind,
        records_missing_trigger_kind,
        nondirect_compact_record_count,
        nondirect_compact_records_missing_trigger_kind,
        trigger_kinds_present,
        add_building_dispatch_strip_record_indexes,
        add_building_dispatch_strip_descriptor_labels,
        add_building_dispatch_strip_records_with_trigger_kind,
        add_building_dispatch_strip_records_missing_trigger_kind,
        add_building_dispatch_strip_row_shape_families,
        add_building_dispatch_strip_signature_families,
        add_building_dispatch_strip_condition_tuple_families,
        add_building_dispatch_strip_signature_condition_clusters,
        control_lane_notes,
    }
}

#[allow(clippy::too_many_arguments)]
fn build_control_lane_notes(
    records: &[SmpLoadedPackedEventRecordSummary],
    records_with_trigger_kind: usize,
    nondirect_compact_record_count: usize,
    nondirect_compact_records_missing_trigger_kind: usize,
    trigger_kinds_present: &[u8],
    mutation_candidate_record_indexes: &[usize],
    mutation_candidate_opcodes: &[u8],
    mutation_candidate_descriptor_labels: &[String],
    mutation_candidate_unknown_descriptor_ids: &[u32],
    mutation_candidate_special_condition_label_matches: &[String],
    dispatch_strip_unknown_condition_ids: &[i32],
    opcode_0x08_record_indexes: &[usize],
    add_building_dispatch_strip_record_indexes: &[usize],
    add_building_dispatch_strip_descriptor_labels: &[String],
    add_building_dispatch_strip_row_shape_families: &[String],
    add_building_dispatch_strip_signature_families: &[String],
    add_building_dispatch_strip_condition_tuple_families: &[String],
    add_building_dispatch_strip_signature_condition_clusters: &[String],
    add_building_dispatch_strip_records_with_trigger_kind: usize,
) -> Vec<String> {
    let mut control_lane_notes = Vec::new();
    if nondirect_compact_record_count != 0
        && nondirect_compact_record_count == nondirect_compact_records_missing_trigger_kind
    {
        control_lane_notes.push(
            "all compact non-direct rows currently decode row bodies only and still lack a decoded trigger/control lane".to_string(),
        );
        control_lane_notes.push(
            "direct disassembly now grounds that as a real loader boundary: 0x0042db20 allocates linked 0x1e/0x28 row nodes from the 0x4e9a slice and leaves [event+0x7ee..0x80f] to the separate 0x0042e050 full-event clone path, so missing trigger-kind bytes on this family are not just a parser gap".to_string(),
        );
        control_lane_notes.push(
            "the checked 0x0042e050 caller census is narrow too: current direct caller 0x004dba23 sits under the event-editor duplication path rather than 0x00433130 load, so ordinary 0x4e9a restore is not currently grounded to inherit trigger/control bytes through that deep-copy seam".to_string(),
        );
        control_lane_notes.push(
            "the first non-editor positive control-lane writer is bounded away from ordinary restore too: 0x00430b50 allocates a fresh live runtime-effect row through 0x00432ea0 -> 0x0042d5a0, seeds [event+0x7ef] to 2 or 3 plus adjacent control bytes, and is reached from 0x004323a0 service at 0x0043232e rather than 0x00433130 load".to_string(),
        );
        control_lane_notes.push(
            "the remaining non-editor [event+0x7ef] mutators are bounded away from restore too: the 0x00443200..0x004436e3 sweep searches existing live runtime-event names through 0x005a57cf (including strings like 'New Beginnings', 'Chicago to New York', 'The American', and 'Labor') and retags already-live records, so it reads as scenario-specific live maintenance rather than the missing 0x4e9a restore owner".to_string(),
        );
        control_lane_notes.push(
            "direct disassembly of 0x004323a0 now makes the live gate explicit too: the per-record service returns before dispatch unless one-shot latch [event+0x81f] is clear, mode byte [event+0x7ef] matches the selected trigger kind from 0x00432f40, and compact chain root [event+0x00] is nonzero; its kind-8 side path at 0x00432ca1..0x00432cb0 only calls 0x00438710 on already-live records with [event+0x7ef] == 8".to_string(),
        );
        control_lane_notes.push(
            "the post-load name-driven retagger is narrower than a bulk trigger-kind materializer too: direct disassembly of 0x00442c30 (called from 0x00443a50 at 0x00444b50) shows a hardcoded scenario-name patch table over already-live records in 0x0062be18/0x0062bae0, and the checked cases mostly tweak modifier bytes [event+0x7f9/+0x7fa] or nested payload scalars on records that already carry concrete kinds such as 7 ('Open Aus', 'The American'), 6 ('Test connections'), 5 ('Win - Gold'), and 1 ('Win - Silver' / 'Win - Bronze')".to_string(),
        );
        control_lane_notes.push(
            "direct disassembly now boxes in the explicit trigger-kind materializations inside that same retagger too: the 'SP - GOLD' branch at 0x00443526 rewrites [event+0x7ef] from 1 to 5 on live runtime-event id 1 when the scenario flag [world+0x66de] is set and payload-root kind 7 carries subtype byte 5, while the 'Labor' branch at 0x00443601 rewrites [event+0x7ef] from 0 to 2 on live runtime-event id 0x0d when the same scenario flag is set and the checked 0x3c -> 0x3d child payload pair carries the matching negative scalar sentinel".to_string(),
        );
    }
    if records_with_trigger_kind != 0 {
        control_lane_notes.push(format!(
            "decoded trigger kinds present in this collection = {:?}",
            trigger_kinds_present
        ));
    }
    if !mutation_candidate_record_indexes.is_empty() {
        control_lane_notes.push(format!(
            "records with grouped opcodes already in the 0x00431b20 dispatch strip = {:?}",
            mutation_candidate_record_indexes
        ));
        if records_with_trigger_kind == 0 {
            control_lane_notes.push(
                "decoded grouped rows already reach the 0x00431b20 dispatch strip in this collection even though the current inspection surface recovered no trigger/control kind bytes for those records"
                    .to_string(),
            );
            if nondirect_compact_record_count == records.len() {
                control_lane_notes.push(
                    "every currently decoded dispatch-strip row in this collection still sits in the nondirect compact 0x4e99/0x4e9a/0x4e9b family with null [event+0x7ef], so the direct full-record 0x4e21/0x4e22 framing path is not currently bridging trigger-kind control bytes for these mutation-capable rows".to_string(),
                );
            }
        }
        control_lane_notes.push(format!(
            "0x00431b20 dispatch-strip opcodes present in decoded grouped rows = {:?}",
            mutation_candidate_opcodes
        ));
        if !mutation_candidate_descriptor_labels.is_empty() {
            control_lane_notes.push(format!(
                "decoded grouped descriptor labels present in the 0x00431b20 dispatch strip = {:?}",
                mutation_candidate_descriptor_labels
            ));
        }
        if !mutation_candidate_unknown_descriptor_ids.is_empty() {
            control_lane_notes.push(format!(
                "grouped descriptor ids still missing checked-in labels in the 0x00431b20 dispatch strip = {:?}",
                mutation_candidate_unknown_descriptor_ids
            ));
        }
        if !mutation_candidate_special_condition_label_matches.is_empty() {
            control_lane_notes.push(format!(
                "unlabeled 0x00431b20 dispatch-strip descriptor ids matching known special-condition label_id-2000 values = {:?}",
                mutation_candidate_special_condition_label_matches
            ));
        }
        if !dispatch_strip_unknown_condition_ids.is_empty() {
            control_lane_notes.push(format!(
                "standalone condition ids still missing checked-in labels in the 0x00431b20 dispatch strip = {:?}",
                dispatch_strip_unknown_condition_ids
            ));
        }
        if !opcode_0x08_record_indexes.is_empty() {
            control_lane_notes.push(format!(
                "records with opcode 0x08 in the 0x00431b20 dispatch strip = {:?}",
                opcode_0x08_record_indexes
            ));
            control_lane_notes.push(
                "checked-in function-map evidence currently grounds opcode 0x08 on the 0x00426d60 company_deactivate_and_clear_chairman_share_links branch".to_string(),
            );
        }
        if !add_building_dispatch_strip_record_indexes.is_empty() {
            control_lane_notes.push(format!(
                "records with Add Building descriptors in the 0x00431b20 dispatch strip = {:?}",
                add_building_dispatch_strip_record_indexes
            ));
            control_lane_notes.push(format!(
                "decoded Add Building descriptor labels present in the 0x00431b20 dispatch strip = {:?}",
                add_building_dispatch_strip_descriptor_labels
            ));
            control_lane_notes.push(format!(
                "Add Building row-shape families present in the 0x00431b20 dispatch strip = {:?}",
                add_building_dispatch_strip_row_shape_families
            ));
            control_lane_notes.push(format!(
                "Add Building signature families present in the 0x00431b20 dispatch strip = {:?}",
                add_building_dispatch_strip_signature_families
            ));
            control_lane_notes.push(format!(
                "Add Building condition-tuple families present in the 0x00431b20 dispatch strip = {:?}",
                add_building_dispatch_strip_condition_tuple_families
            ));
            control_lane_notes.push(format!(
                "Add Building signature/condition clusters present in the 0x00431b20 dispatch strip = {:?}",
                add_building_dispatch_strip_signature_condition_clusters
            ));
            if add_building_dispatch_strip_records_with_trigger_kind == 0 {
                control_lane_notes.push(
                    "every currently decoded Add Building dispatch-strip row still has null trigger kind, so the missing control-lane mapping remains the blocker above the already-grounded add-building descriptor bridge".to_string(),
                );
            }
        }
    }

    control_lane_notes
}

pub(in crate::inspect::smp) fn opcode_reaches_world_apply_compact_runtime_effect_dispatch_strip(
    opcode: u8,
) -> bool {
    matches!(opcode, 0x04..=0x08 | 0x0d | 0x10..=0x13 | 0x16)
}

pub(in crate::inspect::smp) fn compact_event_dispatch_add_building_descriptor_id(
    descriptor_id: u32,
) -> bool {
    (503..=613).contains(&descriptor_id)
}

pub(in crate::inspect::smp) fn compact_event_signature_family_from_notes(
    notes: &[String],
) -> Option<String> {
    notes.iter().find_map(|note| {
        note.strip_prefix("compact signature family = ")
            .map(ToString::to_string)
    })
}

pub(in crate::inspect::smp) fn compact_event_dispatch_condition_tuple_family_from_summary_rows(
    rows: &[SmpLoadedPackedEventConditionRowSummary],
) -> String {
    if rows.is_empty() {
        return "[]".to_string();
    }
    let parts = rows
        .iter()
        .map(|row| match &row.metric {
            Some(metric) => format!("{}:{}:{}", row.raw_condition_id, row.subtype, metric),
            None => format!("{}:{}", row.raw_condition_id, row.subtype),
        })
        .collect::<Vec<_>>();
    format!("[{}]", parts.join(","))
}

pub(in crate::inspect::smp) fn compact_event_dispatch_row_shape_family_from_summary_rows(
    rows: &[SmpLoadedPackedEventGroupedEffectRowSummary],
) -> String {
    if rows.is_empty() {
        return "[]".to_string();
    }
    let parts = rows
        .iter()
        .map(|row| {
            format!(
                "{}:{}:{}",
                row.group_index, row.opcode, row.raw_scalar_value
            )
        })
        .collect::<Vec<_>>();
    format!("[{}]", parts.join(","))
}

pub(in crate::inspect::smp) fn compact_event_dispatch_signature_condition_cluster_from_summary_rows(
    signature_family: Option<&str>,
    rows: &[SmpLoadedPackedEventConditionRowSummary],
) -> String {
    format!(
        "{} :: {}",
        signature_family.unwrap_or("unknown-signature-family"),
        compact_event_dispatch_condition_tuple_family_from_summary_rows(rows)
    )
}

pub(in crate::inspect::smp) fn known_special_condition_label_for_compact_descriptor_id(
    descriptor_id: u32,
) -> Option<&'static str> {
    let label_id = descriptor_id.checked_add(2000)?;
    KNOWN_SPECIAL_CONDITION_DEFINITIONS
        .iter()
        .find(|definition| definition.label_id == label_id)
        .map(|definition| definition.label)
}
