use serde::{Deserialize, Serialize};
use serde_json::Value;

use rrt_runtime::{RuntimeState, RuntimeSummary, StepCommand};

pub const FIXTURE_FORMAT_VERSION: u32 = 1;

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
pub struct FixtureSource {
    pub kind: String,
    #[serde(default)]
    pub description: Option<String>,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
pub struct ExpectedRuntimeSummary {
    #[serde(default)]
    pub calendar: Option<rrt_runtime::CalendarPoint>,
    #[serde(default)]
    pub calendar_projection_source: Option<String>,
    #[serde(default)]
    pub calendar_projection_is_placeholder: Option<bool>,
    #[serde(default)]
    pub world_flag_count: Option<usize>,
    #[serde(default)]
    pub world_restore_selected_year_profile_lane: Option<u8>,
    #[serde(default)]
    pub world_restore_campaign_scenario_enabled: Option<bool>,
    #[serde(default)]
    pub world_restore_sandbox_enabled: Option<bool>,
    #[serde(default)]
    pub world_restore_seed_tuple_written_from_raw_lane: Option<bool>,
    #[serde(default)]
    pub world_restore_absolute_counter_requires_shell_context: Option<bool>,
    #[serde(default)]
    pub world_restore_absolute_counter_reconstructible_from_save: Option<bool>,
    #[serde(default)]
    pub world_restore_packed_year_word_raw_u16: Option<u16>,
    #[serde(default)]
    pub world_restore_partial_year_progress_raw_u8: Option<u8>,
    #[serde(default)]
    pub world_restore_current_calendar_tuple_word_raw_u32: Option<u32>,
    #[serde(default)]
    pub world_restore_current_calendar_tuple_word_2_raw_u32: Option<u32>,
    #[serde(default)]
    pub world_restore_absolute_counter_raw_u32: Option<u32>,
    #[serde(default)]
    pub world_restore_absolute_counter_mirror_raw_u32: Option<u32>,
    #[serde(default)]
    pub world_restore_disable_cargo_economy_special_condition_slot: Option<u8>,
    #[serde(default)]
    pub world_restore_disable_cargo_economy_special_condition_reconstructible_from_save:
        Option<bool>,
    #[serde(default)]
    pub world_restore_disable_cargo_economy_special_condition_write_side_grounded: Option<bool>,
    #[serde(default)]
    pub world_restore_disable_cargo_economy_special_condition_enabled: Option<bool>,
    #[serde(default)]
    pub world_restore_use_bio_accelerator_cars_enabled: Option<bool>,
    #[serde(default)]
    pub world_restore_use_wartime_cargos_enabled: Option<bool>,
    #[serde(default)]
    pub world_restore_disable_train_crashes_enabled: Option<bool>,
    #[serde(default)]
    pub world_restore_disable_train_crashes_and_breakdowns_enabled: Option<bool>,
    #[serde(default)]
    pub world_restore_ai_ignore_territories_at_startup_enabled: Option<bool>,
    #[serde(default)]
    pub world_restore_limited_track_building_amount: Option<i32>,
    #[serde(default)]
    pub world_restore_economic_status_code: Option<i32>,
    #[serde(default)]
    pub world_restore_territory_access_cost: Option<u32>,
    #[serde(default)]
    pub world_restore_issue_37_value: Option<u32>,
    #[serde(default)]
    pub world_restore_issue_38_value: Option<u32>,
    #[serde(default)]
    pub world_restore_issue_39_value: Option<u32>,
    #[serde(default)]
    pub world_restore_issue_3a_value: Option<u32>,
    #[serde(default)]
    pub world_restore_issue_37_multiplier_raw_u32: Option<u32>,
    #[serde(default)]
    pub world_restore_issue_37_multiplier_value_f32_text: Option<String>,
    #[serde(default)]
    pub world_restore_finance_neighborhood_count: Option<usize>,
    #[serde(default)]
    pub world_restore_finance_neighborhood_labels: Option<Vec<String>>,
    #[serde(default)]
    pub world_restore_economic_tuning_mirror_raw_u32: Option<u32>,
    #[serde(default)]
    pub world_restore_economic_tuning_mirror_value_f32_text: Option<String>,
    #[serde(default)]
    pub world_restore_economic_tuning_lane_count: Option<usize>,
    #[serde(default)]
    pub world_restore_economic_tuning_lane_value_f32_text: Option<Vec<String>>,
    #[serde(default)]
    pub world_restore_absolute_counter_restore_kind: Option<String>,
    #[serde(default)]
    pub world_restore_absolute_counter_adjustment_context: Option<String>,
    #[serde(default)]
    pub metadata_count: Option<usize>,
    #[serde(default)]
    pub company_count: Option<usize>,
    #[serde(default)]
    pub active_company_count: Option<usize>,
    #[serde(default)]
    pub company_market_state_owner_count: Option<usize>,
    #[serde(default)]
    pub selected_company_outstanding_shares: Option<u32>,
    #[serde(default)]
    pub selected_company_bond_count: Option<u8>,
    #[serde(default)]
    pub selected_company_largest_live_bond_principal: Option<u32>,
    #[serde(default)]
    pub selected_company_highest_coupon_live_bond_principal: Option<u32>,
    #[serde(default)]
    pub selected_company_assigned_share_pool: Option<u32>,
    #[serde(default)]
    pub selected_company_unassigned_share_pool: Option<u32>,
    #[serde(default)]
    pub selected_company_cached_share_price: Option<i64>,
    #[serde(default)]
    pub selected_company_cached_share_price_value_f32_text: Option<String>,
    #[serde(default)]
    pub selected_company_mutable_support_scalar_value_f32_text: Option<String>,
    #[serde(default)]
    pub selected_company_stat_band_root_0cfb_count: Option<usize>,
    #[serde(default)]
    pub selected_company_stat_band_root_0d7f_count: Option<usize>,
    #[serde(default)]
    pub selected_company_stat_band_root_1c47_count: Option<usize>,
    #[serde(default)]
    pub selected_company_last_dividend_year: Option<u32>,
    #[serde(default)]
    pub selected_company_years_since_founding: Option<u32>,
    #[serde(default)]
    pub selected_company_years_since_last_bankruptcy: Option<u32>,
    #[serde(default)]
    pub selected_company_years_since_last_dividend: Option<u32>,
    #[serde(default)]
    pub selected_company_current_partial_year_weight_numerator: Option<i64>,
    #[serde(default)]
    pub selected_company_current_issue_absolute_counter: Option<u32>,
    #[serde(default)]
    pub selected_company_prior_issue_absolute_counter: Option<u32>,
    #[serde(default)]
    pub selected_company_current_issue_age_absolute_counter_delta: Option<i64>,
    #[serde(default)]
    pub selected_company_chairman_bonus_year: Option<u32>,
    #[serde(default)]
    pub selected_company_chairman_bonus_amount: Option<i32>,
    #[serde(default)]
    pub player_count: Option<usize>,
    #[serde(default)]
    pub chairman_profile_count: Option<usize>,
    #[serde(default)]
    pub active_chairman_profile_count: Option<usize>,
    #[serde(default)]
    pub selected_chairman_profile_id: Option<u32>,
    #[serde(default)]
    pub linked_chairman_company_count: Option<usize>,
    #[serde(default)]
    pub company_takeover_cooldown_count: Option<usize>,
    #[serde(default)]
    pub company_merger_cooldown_count: Option<usize>,
    #[serde(default)]
    pub train_count: Option<usize>,
    #[serde(default)]
    pub active_train_count: Option<usize>,
    #[serde(default)]
    pub retired_train_count: Option<usize>,
    #[serde(default)]
    pub locomotive_catalog_count: Option<usize>,
    #[serde(default)]
    pub cargo_catalog_count: Option<usize>,
    #[serde(default)]
    pub territory_count: Option<usize>,
    #[serde(default)]
    pub company_territory_track_count: Option<usize>,
    #[serde(default)]
    pub packed_event_collection_present: Option<bool>,
    #[serde(default)]
    pub packed_event_record_count: Option<usize>,
    #[serde(default)]
    pub packed_event_decoded_record_count: Option<usize>,
    #[serde(default)]
    pub packed_event_imported_runtime_record_count: Option<usize>,
    #[serde(default)]
    pub packed_event_parity_only_record_count: Option<usize>,
    #[serde(default)]
    pub packed_event_unsupported_record_count: Option<usize>,
    #[serde(default)]
    pub packed_event_blocked_missing_company_context_count: Option<usize>,
    #[serde(default)]
    pub packed_event_blocked_missing_selection_context_count: Option<usize>,
    #[serde(default)]
    pub packed_event_blocked_missing_company_role_context_count: Option<usize>,
    #[serde(default)]
    pub packed_event_blocked_missing_player_context_count: Option<usize>,
    #[serde(default)]
    pub packed_event_blocked_missing_player_selection_context_count: Option<usize>,
    #[serde(default)]
    pub packed_event_blocked_missing_player_role_context_count: Option<usize>,
    #[serde(default)]
    pub packed_event_blocked_missing_chairman_context_count: Option<usize>,
    #[serde(default)]
    pub packed_event_blocked_chairman_target_scope_count: Option<usize>,
    #[serde(default)]
    pub packed_event_blocked_missing_condition_context_count: Option<usize>,
    #[serde(default)]
    pub packed_event_blocked_missing_player_condition_context_count: Option<usize>,
    #[serde(default)]
    pub packed_event_blocked_company_condition_scope_disabled_count: Option<usize>,
    #[serde(default)]
    pub packed_event_blocked_player_condition_scope_count: Option<usize>,
    #[serde(default)]
    pub packed_event_blocked_territory_condition_scope_count: Option<usize>,
    #[serde(default)]
    pub packed_event_blocked_missing_territory_context_count: Option<usize>,
    #[serde(default)]
    pub packed_event_blocked_named_territory_binding_count: Option<usize>,
    #[serde(default)]
    pub packed_event_blocked_unmapped_ordinary_condition_count: Option<usize>,
    #[serde(default)]
    pub packed_event_blocked_unmapped_world_condition_count: Option<usize>,
    #[serde(default)]
    pub packed_event_blocked_missing_compact_control_count: Option<usize>,
    #[serde(default)]
    pub packed_event_blocked_shell_owned_descriptor_count: Option<usize>,
    #[serde(default)]
    pub packed_event_blocked_evidence_blocked_descriptor_count: Option<usize>,
    #[serde(default)]
    pub packed_event_blocked_variant_or_scope_blocked_descriptor_count: Option<usize>,
    #[serde(default)]
    pub packed_event_blocked_unmapped_real_descriptor_count: Option<usize>,
    #[serde(default)]
    pub packed_event_blocked_unmapped_world_descriptor_count: Option<usize>,
    #[serde(default)]
    pub packed_event_blocked_territory_access_variant_count: Option<usize>,
    #[serde(default)]
    pub packed_event_blocked_territory_access_scope_count: Option<usize>,
    #[serde(default)]
    pub packed_event_blocked_missing_train_context_count: Option<usize>,
    #[serde(default)]
    pub packed_event_blocked_missing_train_territory_context_count: Option<usize>,
    #[serde(default)]
    pub packed_event_blocked_missing_locomotive_catalog_context_count: Option<usize>,
    #[serde(default)]
    pub packed_event_blocked_confiscation_variant_count: Option<usize>,
    #[serde(default)]
    pub packed_event_blocked_retire_train_variant_count: Option<usize>,
    #[serde(default)]
    pub packed_event_blocked_retire_train_scope_count: Option<usize>,
    #[serde(default)]
    pub packed_event_blocked_structural_only_count: Option<usize>,
    #[serde(default)]
    pub event_runtime_record_count: Option<usize>,
    #[serde(default)]
    pub candidate_availability_count: Option<usize>,
    #[serde(default)]
    pub zero_candidate_availability_count: Option<usize>,
    #[serde(default)]
    pub named_locomotive_availability_count: Option<usize>,
    #[serde(default)]
    pub zero_named_locomotive_availability_count: Option<usize>,
    #[serde(default)]
    pub named_locomotive_cost_count: Option<usize>,
    #[serde(default)]
    pub cargo_production_override_count: Option<usize>,
    #[serde(default)]
    pub world_runtime_variable_count: Option<usize>,
    #[serde(default)]
    pub company_runtime_variable_owner_count: Option<usize>,
    #[serde(default)]
    pub player_runtime_variable_owner_count: Option<usize>,
    #[serde(default)]
    pub territory_runtime_variable_owner_count: Option<usize>,
    #[serde(default)]
    pub world_scalar_override_count: Option<usize>,
    #[serde(default)]
    pub special_condition_count: Option<usize>,
    #[serde(default)]
    pub enabled_special_condition_count: Option<usize>,
    #[serde(default)]
    pub save_profile_kind: Option<String>,
    #[serde(default)]
    pub save_profile_family: Option<String>,
    #[serde(default)]
    pub save_profile_map_path: Option<String>,
    #[serde(default)]
    pub save_profile_display_name: Option<String>,
    #[serde(default)]
    pub save_profile_selected_year_profile_lane: Option<u8>,
    #[serde(default)]
    pub save_profile_sandbox_enabled: Option<bool>,
    #[serde(default)]
    pub save_profile_campaign_scenario_enabled: Option<bool>,
    #[serde(default)]
    pub save_profile_staged_profile_copy_on_restore: Option<bool>,
    #[serde(default)]
    pub total_event_record_service_count: Option<u64>,
    #[serde(default)]
    pub periodic_boundary_call_count: Option<u64>,
    #[serde(default)]
    pub total_trigger_dispatch_count: Option<u64>,
    #[serde(default)]
    pub dirty_rerun_count: Option<u64>,
    #[serde(default)]
    pub total_company_cash: Option<i64>,
}

impl ExpectedRuntimeSummary {
    pub fn compare(&self, actual: &RuntimeSummary) -> Vec<String> {
        let mut mismatches = Vec::new();

        if let Some(calendar) = self.calendar {
            if actual.calendar != calendar {
                mismatches.push(format!(
                    "calendar mismatch: expected {:?}, got {:?}",
                    calendar, actual.calendar
                ));
            }
        }
        if let Some(source) = &self.calendar_projection_source {
            if actual.calendar_projection_source.as_ref() != Some(source) {
                mismatches.push(format!(
                    "calendar_projection_source mismatch: expected {source:?}, got {:?}",
                    actual.calendar_projection_source
                ));
            }
        }
        if let Some(is_placeholder) = self.calendar_projection_is_placeholder {
            if actual.calendar_projection_is_placeholder != is_placeholder {
                mismatches.push(format!(
                    "calendar_projection_is_placeholder mismatch: expected {is_placeholder}, got {}",
                    actual.calendar_projection_is_placeholder
                ));
            }
        }
        if let Some(count) = self.world_flag_count {
            if actual.world_flag_count != count {
                mismatches.push(format!(
                    "world_flag_count mismatch: expected {count}, got {}",
                    actual.world_flag_count
                ));
            }
        }
        if let Some(lane) = self.world_restore_selected_year_profile_lane {
            if actual.world_restore_selected_year_profile_lane != Some(lane) {
                mismatches.push(format!(
                    "world_restore_selected_year_profile_lane mismatch: expected {lane}, got {:?}",
                    actual.world_restore_selected_year_profile_lane
                ));
            }
        }
        if let Some(enabled) = self.world_restore_campaign_scenario_enabled {
            if actual.world_restore_campaign_scenario_enabled != Some(enabled) {
                mismatches.push(format!(
                    "world_restore_campaign_scenario_enabled mismatch: expected {enabled}, got {:?}",
                    actual.world_restore_campaign_scenario_enabled
                ));
            }
        }
        if let Some(enabled) = self.world_restore_sandbox_enabled {
            if actual.world_restore_sandbox_enabled != Some(enabled) {
                mismatches.push(format!(
                    "world_restore_sandbox_enabled mismatch: expected {enabled}, got {:?}",
                    actual.world_restore_sandbox_enabled
                ));
            }
        }
        if let Some(enabled) = self.world_restore_seed_tuple_written_from_raw_lane {
            if actual.world_restore_seed_tuple_written_from_raw_lane != Some(enabled) {
                mismatches.push(format!(
                    "world_restore_seed_tuple_written_from_raw_lane mismatch: expected {enabled}, got {:?}",
                    actual.world_restore_seed_tuple_written_from_raw_lane
                ));
            }
        }
        if let Some(enabled) = self.world_restore_absolute_counter_requires_shell_context {
            if actual.world_restore_absolute_counter_requires_shell_context != Some(enabled) {
                mismatches.push(format!(
                    "world_restore_absolute_counter_requires_shell_context mismatch: expected {enabled}, got {:?}",
                    actual.world_restore_absolute_counter_requires_shell_context
                ));
            }
        }
        if let Some(enabled) = self.world_restore_absolute_counter_reconstructible_from_save {
            if actual.world_restore_absolute_counter_reconstructible_from_save != Some(enabled) {
                mismatches.push(format!(
                    "world_restore_absolute_counter_reconstructible_from_save mismatch: expected {enabled}, got {:?}",
                    actual.world_restore_absolute_counter_reconstructible_from_save
                ));
            }
        }
        if let Some(value) = self.world_restore_packed_year_word_raw_u16 {
            if actual.world_restore_packed_year_word_raw_u16 != Some(value) {
                mismatches.push(format!(
                    "world_restore_packed_year_word_raw_u16 mismatch: expected {value}, got {:?}",
                    actual.world_restore_packed_year_word_raw_u16
                ));
            }
        }
        if let Some(value) = self.world_restore_partial_year_progress_raw_u8 {
            if actual.world_restore_partial_year_progress_raw_u8 != Some(value) {
                mismatches.push(format!(
                    "world_restore_partial_year_progress_raw_u8 mismatch: expected {value}, got {:?}",
                    actual.world_restore_partial_year_progress_raw_u8
                ));
            }
        }
        if let Some(value) = self.world_restore_current_calendar_tuple_word_raw_u32 {
            if actual.world_restore_current_calendar_tuple_word_raw_u32 != Some(value) {
                mismatches.push(format!(
                    "world_restore_current_calendar_tuple_word_raw_u32 mismatch: expected {value}, got {:?}",
                    actual.world_restore_current_calendar_tuple_word_raw_u32
                ));
            }
        }
        if let Some(value) = self.world_restore_current_calendar_tuple_word_2_raw_u32 {
            if actual.world_restore_current_calendar_tuple_word_2_raw_u32 != Some(value) {
                mismatches.push(format!(
                    "world_restore_current_calendar_tuple_word_2_raw_u32 mismatch: expected {value}, got {:?}",
                    actual.world_restore_current_calendar_tuple_word_2_raw_u32
                ));
            }
        }
        if let Some(value) = self.world_restore_absolute_counter_raw_u32 {
            if actual.world_restore_absolute_counter_raw_u32 != Some(value) {
                mismatches.push(format!(
                    "world_restore_absolute_counter_raw_u32 mismatch: expected {value}, got {:?}",
                    actual.world_restore_absolute_counter_raw_u32
                ));
            }
        }
        if let Some(value) = self.world_restore_absolute_counter_mirror_raw_u32 {
            if actual.world_restore_absolute_counter_mirror_raw_u32 != Some(value) {
                mismatches.push(format!(
                    "world_restore_absolute_counter_mirror_raw_u32 mismatch: expected {value}, got {:?}",
                    actual.world_restore_absolute_counter_mirror_raw_u32
                ));
            }
        }
        if let Some(slot) = self.world_restore_disable_cargo_economy_special_condition_slot {
            if actual.world_restore_disable_cargo_economy_special_condition_slot != Some(slot) {
                mismatches.push(format!(
                    "world_restore_disable_cargo_economy_special_condition_slot mismatch: expected {slot}, got {:?}",
                    actual.world_restore_disable_cargo_economy_special_condition_slot
                ));
            }
        }
        if let Some(enabled) =
            self.world_restore_disable_cargo_economy_special_condition_reconstructible_from_save
        {
            if actual
                .world_restore_disable_cargo_economy_special_condition_reconstructible_from_save
                != Some(enabled)
            {
                mismatches.push(format!(
                    "world_restore_disable_cargo_economy_special_condition_reconstructible_from_save mismatch: expected {enabled}, got {:?}",
                    actual.world_restore_disable_cargo_economy_special_condition_reconstructible_from_save
                ));
            }
        }
        if let Some(enabled) =
            self.world_restore_disable_cargo_economy_special_condition_write_side_grounded
        {
            if actual.world_restore_disable_cargo_economy_special_condition_write_side_grounded
                != Some(enabled)
            {
                mismatches.push(format!(
                    "world_restore_disable_cargo_economy_special_condition_write_side_grounded mismatch: expected {enabled}, got {:?}",
                    actual.world_restore_disable_cargo_economy_special_condition_write_side_grounded
                ));
            }
        }
        if let Some(enabled) = self.world_restore_disable_cargo_economy_special_condition_enabled {
            if actual.world_restore_disable_cargo_economy_special_condition_enabled != Some(enabled)
            {
                mismatches.push(format!(
                    "world_restore_disable_cargo_economy_special_condition_enabled mismatch: expected {enabled}, got {:?}",
                    actual.world_restore_disable_cargo_economy_special_condition_enabled
                ));
            }
        }
        if let Some(enabled) = self.world_restore_use_bio_accelerator_cars_enabled {
            if actual.world_restore_use_bio_accelerator_cars_enabled != Some(enabled) {
                mismatches.push(format!(
                    "world_restore_use_bio_accelerator_cars_enabled mismatch: expected {enabled}, got {:?}",
                    actual.world_restore_use_bio_accelerator_cars_enabled
                ));
            }
        }
        if let Some(enabled) = self.world_restore_use_wartime_cargos_enabled {
            if actual.world_restore_use_wartime_cargos_enabled != Some(enabled) {
                mismatches.push(format!(
                    "world_restore_use_wartime_cargos_enabled mismatch: expected {enabled}, got {:?}",
                    actual.world_restore_use_wartime_cargos_enabled
                ));
            }
        }
        if let Some(enabled) = self.world_restore_disable_train_crashes_enabled {
            if actual.world_restore_disable_train_crashes_enabled != Some(enabled) {
                mismatches.push(format!(
                    "world_restore_disable_train_crashes_enabled mismatch: expected {enabled}, got {:?}",
                    actual.world_restore_disable_train_crashes_enabled
                ));
            }
        }
        if let Some(enabled) = self.world_restore_disable_train_crashes_and_breakdowns_enabled {
            if actual.world_restore_disable_train_crashes_and_breakdowns_enabled != Some(enabled) {
                mismatches.push(format!(
                    "world_restore_disable_train_crashes_and_breakdowns_enabled mismatch: expected {enabled}, got {:?}",
                    actual.world_restore_disable_train_crashes_and_breakdowns_enabled
                ));
            }
        }
        if let Some(enabled) = self.world_restore_ai_ignore_territories_at_startup_enabled {
            if actual.world_restore_ai_ignore_territories_at_startup_enabled != Some(enabled) {
                mismatches.push(format!(
                    "world_restore_ai_ignore_territories_at_startup_enabled mismatch: expected {enabled}, got {:?}",
                    actual.world_restore_ai_ignore_territories_at_startup_enabled
                ));
            }
        }
        if let Some(value) = self.world_restore_limited_track_building_amount {
            if actual.world_restore_limited_track_building_amount != Some(value) {
                mismatches.push(format!(
                    "world_restore_limited_track_building_amount mismatch: expected {value}, got {:?}",
                    actual.world_restore_limited_track_building_amount
                ));
            }
        }
        if let Some(code) = self.world_restore_economic_status_code {
            if actual.world_restore_economic_status_code != Some(code) {
                mismatches.push(format!(
                    "world_restore_economic_status_code mismatch: expected {code}, got {:?}",
                    actual.world_restore_economic_status_code
                ));
            }
        }
        if let Some(value) = self.world_restore_territory_access_cost {
            if actual.world_restore_territory_access_cost != Some(value) {
                mismatches.push(format!(
                    "world_restore_territory_access_cost mismatch: expected {value}, got {:?}",
                    actual.world_restore_territory_access_cost
                ));
            }
        }
        if let Some(value) = self.world_restore_issue_37_value {
            if actual.world_restore_issue_37_value != Some(value) {
                mismatches.push(format!(
                    "world_restore_issue_37_value mismatch: expected {value}, got {:?}",
                    actual.world_restore_issue_37_value
                ));
            }
        }
        if let Some(value) = self.world_restore_issue_38_value {
            if actual.world_restore_issue_38_value != Some(value) {
                mismatches.push(format!(
                    "world_restore_issue_38_value mismatch: expected {value}, got {:?}",
                    actual.world_restore_issue_38_value
                ));
            }
        }
        if let Some(value) = self.world_restore_issue_39_value {
            if actual.world_restore_issue_39_value != Some(value) {
                mismatches.push(format!(
                    "world_restore_issue_39_value mismatch: expected {value}, got {:?}",
                    actual.world_restore_issue_39_value
                ));
            }
        }
        if let Some(value) = self.world_restore_issue_3a_value {
            if actual.world_restore_issue_3a_value != Some(value) {
                mismatches.push(format!(
                    "world_restore_issue_3a_value mismatch: expected {value}, got {:?}",
                    actual.world_restore_issue_3a_value
                ));
            }
        }
        if let Some(value) = self.world_restore_issue_37_multiplier_raw_u32 {
            if actual.world_restore_issue_37_multiplier_raw_u32 != Some(value) {
                mismatches.push(format!(
                    "world_restore_issue_37_multiplier_raw_u32 mismatch: expected {value}, got {:?}",
                    actual.world_restore_issue_37_multiplier_raw_u32
                ));
            }
        }
        if let Some(value) = &self.world_restore_issue_37_multiplier_value_f32_text {
            if actual
                .world_restore_issue_37_multiplier_value_f32_text
                .as_ref()
                != Some(value)
            {
                mismatches.push(format!(
                    "world_restore_issue_37_multiplier_value_f32_text mismatch: expected {value:?}, got {:?}",
                    actual.world_restore_issue_37_multiplier_value_f32_text
                ));
            }
        }
        if let Some(count) = self.world_restore_finance_neighborhood_count {
            if actual.world_restore_finance_neighborhood_count != count {
                mismatches.push(format!(
                    "world_restore_finance_neighborhood_count mismatch: expected {count}, got {}",
                    actual.world_restore_finance_neighborhood_count
                ));
            }
        }
        if let Some(labels) = &self.world_restore_finance_neighborhood_labels {
            if &actual.world_restore_finance_neighborhood_labels != labels {
                mismatches.push(format!(
                    "world_restore_finance_neighborhood_labels mismatch: expected {labels:?}, got {:?}",
                    actual.world_restore_finance_neighborhood_labels
                ));
            }
        }
        if let Some(value) = self.world_restore_economic_tuning_mirror_raw_u32 {
            if actual.world_restore_economic_tuning_mirror_raw_u32 != Some(value) {
                mismatches.push(format!(
                    "world_restore_economic_tuning_mirror_raw_u32 mismatch: expected {value}, got {:?}",
                    actual.world_restore_economic_tuning_mirror_raw_u32
                ));
            }
        }
        if let Some(value) = &self.world_restore_economic_tuning_mirror_value_f32_text {
            if actual
                .world_restore_economic_tuning_mirror_value_f32_text
                .as_ref()
                != Some(value)
            {
                mismatches.push(format!(
                    "world_restore_economic_tuning_mirror_value_f32_text mismatch: expected {value:?}, got {:?}",
                    actual.world_restore_economic_tuning_mirror_value_f32_text
                ));
            }
        }
        if let Some(count) = self.world_restore_economic_tuning_lane_count {
            if actual.world_restore_economic_tuning_lane_count != count {
                mismatches.push(format!(
                    "world_restore_economic_tuning_lane_count mismatch: expected {count}, got {}",
                    actual.world_restore_economic_tuning_lane_count
                ));
            }
        }
        if let Some(values) = &self.world_restore_economic_tuning_lane_value_f32_text {
            if &actual.world_restore_economic_tuning_lane_value_f32_text != values {
                mismatches.push(format!(
                    "world_restore_economic_tuning_lane_value_f32_text mismatch: expected {values:?}, got {:?}",
                    actual.world_restore_economic_tuning_lane_value_f32_text
                ));
            }
        }
        if let Some(kind) = &self.world_restore_absolute_counter_restore_kind {
            if actual.world_restore_absolute_counter_restore_kind.as_ref() != Some(kind) {
                mismatches.push(format!(
                    "world_restore_absolute_counter_restore_kind mismatch: expected {kind:?}, got {:?}",
                    actual.world_restore_absolute_counter_restore_kind
                ));
            }
        }
        if let Some(context) = &self.world_restore_absolute_counter_adjustment_context {
            if actual
                .world_restore_absolute_counter_adjustment_context
                .as_ref()
                != Some(context)
            {
                mismatches.push(format!(
                    "world_restore_absolute_counter_adjustment_context mismatch: expected {context:?}, got {:?}",
                    actual.world_restore_absolute_counter_adjustment_context
                ));
            }
        }
        if let Some(count) = self.metadata_count {
            if actual.metadata_count != count {
                mismatches.push(format!(
                    "metadata_count mismatch: expected {count}, got {}",
                    actual.metadata_count
                ));
            }
        }
        if let Some(count) = self.company_count {
            if actual.company_count != count {
                mismatches.push(format!(
                    "company_count mismatch: expected {count}, got {}",
                    actual.company_count
                ));
            }
        }
        if let Some(count) = self.active_company_count {
            if actual.active_company_count != count {
                mismatches.push(format!(
                    "active_company_count mismatch: expected {count}, got {}",
                    actual.active_company_count
                ));
            }
        }
        if let Some(count) = self.company_market_state_owner_count {
            if actual.company_market_state_owner_count != count {
                mismatches.push(format!(
                    "company_market_state_owner_count mismatch: expected {count}, got {}",
                    actual.company_market_state_owner_count
                ));
            }
        }
        if let Some(value) = self.selected_company_outstanding_shares {
            if actual.selected_company_outstanding_shares != Some(value) {
                mismatches.push(format!(
                    "selected_company_outstanding_shares mismatch: expected {value}, got {:?}",
                    actual.selected_company_outstanding_shares
                ));
            }
        }
        if let Some(value) = self.selected_company_bond_count {
            if actual.selected_company_bond_count != Some(value) {
                mismatches.push(format!(
                    "selected_company_bond_count mismatch: expected {value}, got {:?}",
                    actual.selected_company_bond_count
                ));
            }
        }
        if let Some(value) = self.selected_company_largest_live_bond_principal {
            if actual.selected_company_largest_live_bond_principal != Some(value) {
                mismatches.push(format!(
                    "selected_company_largest_live_bond_principal mismatch: expected {value}, got {:?}",
                    actual.selected_company_largest_live_bond_principal
                ));
            }
        }
        if let Some(value) = self.selected_company_highest_coupon_live_bond_principal {
            if actual.selected_company_highest_coupon_live_bond_principal != Some(value) {
                mismatches.push(format!(
                    "selected_company_highest_coupon_live_bond_principal mismatch: expected {value}, got {:?}",
                    actual.selected_company_highest_coupon_live_bond_principal
                ));
            }
        }
        if let Some(value) = self.selected_company_assigned_share_pool {
            if actual.selected_company_assigned_share_pool != Some(value) {
                mismatches.push(format!(
                    "selected_company_assigned_share_pool mismatch: expected {value}, got {:?}",
                    actual.selected_company_assigned_share_pool
                ));
            }
        }
        if let Some(value) = self.selected_company_unassigned_share_pool {
            if actual.selected_company_unassigned_share_pool != Some(value) {
                mismatches.push(format!(
                    "selected_company_unassigned_share_pool mismatch: expected {value}, got {:?}",
                    actual.selected_company_unassigned_share_pool
                ));
            }
        }
        if let Some(value) = self.selected_company_cached_share_price {
            if actual.selected_company_cached_share_price != Some(value) {
                mismatches.push(format!(
                    "selected_company_cached_share_price mismatch: expected {value}, got {:?}",
                    actual.selected_company_cached_share_price
                ));
            }
        }
        if let Some(value) = &self.selected_company_cached_share_price_value_f32_text {
            if actual
                .selected_company_cached_share_price_value_f32_text
                .as_ref()
                != Some(value)
            {
                mismatches.push(format!(
                    "selected_company_cached_share_price_value_f32_text mismatch: expected {value:?}, got {:?}",
                    actual.selected_company_cached_share_price_value_f32_text
                ));
            }
        }
        if let Some(value) = &self.selected_company_mutable_support_scalar_value_f32_text {
            if actual
                .selected_company_mutable_support_scalar_value_f32_text
                .as_ref()
                != Some(value)
            {
                mismatches.push(format!(
                    "selected_company_mutable_support_scalar_value_f32_text mismatch: expected {value:?}, got {:?}",
                    actual.selected_company_mutable_support_scalar_value_f32_text
                ));
            }
        }
        if let Some(count) = self.selected_company_stat_band_root_0cfb_count {
            if actual.selected_company_stat_band_root_0cfb_count != count {
                mismatches.push(format!(
                    "selected_company_stat_band_root_0cfb_count mismatch: expected {count}, got {}",
                    actual.selected_company_stat_band_root_0cfb_count
                ));
            }
        }
        if let Some(count) = self.selected_company_stat_band_root_0d7f_count {
            if actual.selected_company_stat_band_root_0d7f_count != count {
                mismatches.push(format!(
                    "selected_company_stat_band_root_0d7f_count mismatch: expected {count}, got {}",
                    actual.selected_company_stat_band_root_0d7f_count
                ));
            }
        }
        if let Some(count) = self.selected_company_stat_band_root_1c47_count {
            if actual.selected_company_stat_band_root_1c47_count != count {
                mismatches.push(format!(
                    "selected_company_stat_band_root_1c47_count mismatch: expected {count}, got {}",
                    actual.selected_company_stat_band_root_1c47_count
                ));
            }
        }
        if let Some(value) = self.selected_company_last_dividend_year {
            if actual.selected_company_last_dividend_year != Some(value) {
                mismatches.push(format!(
                    "selected_company_last_dividend_year mismatch: expected {value}, got {:?}",
                    actual.selected_company_last_dividend_year
                ));
            }
        }
        if let Some(value) = self.selected_company_years_since_founding {
            if actual.selected_company_years_since_founding != Some(value) {
                mismatches.push(format!(
                    "selected_company_years_since_founding mismatch: expected {value}, got {:?}",
                    actual.selected_company_years_since_founding
                ));
            }
        }
        if let Some(value) = self.selected_company_years_since_last_bankruptcy {
            if actual.selected_company_years_since_last_bankruptcy != Some(value) {
                mismatches.push(format!(
                    "selected_company_years_since_last_bankruptcy mismatch: expected {value}, got {:?}",
                    actual.selected_company_years_since_last_bankruptcy
                ));
            }
        }
        if let Some(value) = self.selected_company_years_since_last_dividend {
            if actual.selected_company_years_since_last_dividend != Some(value) {
                mismatches.push(format!(
                    "selected_company_years_since_last_dividend mismatch: expected {value}, got {:?}",
                    actual.selected_company_years_since_last_dividend
                ));
            }
        }
        if let Some(value) = self.selected_company_current_partial_year_weight_numerator {
            if actual.selected_company_current_partial_year_weight_numerator != Some(value) {
                mismatches.push(format!(
                    "selected_company_current_partial_year_weight_numerator mismatch: expected {value}, got {:?}",
                    actual.selected_company_current_partial_year_weight_numerator
                ));
            }
        }
        if let Some(value) = self.selected_company_current_issue_absolute_counter {
            if actual.selected_company_current_issue_absolute_counter != Some(value) {
                mismatches.push(format!(
                    "selected_company_current_issue_absolute_counter mismatch: expected {value}, got {:?}",
                    actual.selected_company_current_issue_absolute_counter
                ));
            }
        }
        if let Some(value) = self.selected_company_prior_issue_absolute_counter {
            if actual.selected_company_prior_issue_absolute_counter != Some(value) {
                mismatches.push(format!(
                    "selected_company_prior_issue_absolute_counter mismatch: expected {value}, got {:?}",
                    actual.selected_company_prior_issue_absolute_counter
                ));
            }
        }
        if let Some(value) = self.selected_company_current_issue_age_absolute_counter_delta {
            if actual.selected_company_current_issue_age_absolute_counter_delta != Some(value) {
                mismatches.push(format!(
                    "selected_company_current_issue_age_absolute_counter_delta mismatch: expected {value}, got {:?}",
                    actual.selected_company_current_issue_age_absolute_counter_delta
                ));
            }
        }
        if let Some(value) = self.selected_company_chairman_bonus_year {
            if actual.selected_company_chairman_bonus_year != Some(value) {
                mismatches.push(format!(
                    "selected_company_chairman_bonus_year mismatch: expected {value}, got {:?}",
                    actual.selected_company_chairman_bonus_year
                ));
            }
        }
        if let Some(value) = self.selected_company_chairman_bonus_amount {
            if actual.selected_company_chairman_bonus_amount != Some(value) {
                mismatches.push(format!(
                    "selected_company_chairman_bonus_amount mismatch: expected {value}, got {:?}",
                    actual.selected_company_chairman_bonus_amount
                ));
            }
        }
        if let Some(count) = self.player_count {
            if actual.player_count != count {
                mismatches.push(format!(
                    "player_count mismatch: expected {count}, got {}",
                    actual.player_count
                ));
            }
        }
        if let Some(count) = self.chairman_profile_count {
            if actual.chairman_profile_count != count {
                mismatches.push(format!(
                    "chairman_profile_count mismatch: expected {count}, got {}",
                    actual.chairman_profile_count
                ));
            }
        }
        if let Some(count) = self.active_chairman_profile_count {
            if actual.active_chairman_profile_count != count {
                mismatches.push(format!(
                    "active_chairman_profile_count mismatch: expected {count}, got {}",
                    actual.active_chairman_profile_count
                ));
            }
        }
        if let Some(selected_id) = self.selected_chairman_profile_id {
            if actual.selected_chairman_profile_id != Some(selected_id) {
                mismatches.push(format!(
                    "selected_chairman_profile_id mismatch: expected {selected_id:?}, got {:?}",
                    actual.selected_chairman_profile_id
                ));
            }
        }
        if let Some(count) = self.linked_chairman_company_count {
            if actual.linked_chairman_company_count != count {
                mismatches.push(format!(
                    "linked_chairman_company_count mismatch: expected {count}, got {}",
                    actual.linked_chairman_company_count
                ));
            }
        }
        if let Some(count) = self.company_takeover_cooldown_count {
            if actual.company_takeover_cooldown_count != count {
                mismatches.push(format!(
                    "company_takeover_cooldown_count mismatch: expected {count}, got {}",
                    actual.company_takeover_cooldown_count
                ));
            }
        }
        if let Some(count) = self.company_merger_cooldown_count {
            if actual.company_merger_cooldown_count != count {
                mismatches.push(format!(
                    "company_merger_cooldown_count mismatch: expected {count}, got {}",
                    actual.company_merger_cooldown_count
                ));
            }
        }
        if let Some(count) = self.train_count {
            if actual.train_count != count {
                mismatches.push(format!(
                    "train_count mismatch: expected {count}, got {}",
                    actual.train_count
                ));
            }
        }
        if let Some(count) = self.active_train_count {
            if actual.active_train_count != count {
                mismatches.push(format!(
                    "active_train_count mismatch: expected {count}, got {}",
                    actual.active_train_count
                ));
            }
        }
        if let Some(count) = self.retired_train_count {
            if actual.retired_train_count != count {
                mismatches.push(format!(
                    "retired_train_count mismatch: expected {count}, got {}",
                    actual.retired_train_count
                ));
            }
        }
        if let Some(count) = self.locomotive_catalog_count {
            if actual.locomotive_catalog_count != count {
                mismatches.push(format!(
                    "locomotive_catalog_count mismatch: expected {count}, got {}",
                    actual.locomotive_catalog_count
                ));
            }
        }
        if let Some(count) = self.cargo_catalog_count {
            if actual.cargo_catalog_count != count {
                mismatches.push(format!(
                    "cargo_catalog_count mismatch: expected {count}, got {}",
                    actual.cargo_catalog_count
                ));
            }
        }
        if let Some(count) = self.territory_count {
            if actual.territory_count != count {
                mismatches.push(format!(
                    "territory_count mismatch: expected {count}, got {}",
                    actual.territory_count
                ));
            }
        }
        if let Some(count) = self.company_territory_track_count {
            if actual.company_territory_track_count != count {
                mismatches.push(format!(
                    "company_territory_track_count mismatch: expected {count}, got {}",
                    actual.company_territory_track_count
                ));
            }
        }
        if let Some(present) = self.packed_event_collection_present {
            if actual.packed_event_collection_present != present {
                mismatches.push(format!(
                    "packed_event_collection_present mismatch: expected {present}, got {}",
                    actual.packed_event_collection_present
                ));
            }
        }
        if let Some(count) = self.packed_event_record_count {
            if actual.packed_event_record_count != count {
                mismatches.push(format!(
                    "packed_event_record_count mismatch: expected {count}, got {}",
                    actual.packed_event_record_count
                ));
            }
        }
        if let Some(count) = self.packed_event_decoded_record_count {
            if actual.packed_event_decoded_record_count != count {
                mismatches.push(format!(
                    "packed_event_decoded_record_count mismatch: expected {count}, got {}",
                    actual.packed_event_decoded_record_count
                ));
            }
        }
        if let Some(count) = self.packed_event_imported_runtime_record_count {
            if actual.packed_event_imported_runtime_record_count != count {
                mismatches.push(format!(
                    "packed_event_imported_runtime_record_count mismatch: expected {count}, got {}",
                    actual.packed_event_imported_runtime_record_count
                ));
            }
        }
        if let Some(count) = self.packed_event_parity_only_record_count {
            if actual.packed_event_parity_only_record_count != count {
                mismatches.push(format!(
                    "packed_event_parity_only_record_count mismatch: expected {count}, got {}",
                    actual.packed_event_parity_only_record_count
                ));
            }
        }
        if let Some(count) = self.packed_event_unsupported_record_count {
            if actual.packed_event_unsupported_record_count != count {
                mismatches.push(format!(
                    "packed_event_unsupported_record_count mismatch: expected {count}, got {}",
                    actual.packed_event_unsupported_record_count
                ));
            }
        }
        if let Some(count) = self.packed_event_blocked_missing_company_context_count {
            if actual.packed_event_blocked_missing_company_context_count != count {
                mismatches.push(format!(
                    "packed_event_blocked_missing_company_context_count mismatch: expected {count}, got {}",
                    actual.packed_event_blocked_missing_company_context_count
                ));
            }
        }
        if let Some(count) = self.packed_event_blocked_missing_selection_context_count {
            if actual.packed_event_blocked_missing_selection_context_count != count {
                mismatches.push(format!(
                    "packed_event_blocked_missing_selection_context_count mismatch: expected {count}, got {}",
                    actual.packed_event_blocked_missing_selection_context_count
                ));
            }
        }
        if let Some(count) = self.packed_event_blocked_missing_company_role_context_count {
            if actual.packed_event_blocked_missing_company_role_context_count != count {
                mismatches.push(format!(
                    "packed_event_blocked_missing_company_role_context_count mismatch: expected {count}, got {}",
                    actual.packed_event_blocked_missing_company_role_context_count
                ));
            }
        }
        if let Some(count) = self.packed_event_blocked_missing_player_context_count {
            if actual.packed_event_blocked_missing_player_context_count != count {
                mismatches.push(format!(
                    "packed_event_blocked_missing_player_context_count mismatch: expected {count}, got {}",
                    actual.packed_event_blocked_missing_player_context_count
                ));
            }
        }
        if let Some(count) = self.packed_event_blocked_missing_player_selection_context_count {
            if actual.packed_event_blocked_missing_player_selection_context_count != count {
                mismatches.push(format!(
                    "packed_event_blocked_missing_player_selection_context_count mismatch: expected {count}, got {}",
                    actual.packed_event_blocked_missing_player_selection_context_count
                ));
            }
        }
        if let Some(count) = self.packed_event_blocked_missing_player_role_context_count {
            if actual.packed_event_blocked_missing_player_role_context_count != count {
                mismatches.push(format!(
                    "packed_event_blocked_missing_player_role_context_count mismatch: expected {count}, got {}",
                    actual.packed_event_blocked_missing_player_role_context_count
                ));
            }
        }
        if let Some(count) = self.packed_event_blocked_missing_chairman_context_count {
            if actual.packed_event_blocked_missing_chairman_context_count != count {
                mismatches.push(format!(
                    "packed_event_blocked_missing_chairman_context_count mismatch: expected {count}, got {}",
                    actual.packed_event_blocked_missing_chairman_context_count
                ));
            }
        }
        if let Some(count) = self.packed_event_blocked_chairman_target_scope_count {
            if actual.packed_event_blocked_chairman_target_scope_count != count {
                mismatches.push(format!(
                    "packed_event_blocked_chairman_target_scope_count mismatch: expected {count}, got {}",
                    actual.packed_event_blocked_chairman_target_scope_count
                ));
            }
        }
        if let Some(count) = self.packed_event_blocked_missing_condition_context_count {
            if actual.packed_event_blocked_missing_condition_context_count != count {
                mismatches.push(format!(
                    "packed_event_blocked_missing_condition_context_count mismatch: expected {count}, got {}",
                    actual.packed_event_blocked_missing_condition_context_count
                ));
            }
        }
        if let Some(count) = self.packed_event_blocked_missing_player_condition_context_count {
            if actual.packed_event_blocked_missing_player_condition_context_count != count {
                mismatches.push(format!(
                    "packed_event_blocked_missing_player_condition_context_count mismatch: expected {count}, got {}",
                    actual.packed_event_blocked_missing_player_condition_context_count
                ));
            }
        }
        if let Some(count) = self.packed_event_blocked_company_condition_scope_disabled_count {
            if actual.packed_event_blocked_company_condition_scope_disabled_count != count {
                mismatches.push(format!(
                    "packed_event_blocked_company_condition_scope_disabled_count mismatch: expected {count}, got {}",
                    actual.packed_event_blocked_company_condition_scope_disabled_count
                ));
            }
        }
        if let Some(count) = self.packed_event_blocked_player_condition_scope_count {
            if actual.packed_event_blocked_player_condition_scope_count != count {
                mismatches.push(format!(
                    "packed_event_blocked_player_condition_scope_count mismatch: expected {count}, got {}",
                    actual.packed_event_blocked_player_condition_scope_count
                ));
            }
        }
        if let Some(count) = self.packed_event_blocked_territory_condition_scope_count {
            if actual.packed_event_blocked_territory_condition_scope_count != count {
                mismatches.push(format!(
                    "packed_event_blocked_territory_condition_scope_count mismatch: expected {count}, got {}",
                    actual.packed_event_blocked_territory_condition_scope_count
                ));
            }
        }
        if let Some(count) = self.packed_event_blocked_missing_territory_context_count {
            if actual.packed_event_blocked_missing_territory_context_count != count {
                mismatches.push(format!(
                    "packed_event_blocked_missing_territory_context_count mismatch: expected {count}, got {}",
                    actual.packed_event_blocked_missing_territory_context_count
                ));
            }
        }
        if let Some(count) = self.packed_event_blocked_named_territory_binding_count {
            if actual.packed_event_blocked_named_territory_binding_count != count {
                mismatches.push(format!(
                    "packed_event_blocked_named_territory_binding_count mismatch: expected {count}, got {}",
                    actual.packed_event_blocked_named_territory_binding_count
                ));
            }
        }
        if let Some(count) = self.packed_event_blocked_unmapped_ordinary_condition_count {
            if actual.packed_event_blocked_unmapped_ordinary_condition_count != count {
                mismatches.push(format!(
                    "packed_event_blocked_unmapped_ordinary_condition_count mismatch: expected {count}, got {}",
                    actual.packed_event_blocked_unmapped_ordinary_condition_count
                ));
            }
        }
        if let Some(count) = self.packed_event_blocked_unmapped_world_condition_count {
            if actual.packed_event_blocked_unmapped_world_condition_count != count {
                mismatches.push(format!(
                    "packed_event_blocked_unmapped_world_condition_count mismatch: expected {count}, got {}",
                    actual.packed_event_blocked_unmapped_world_condition_count
                ));
            }
        }
        if let Some(count) = self.packed_event_blocked_missing_compact_control_count {
            if actual.packed_event_blocked_missing_compact_control_count != count {
                mismatches.push(format!(
                    "packed_event_blocked_missing_compact_control_count mismatch: expected {count}, got {}",
                    actual.packed_event_blocked_missing_compact_control_count
                ));
            }
        }
        if let Some(count) = self.packed_event_blocked_shell_owned_descriptor_count {
            if actual.packed_event_blocked_shell_owned_descriptor_count != count {
                mismatches.push(format!(
                    "packed_event_blocked_shell_owned_descriptor_count mismatch: expected {count}, got {}",
                    actual.packed_event_blocked_shell_owned_descriptor_count
                ));
            }
        }
        if let Some(count) = self.packed_event_blocked_evidence_blocked_descriptor_count {
            if actual.packed_event_blocked_evidence_blocked_descriptor_count != count {
                mismatches.push(format!(
                    "packed_event_blocked_evidence_blocked_descriptor_count mismatch: expected {count}, got {}",
                    actual.packed_event_blocked_evidence_blocked_descriptor_count
                ));
            }
        }
        if let Some(count) = self.packed_event_blocked_variant_or_scope_blocked_descriptor_count {
            if actual.packed_event_blocked_variant_or_scope_blocked_descriptor_count != count {
                mismatches.push(format!(
                    "packed_event_blocked_variant_or_scope_blocked_descriptor_count mismatch: expected {count}, got {}",
                    actual.packed_event_blocked_variant_or_scope_blocked_descriptor_count
                ));
            }
        }
        if let Some(count) = self.packed_event_blocked_unmapped_real_descriptor_count {
            if actual.packed_event_blocked_unmapped_real_descriptor_count != count {
                mismatches.push(format!(
                    "packed_event_blocked_unmapped_real_descriptor_count mismatch: expected {count}, got {}",
                    actual.packed_event_blocked_unmapped_real_descriptor_count
                ));
            }
        }
        if let Some(count) = self.packed_event_blocked_unmapped_world_descriptor_count {
            if actual.packed_event_blocked_unmapped_world_descriptor_count != count {
                mismatches.push(format!(
                    "packed_event_blocked_unmapped_world_descriptor_count mismatch: expected {count}, got {}",
                    actual.packed_event_blocked_unmapped_world_descriptor_count
                ));
            }
        }
        if let Some(count) = self.packed_event_blocked_territory_access_variant_count {
            if actual.packed_event_blocked_territory_access_variant_count != count {
                mismatches.push(format!(
                    "packed_event_blocked_territory_access_variant_count mismatch: expected {count}, got {}",
                    actual.packed_event_blocked_territory_access_variant_count
                ));
            }
        }
        if let Some(count) = self.packed_event_blocked_territory_access_scope_count {
            if actual.packed_event_blocked_territory_access_scope_count != count {
                mismatches.push(format!(
                    "packed_event_blocked_territory_access_scope_count mismatch: expected {count}, got {}",
                    actual.packed_event_blocked_territory_access_scope_count
                ));
            }
        }
        if let Some(count) = self.packed_event_blocked_missing_train_context_count {
            if actual.packed_event_blocked_missing_train_context_count != count {
                mismatches.push(format!(
                    "packed_event_blocked_missing_train_context_count mismatch: expected {count}, got {}",
                    actual.packed_event_blocked_missing_train_context_count
                ));
            }
        }
        if let Some(count) = self.packed_event_blocked_missing_train_territory_context_count {
            if actual.packed_event_blocked_missing_train_territory_context_count != count {
                mismatches.push(format!(
                    "packed_event_blocked_missing_train_territory_context_count mismatch: expected {count}, got {}",
                    actual.packed_event_blocked_missing_train_territory_context_count
                ));
            }
        }
        if let Some(count) = self.packed_event_blocked_missing_locomotive_catalog_context_count {
            if actual.packed_event_blocked_missing_locomotive_catalog_context_count != count {
                mismatches.push(format!(
                    "packed_event_blocked_missing_locomotive_catalog_context_count mismatch: expected {count}, got {}",
                    actual.packed_event_blocked_missing_locomotive_catalog_context_count
                ));
            }
        }
        if let Some(count) = self.packed_event_blocked_confiscation_variant_count {
            if actual.packed_event_blocked_confiscation_variant_count != count {
                mismatches.push(format!(
                    "packed_event_blocked_confiscation_variant_count mismatch: expected {count}, got {}",
                    actual.packed_event_blocked_confiscation_variant_count
                ));
            }
        }
        if let Some(count) = self.packed_event_blocked_retire_train_variant_count {
            if actual.packed_event_blocked_retire_train_variant_count != count {
                mismatches.push(format!(
                    "packed_event_blocked_retire_train_variant_count mismatch: expected {count}, got {}",
                    actual.packed_event_blocked_retire_train_variant_count
                ));
            }
        }
        if let Some(count) = self.packed_event_blocked_retire_train_scope_count {
            if actual.packed_event_blocked_retire_train_scope_count != count {
                mismatches.push(format!(
                    "packed_event_blocked_retire_train_scope_count mismatch: expected {count}, got {}",
                    actual.packed_event_blocked_retire_train_scope_count
                ));
            }
        }
        if let Some(count) = self.packed_event_blocked_structural_only_count {
            if actual.packed_event_blocked_structural_only_count != count {
                mismatches.push(format!(
                    "packed_event_blocked_structural_only_count mismatch: expected {count}, got {}",
                    actual.packed_event_blocked_structural_only_count
                ));
            }
        }
        if let Some(count) = self.event_runtime_record_count {
            if actual.event_runtime_record_count != count {
                mismatches.push(format!(
                    "event_runtime_record_count mismatch: expected {count}, got {}",
                    actual.event_runtime_record_count
                ));
            }
        }
        if let Some(count) = self.candidate_availability_count {
            if actual.candidate_availability_count != count {
                mismatches.push(format!(
                    "candidate_availability_count mismatch: expected {count}, got {}",
                    actual.candidate_availability_count
                ));
            }
        }
        if let Some(count) = self.zero_candidate_availability_count {
            if actual.zero_candidate_availability_count != count {
                mismatches.push(format!(
                    "zero_candidate_availability_count mismatch: expected {count}, got {}",
                    actual.zero_candidate_availability_count
                ));
            }
        }
        if let Some(count) = self.named_locomotive_availability_count {
            if actual.named_locomotive_availability_count != count {
                mismatches.push(format!(
                    "named_locomotive_availability_count mismatch: expected {count}, got {}",
                    actual.named_locomotive_availability_count
                ));
            }
        }
        if let Some(count) = self.zero_named_locomotive_availability_count {
            if actual.zero_named_locomotive_availability_count != count {
                mismatches.push(format!(
                    "zero_named_locomotive_availability_count mismatch: expected {count}, got {}",
                    actual.zero_named_locomotive_availability_count
                ));
            }
        }
        if let Some(count) = self.named_locomotive_cost_count {
            if actual.named_locomotive_cost_count != count {
                mismatches.push(format!(
                    "named_locomotive_cost_count mismatch: expected {count}, got {}",
                    actual.named_locomotive_cost_count
                ));
            }
        }
        if let Some(count) = self.cargo_production_override_count {
            if actual.cargo_production_override_count != count {
                mismatches.push(format!(
                    "cargo_production_override_count mismatch: expected {count}, got {}",
                    actual.cargo_production_override_count
                ));
            }
        }
        if let Some(count) = self.world_runtime_variable_count {
            if actual.world_runtime_variable_count != count {
                mismatches.push(format!(
                    "world_runtime_variable_count mismatch: expected {count}, got {}",
                    actual.world_runtime_variable_count
                ));
            }
        }
        if let Some(count) = self.company_runtime_variable_owner_count {
            if actual.company_runtime_variable_owner_count != count {
                mismatches.push(format!(
                    "company_runtime_variable_owner_count mismatch: expected {count}, got {}",
                    actual.company_runtime_variable_owner_count
                ));
            }
        }
        if let Some(count) = self.player_runtime_variable_owner_count {
            if actual.player_runtime_variable_owner_count != count {
                mismatches.push(format!(
                    "player_runtime_variable_owner_count mismatch: expected {count}, got {}",
                    actual.player_runtime_variable_owner_count
                ));
            }
        }
        if let Some(count) = self.territory_runtime_variable_owner_count {
            if actual.territory_runtime_variable_owner_count != count {
                mismatches.push(format!(
                    "territory_runtime_variable_owner_count mismatch: expected {count}, got {}",
                    actual.territory_runtime_variable_owner_count
                ));
            }
        }
        if let Some(count) = self.world_scalar_override_count {
            if actual.world_scalar_override_count != count {
                mismatches.push(format!(
                    "world_scalar_override_count mismatch: expected {count}, got {}",
                    actual.world_scalar_override_count
                ));
            }
        }
        if let Some(count) = self.special_condition_count {
            if actual.special_condition_count != count {
                mismatches.push(format!(
                    "special_condition_count mismatch: expected {count}, got {}",
                    actual.special_condition_count
                ));
            }
        }
        if let Some(count) = self.enabled_special_condition_count {
            if actual.enabled_special_condition_count != count {
                mismatches.push(format!(
                    "enabled_special_condition_count mismatch: expected {count}, got {}",
                    actual.enabled_special_condition_count
                ));
            }
        }
        if let Some(kind) = &self.save_profile_kind {
            if actual.save_profile_kind.as_ref() != Some(kind) {
                mismatches.push(format!(
                    "save_profile_kind mismatch: expected {kind:?}, got {:?}",
                    actual.save_profile_kind
                ));
            }
        }
        if let Some(family) = &self.save_profile_family {
            if actual.save_profile_family.as_ref() != Some(family) {
                mismatches.push(format!(
                    "save_profile_family mismatch: expected {family:?}, got {:?}",
                    actual.save_profile_family
                ));
            }
        }
        if let Some(map_path) = &self.save_profile_map_path {
            if actual.save_profile_map_path.as_ref() != Some(map_path) {
                mismatches.push(format!(
                    "save_profile_map_path mismatch: expected {map_path:?}, got {:?}",
                    actual.save_profile_map_path
                ));
            }
        }
        if let Some(display_name) = &self.save_profile_display_name {
            if actual.save_profile_display_name.as_ref() != Some(display_name) {
                mismatches.push(format!(
                    "save_profile_display_name mismatch: expected {display_name:?}, got {:?}",
                    actual.save_profile_display_name
                ));
            }
        }
        if let Some(lane) = self.save_profile_selected_year_profile_lane {
            if actual.save_profile_selected_year_profile_lane != Some(lane) {
                mismatches.push(format!(
                    "save_profile_selected_year_profile_lane mismatch: expected {lane}, got {:?}",
                    actual.save_profile_selected_year_profile_lane
                ));
            }
        }
        if let Some(enabled) = self.save_profile_sandbox_enabled {
            if actual.save_profile_sandbox_enabled != Some(enabled) {
                mismatches.push(format!(
                    "save_profile_sandbox_enabled mismatch: expected {enabled}, got {:?}",
                    actual.save_profile_sandbox_enabled
                ));
            }
        }
        if let Some(enabled) = self.save_profile_campaign_scenario_enabled {
            if actual.save_profile_campaign_scenario_enabled != Some(enabled) {
                mismatches.push(format!(
                    "save_profile_campaign_scenario_enabled mismatch: expected {enabled}, got {:?}",
                    actual.save_profile_campaign_scenario_enabled
                ));
            }
        }
        if let Some(enabled) = self.save_profile_staged_profile_copy_on_restore {
            if actual.save_profile_staged_profile_copy_on_restore != Some(enabled) {
                mismatches.push(format!(
                    "save_profile_staged_profile_copy_on_restore mismatch: expected {enabled}, got {:?}",
                    actual.save_profile_staged_profile_copy_on_restore
                ));
            }
        }
        if let Some(count) = self.total_event_record_service_count {
            if actual.total_event_record_service_count != count {
                mismatches.push(format!(
                    "total_event_record_service_count mismatch: expected {count}, got {}",
                    actual.total_event_record_service_count
                ));
            }
        }
        if let Some(count) = self.periodic_boundary_call_count {
            if actual.periodic_boundary_call_count != count {
                mismatches.push(format!(
                    "periodic_boundary_call_count mismatch: expected {count}, got {}",
                    actual.periodic_boundary_call_count
                ));
            }
        }
        if let Some(count) = self.total_trigger_dispatch_count {
            if actual.total_trigger_dispatch_count != count {
                mismatches.push(format!(
                    "total_trigger_dispatch_count mismatch: expected {count}, got {}",
                    actual.total_trigger_dispatch_count
                ));
            }
        }
        if let Some(count) = self.dirty_rerun_count {
            if actual.dirty_rerun_count != count {
                mismatches.push(format!(
                    "dirty_rerun_count mismatch: expected {count}, got {}",
                    actual.dirty_rerun_count
                ));
            }
        }
        if let Some(total) = self.total_company_cash {
            if actual.total_company_cash != total {
                mismatches.push(format!(
                    "total_company_cash mismatch: expected {total}, got {}",
                    actual.total_company_cash
                ));
            }
        }

        mismatches
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct FixtureDocument {
    pub format_version: u32,
    pub fixture_id: String,
    #[serde(default)]
    pub source: FixtureSource,
    pub state: RuntimeState,
    pub state_origin: FixtureStateOrigin,
    #[serde(default)]
    pub commands: Vec<StepCommand>,
    #[serde(default)]
    pub expected_summary: ExpectedRuntimeSummary,
    #[serde(default)]
    pub expected_state_fragment: Option<Value>,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum FixtureStateOrigin {
    Inline,
    SnapshotPath(String),
    SaveSlicePath(String),
    ImportPath(String),
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct RawFixtureDocument {
    pub format_version: u32,
    pub fixture_id: String,
    #[serde(default)]
    pub source: FixtureSource,
    #[serde(default)]
    pub state: Option<RuntimeState>,
    #[serde(default)]
    pub state_snapshot_path: Option<String>,
    #[serde(default)]
    pub state_save_slice_path: Option<String>,
    #[serde(default)]
    pub state_import_path: Option<String>,
    #[serde(default)]
    pub commands: Vec<StepCommand>,
    #[serde(default)]
    pub expected_summary: ExpectedRuntimeSummary,
    #[serde(default)]
    pub expected_state_fragment: Option<Value>,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct FixtureValidationReport {
    pub fixture_id: String,
    pub valid: bool,
    pub issue_count: usize,
    pub issues: Vec<String>,
}

pub fn compare_expected_state_fragment(expected: &Value, actual: &Value) -> Vec<String> {
    let mut mismatches = Vec::new();
    compare_expected_state_fragment_at_path("$", expected, actual, &mut mismatches);
    mismatches
}

fn compare_expected_state_fragment_at_path(
    path: &str,
    expected: &Value,
    actual: &Value,
    mismatches: &mut Vec<String>,
) {
    match (expected, actual) {
        (Value::Object(expected_map), Value::Object(actual_map)) => {
            for (key, expected_value) in expected_map {
                let next_path = format!("{path}.{key}");
                match actual_map.get(key) {
                    Some(actual_value) => compare_expected_state_fragment_at_path(
                        &next_path,
                        expected_value,
                        actual_value,
                        mismatches,
                    ),
                    None => mismatches.push(format!("{next_path} missing in actual state")),
                }
            }
        }
        (Value::Array(expected_items), Value::Array(actual_items)) => {
            for (index, expected_item) in expected_items.iter().enumerate() {
                let next_path = format!("{path}[{index}]");
                match actual_items.get(index) {
                    Some(actual_item) => compare_expected_state_fragment_at_path(
                        &next_path,
                        expected_item,
                        actual_item,
                        mismatches,
                    ),
                    None => mismatches.push(format!("{next_path} missing in actual state")),
                }
            }
        }
        _ if expected != actual => mismatches.push(format!(
            "{path} mismatch: expected {expected:?}, got {actual:?}"
        )),
        _ => {}
    }
}

pub fn validate_fixture_document(document: &FixtureDocument) -> FixtureValidationReport {
    let mut issues = Vec::new();

    if document.format_version != FIXTURE_FORMAT_VERSION {
        issues.push(format!(
            "unsupported format_version {} (expected {})",
            document.format_version, FIXTURE_FORMAT_VERSION
        ));
    }
    if document.fixture_id.trim().is_empty() {
        issues.push("fixture_id must not be empty".to_string());
    }
    if document.source.kind.trim().is_empty() {
        issues.push("source.kind must not be empty".to_string());
    }
    if document.commands.is_empty() {
        issues.push("fixture must contain at least one command".to_string());
    }
    if let Err(err) = document.state.validate() {
        issues.push(format!("invalid runtime state: {err}"));
    }

    for (index, command) in document.commands.iter().enumerate() {
        if let Err(err) = command.validate() {
            issues.push(format!("invalid command at index {index}: {err}"));
        }
    }

    FixtureValidationReport {
        fixture_id: document.fixture_id.clone(),
        valid: issues.is_empty(),
        issue_count: issues.len(),
        issues,
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::load_fixture_document_from_str;

    const FIXTURE_JSON: &str = r#"
{
  "format_version": 1,
  "fixture_id": "minimal-world-step-smoke",
  "source": {
    "kind": "synthetic",
    "description": "basic milestone parser smoke fixture"
  },
  "state": {
    "calendar": {
      "year": 1830,
      "month_slot": 0,
      "phase_slot": 0,
      "tick_slot": 0
    },
    "world_flags": {
      "sandbox": false
    },
    "companies": [
      {
        "company_id": 1,
        "current_cash": 250000,
        "debt": 0
      }
    ],
    "event_runtime_records": [],
    "service_state": {
      "periodic_boundary_calls": 0,
      "trigger_dispatch_counts": {},
      "total_event_record_services": 0,
      "dirty_rerun_count": 0
    }
  },
  "commands": [
    {
      "kind": "advance_to",
      "calendar": {
        "year": 1830,
        "month_slot": 0,
        "phase_slot": 0,
        "tick_slot": 2
      }
    }
  ],
  "expected_summary": {
    "calendar": {
      "year": 1830,
      "month_slot": 0,
      "phase_slot": 0,
      "tick_slot": 2
    },
    "world_flag_count": 1,
    "company_count": 1,
    "event_runtime_record_count": 0,
    "world_restore_economic_tuning_lane_count": 0,
    "total_company_cash": 250000
  }
}
"#;

    #[test]
    fn parses_and_validates_fixture() {
        let fixture = load_fixture_document_from_str(FIXTURE_JSON).expect("fixture should parse");
        let report = validate_fixture_document(&fixture);
        assert!(report.valid, "report should be valid: {:?}", report.issues);
        assert_eq!(fixture.state_origin, FixtureStateOrigin::Inline);
    }

    #[test]
    fn compares_expected_summary() {
        let fixture = load_fixture_document_from_str(FIXTURE_JSON).expect("fixture should parse");
        let summary = RuntimeSummary::from_state(&fixture.state);
        let mismatches = fixture.expected_summary.compare(&summary);
        assert_eq!(mismatches.len(), 1);
        assert!(mismatches[0].contains("calendar mismatch"));
    }

    #[test]
    fn compares_expected_state_fragment_recursively() {
        let expected = serde_json::json!({
            "world_flags": {
                "sandbox": false
            },
            "companies": [
                {
                    "company_id": 1
                }
            ]
        });
        let actual = serde_json::json!({
            "world_flags": {
                "sandbox": false,
                "runtime.effect_fired": true
            },
            "companies": [
                {
                    "company_id": 1,
                    "current_cash": 250000
                }
            ]
        });

        let mismatches = compare_expected_state_fragment(&expected, &actual);
        assert!(
            mismatches.is_empty(),
            "unexpected mismatches: {mismatches:?}"
        );
    }
}
