use std::collections::BTreeSet;

use super::context::ValidationContext;
use crate::state::RuntimeState;
use crate::validation::{validate_runtime_condition, validate_runtime_effect};

pub(super) fn validate_events(
    state: &RuntimeState,
    context: &ValidationContext,
) -> Result<(), String> {
    let mut seen_record_ids = BTreeSet::new();
    for record in &state.event_runtime_records {
        if !seen_record_ids.insert(record.record_id) {
            return Err(format!("duplicate record_id {}", record.record_id));
        }
        for (condition_index, condition) in record.conditions.iter().enumerate() {
            validate_runtime_condition(
                condition,
                &context.seen_company_ids,
                &context.seen_player_ids,
                &context.seen_chairman_profile_ids,
                &context.seen_territory_ids,
            )
            .map_err(|err| {
                format!(
                    "event_runtime_records[record_id={}].conditions[{condition_index}] {err}",
                    record.record_id
                )
            })?;
        }
        for (effect_index, effect) in record.effects.iter().enumerate() {
            validate_runtime_effect(
                effect,
                &context.seen_company_ids,
                &context.seen_player_ids,
                &context.seen_chairman_profile_ids,
                &context.seen_territory_ids,
            )
            .map_err(|err| {
                format!(
                    "event_runtime_records[record_id={}].effects[{effect_index}] {err}",
                    record.record_id
                )
            })?;
        }
    }

    if let Some(summary) = &state.packed_event_collection {
        if summary.source_kind.trim().is_empty() {
            return Err("packed_event_collection.source_kind must not be empty".to_string());
        }
        if summary.mechanism_family.trim().is_empty() {
            return Err("packed_event_collection.mechanism_family must not be empty".to_string());
        }
        if summary.mechanism_confidence.trim().is_empty() {
            return Err(
                "packed_event_collection.mechanism_confidence must not be empty".to_string(),
            );
        }
        if summary
            .container_profile_family
            .as_deref()
            .is_some_and(|value| value.trim().is_empty())
        {
            return Err(
                "packed_event_collection.container_profile_family must not be empty".to_string(),
            );
        }
        if summary.packed_state_version_hex.trim().is_empty() {
            return Err(
                "packed_event_collection.packed_state_version_hex must not be empty".to_string(),
            );
        }
        if summary.live_record_count != summary.live_entry_ids.len() {
            return Err(
                "packed_event_collection.live_record_count must match live_entry_ids length"
                    .to_string(),
            );
        }
        if summary.live_record_count != summary.records.len() {
            return Err(
                "packed_event_collection.live_record_count must match records length".to_string(),
            );
        }
        let decoded_record_count = summary
            .records
            .iter()
            .filter(|record| record.decode_status != "unsupported_framing")
            .count();
        if summary.decoded_record_count != decoded_record_count {
            return Err(
                "packed_event_collection.decoded_record_count must match decoded records"
                    .to_string(),
            );
        }
        let importable_or_imported_count = summary
            .records
            .iter()
            .filter(|record| {
                record.executable_import_ready
                    || record.import_outcome.as_deref() == Some("imported")
            })
            .count();
        if summary.imported_runtime_record_count > importable_or_imported_count {
            return Err(
                "packed_event_collection.imported_runtime_record_count must not exceed importable or imported records"
                    .to_string(),
            );
        }

        let mut previous_id = None;
        for (record_index, entry_id) in summary.live_entry_ids.iter().enumerate() {
            if *entry_id == 0 {
                return Err(
                    "packed_event_collection.live_entry_ids must not contain id 0".to_string(),
                );
            }
            if *entry_id > summary.live_id_bound {
                return Err(format!(
                    "packed_event_collection.live_entry_id {} exceeds live_id_bound {}",
                    entry_id, summary.live_id_bound
                ));
            }
            if previous_id.is_some_and(|prior| prior >= *entry_id) {
                return Err(
                    "packed_event_collection.live_entry_ids must be strictly ascending".to_string(),
                );
            }
            previous_id = Some(*entry_id);

            let record = &summary.records[record_index];
            if record.live_entry_id != *entry_id {
                return Err(format!(
                    "packed_event_collection.records[{record_index}].live_entry_id must match live_entry_ids"
                ));
            }
            if record.record_index != record_index {
                return Err(format!(
                    "packed_event_collection.records[{record_index}].record_index must match position"
                ));
            }
            if record.decode_status.trim().is_empty() {
                return Err(format!(
                    "packed_event_collection.records[{record_index}].decode_status must not be empty"
                ));
            }
            if record.payload_family.trim().is_empty() {
                return Err(format!(
                    "packed_event_collection.records[{record_index}].payload_family must not be empty"
                ));
            }
            if record
                .import_outcome
                .as_deref()
                .is_some_and(|value| value.trim().is_empty())
            {
                return Err(format!(
                    "packed_event_collection.records[{record_index}].import_outcome must not be empty"
                ));
            }
            if record.grouped_effect_row_counts.len() != 4 {
                return Err(format!(
                    "packed_event_collection.records[{record_index}].grouped_effect_row_counts must contain exactly 4 entries"
                ));
            }
            if record.payload_family == "real_packed_v1"
                && record.standalone_condition_rows.len() != record.standalone_condition_row_count
            {
                return Err(format!(
                    "packed_event_collection.records[{record_index}].standalone_condition_rows must match standalone_condition_row_count"
                ));
            }
            if record.payload_family == "real_packed_v1"
                && record.grouped_effect_rows.len()
                    != record.grouped_effect_row_counts.iter().sum::<usize>()
            {
                return Err(format!(
                    "packed_event_collection.records[{record_index}].grouped_effect_rows must match grouped_effect_row_counts"
                ));
            }
            for band in &record.text_bands {
                if band.label.trim().is_empty() {
                    return Err(format!(
                        "packed_event_collection.records[{record_index}].text_bands contains an empty label"
                    ));
                }
            }
            if let Some(control) = &record.compact_control {
                if control.grouped_target_scope_ordinals_0x7fb.len() != 4 {
                    return Err(format!(
                        "packed_event_collection.records[{record_index}].compact_control.grouped_target_scope_ordinals_0x7fb must contain exactly 4 entries"
                    ));
                }
                if control.grouped_scope_checkboxes_0x7ff.len() != 4 {
                    return Err(format!(
                        "packed_event_collection.records[{record_index}].compact_control.grouped_scope_checkboxes_0x7ff must contain exactly 4 entries"
                    ));
                }
                if control.grouped_territory_selectors_0x80f.len() != 4 {
                    return Err(format!(
                        "packed_event_collection.records[{record_index}].compact_control.grouped_territory_selectors_0x80f must contain exactly 4 entries"
                    ));
                }
            }
            for row in &record.standalone_condition_rows {
                if row
                    .candidate_name
                    .as_deref()
                    .is_some_and(|value| value.trim().is_empty())
                {
                    return Err(format!(
                        "packed_event_collection.records[{record_index}].standalone_condition_rows contains an empty candidate_name"
                    ));
                }
                if row
                    .comparator
                    .as_deref()
                    .is_some_and(|value| value.trim().is_empty())
                {
                    return Err(format!(
                        "packed_event_collection.records[{record_index}].standalone_condition_rows contains an empty comparator"
                    ));
                }
                if row
                    .metric
                    .as_deref()
                    .is_some_and(|value| value.trim().is_empty())
                {
                    return Err(format!(
                        "packed_event_collection.records[{record_index}].standalone_condition_rows contains an empty metric"
                    ));
                }
                if row
                    .semantic_family
                    .as_deref()
                    .is_some_and(|value| value.trim().is_empty())
                {
                    return Err(format!(
                        "packed_event_collection.records[{record_index}].standalone_condition_rows contains an empty semantic_family"
                    ));
                }
                if row
                    .semantic_preview
                    .as_deref()
                    .is_some_and(|value| value.trim().is_empty())
                {
                    return Err(format!(
                        "packed_event_collection.records[{record_index}].standalone_condition_rows contains an empty semantic_preview"
                    ));
                }
            }
            for row in &record.grouped_effect_rows {
                if row.row_shape.trim().is_empty() {
                    return Err(format!(
                        "packed_event_collection.records[{record_index}].grouped_effect_rows contains an empty row_shape"
                    ));
                }
                if row
                    .locomotive_name
                    .as_deref()
                    .is_some_and(|value| value.trim().is_empty())
                {
                    return Err(format!(
                        "packed_event_collection.records[{record_index}].grouped_effect_rows contains an empty locomotive_name"
                    ));
                }
            }
        }
    }

    Ok(())
}
