use super::*;

#[test]
fn rejects_duplicate_company_ids() {
    let state = RuntimeState {
        calendar: CalendarPoint {
            year: 1830,
            month_slot: 0,
            phase_slot: 0,
            tick_slot: 0,
        },
        world_flags: BTreeMap::new(),
        save_profile: RuntimeSaveProfileState::default(),
        world_restore: RuntimeWorldRestoreState {
            absolute_counter_raw_u32: Some(5),
            ..RuntimeWorldRestoreState::default()
        },
        metadata: BTreeMap::new(),
        companies: vec![
            RuntimeCompany {
                company_id: 1,
                current_cash: 100,
                debt: 0,
                credit_rating_score: None,
                prime_rate: None,
                track_piece_counts: RuntimeTrackPieceCounts::default(),
                active: true,
                available_track_laying_capacity: None,
                linked_chairman_profile_id: None,
                book_value_per_share: 0,
                investor_confidence: 0,
                management_attitude: 0,
                takeover_cooldown_year: None,
                merger_cooldown_year: None,
                controller_kind: RuntimeCompanyControllerKind::Unknown,
            },
            RuntimeCompany {
                company_id: 1,
                current_cash: 200,
                debt: 0,
                credit_rating_score: None,
                prime_rate: None,
                track_piece_counts: RuntimeTrackPieceCounts::default(),
                active: true,
                available_track_laying_capacity: None,
                linked_chairman_profile_id: None,
                book_value_per_share: 0,
                investor_confidence: 0,
                management_attitude: 0,
                takeover_cooldown_year: None,
                merger_cooldown_year: None,
                controller_kind: RuntimeCompanyControllerKind::Unknown,
            },
        ],
        selected_company_id: None,
        players: Vec::new(),
        selected_player_id: None,
        chairman_profiles: Vec::new(),
        selected_chairman_profile_id: None,
        trains: Vec::new(),
        locomotive_catalog: Vec::new(),
        cargo_catalog: Vec::new(),
        territories: Vec::new(),
        company_territory_track_piece_counts: Vec::new(),
        company_territory_access: Vec::new(),
        packed_event_collection: None,
        event_runtime_records: Vec::new(),
        candidate_availability: BTreeMap::new(),
        named_locomotive_availability: BTreeMap::new(),
        named_locomotive_cost: BTreeMap::new(),
        all_cargo_price_override: None,
        named_cargo_price_overrides: BTreeMap::new(),
        all_cargo_production_override: None,
        factory_cargo_production_override: None,
        farm_mine_cargo_production_override: None,
        named_cargo_production_overrides: BTreeMap::new(),
        cargo_production_overrides: BTreeMap::new(),
        world_runtime_variables: BTreeMap::new(),
        company_runtime_variables: BTreeMap::new(),
        player_runtime_variables: BTreeMap::new(),
        territory_runtime_variables: BTreeMap::new(),
        world_scalar_overrides: BTreeMap::new(),
        special_conditions: BTreeMap::new(),
        service_state: RuntimeServiceState::default(),
    };

    assert!(state.validate().is_err());
}

#[test]
fn rejects_partial_world_restore_without_year_lane() {
    let state = RuntimeState {
            calendar: CalendarPoint {
                year: 1830,
                month_slot: 0,
                phase_slot: 0,
                tick_slot: 0,
            },
            world_flags: BTreeMap::new(),
            save_profile: RuntimeSaveProfileState::default(),
            world_restore: RuntimeWorldRestoreState {
                selected_year_profile_lane: None,
                campaign_scenario_enabled: Some(false),
                sandbox_enabled: Some(true),
                seed_tuple_written_from_raw_lane: Some(true),
                absolute_counter_requires_shell_context: Some(true),
                absolute_counter_reconstructible_from_save: Some(false),
                packed_year_word_raw_u16: None,
                partial_year_progress_raw_u8: None,
                current_calendar_tuple_word_raw_u32: None,
                current_calendar_tuple_word_2_raw_u32: None,
                absolute_counter_raw_u32: None,
                absolute_counter_mirror_raw_u32: None,
                disable_cargo_economy_special_condition_slot: Some(30),
                disable_cargo_economy_special_condition_reconstructible_from_save: Some(true),
                disable_cargo_economy_special_condition_write_side_grounded: Some(true),
                disable_cargo_economy_special_condition_enabled: Some(false),
                use_bio_accelerator_cars_enabled: Some(false),
                use_wartime_cargos_enabled: Some(false),
                disable_train_crashes_enabled: Some(false),
                disable_train_crashes_and_breakdowns_enabled: Some(false),
                ai_ignore_territories_at_startup_enabled: Some(false),
                limited_track_building_amount: None,
                economic_status_code: None,
                territory_access_cost: None,
                linked_site_removal_follow_on_gate_raw_u8: None,
                linked_site_removal_follow_on_gate_enabled: None,
                auto_show_grade_during_track_lay_raw_u8: None,
                starting_building_density_level_raw_u8: None,
                post_text_building_density_growth_raw_u8: None,
                leftover_simulation_time_accumulator_raw_u32: None,
                leftover_simulation_time_accumulator_value_f32_text: None,
                selected_year_lane_snapshot_raw_u8: None,
                all_steam_locomotives_available_raw_u8: None,
                all_steam_locomotives_available_enabled: None,
                all_diesel_locomotives_available_raw_u8: None,
                all_diesel_locomotives_available_enabled: None,
                all_electric_locomotives_available_raw_u8: None,
                all_electric_locomotives_available_enabled: None,
                cached_available_locomotive_rating_raw_u32: None,
                cached_available_locomotive_rating_value_f32_text: None,
                issue_37_value: None,
                issue_38_value: None,
                issue_39_value: None,
                issue_3a_value: None,
                issue_37_multiplier_raw_u32: None,
                issue_37_multiplier_value_f32_text: None,
                stock_issue_and_buyback_policy_raw_u8: None,
                bond_issue_and_repayment_policy_raw_u8: None,
                bankruptcy_policy_raw_u8: None,
                dividend_policy_raw_u8: None,
                building_density_growth_setting_raw_u32: None,
                stock_issue_and_buyback_allowed: None,
                bond_issue_and_repayment_allowed: None,
                bankruptcy_allowed: None,
                dividend_adjustment_allowed: None,
                finance_neighborhood_candidates: Vec::new(),
                economic_tuning_mirror_raw_u32: None,
                economic_tuning_mirror_value_f32_text: None,
                economic_tuning_lane_raw_u32: Vec::new(),
                economic_tuning_lane_value_f32_text: Vec::new(),
                selected_year_bucket_scalar_raw_u32: None,
                selected_year_bucket_scalar_value_f32_text: None,
                selected_year_bucket_direct_lane_raw_u32: Vec::new(),
                selected_year_bucket_direct_lane_value_f32_text: Vec::new(),
                selected_year_bucket_complement_lane_raw_u32: Vec::new(),
                selected_year_bucket_complement_lane_value_f32_text: Vec::new(),
                selected_year_bucket_scaled_companion_lane_raw_u32: Vec::new(),
                selected_year_bucket_scaled_companion_lane_value_f32_text: Vec::new(),
                selected_year_gap_scalar_raw_u32: None,
                selected_year_gap_scalar_value_f32_text: None,
                absolute_counter_restore_kind: Some(
                    "mode-adjusted-selected-year-lane".to_string(),
                ),
                absolute_counter_adjustment_context: Some(
                    "editor-map-mode,shell-selected-year-adjust-policy-0x9d26-0x9d28,save-special-condition-disable-cargo-economy-slot-30".to_string(),
                ),
            },
            metadata: BTreeMap::new(),
            companies: Vec::new(),
            selected_company_id: None,
            players: Vec::new(),
            selected_player_id: None,
            chairman_profiles: Vec::new(),
            selected_chairman_profile_id: None,
            trains: Vec::new(),
            locomotive_catalog: Vec::new(),
            cargo_catalog: Vec::new(),
            territories: Vec::new(),
            company_territory_track_piece_counts: Vec::new(),
            company_territory_access: Vec::new(),
            packed_event_collection: None,
            event_runtime_records: Vec::new(),
            candidate_availability: BTreeMap::new(),
            named_locomotive_availability: BTreeMap::new(),
            named_locomotive_cost: BTreeMap::new(),
            all_cargo_price_override: None,
            named_cargo_price_overrides: BTreeMap::new(),
            all_cargo_production_override: None,
            factory_cargo_production_override: None,
            farm_mine_cargo_production_override: None,
            named_cargo_production_overrides: BTreeMap::new(),
            cargo_production_overrides: BTreeMap::new(),
            world_runtime_variables: BTreeMap::new(),
            company_runtime_variables: BTreeMap::new(),
            player_runtime_variables: BTreeMap::new(),
            territory_runtime_variables: BTreeMap::new(),
            world_scalar_overrides: BTreeMap::new(),
            special_conditions: BTreeMap::new(),
            service_state: RuntimeServiceState::default(),
        };

    assert!(state.validate().is_err());
}

#[test]
fn rejects_event_effect_targeting_unknown_company() {
    let state = RuntimeState {
        calendar: CalendarPoint {
            year: 1830,
            month_slot: 0,
            phase_slot: 0,
            tick_slot: 0,
        },
        world_flags: BTreeMap::new(),
        save_profile: RuntimeSaveProfileState::default(),
        world_restore: RuntimeWorldRestoreState {
            absolute_counter_raw_u32: Some(5),
            ..RuntimeWorldRestoreState::default()
        },
        metadata: BTreeMap::new(),
        companies: vec![RuntimeCompany {
            company_id: 1,
            current_cash: 100,
            debt: 0,
            credit_rating_score: None,
            prime_rate: None,
            track_piece_counts: RuntimeTrackPieceCounts::default(),
            active: true,
            available_track_laying_capacity: None,
            linked_chairman_profile_id: None,
            book_value_per_share: 0,
            investor_confidence: 0,
            management_attitude: 0,
            takeover_cooldown_year: None,
            merger_cooldown_year: None,
            controller_kind: RuntimeCompanyControllerKind::Unknown,
        }],
        selected_company_id: None,
        players: Vec::new(),
        selected_player_id: None,
        chairman_profiles: Vec::new(),
        selected_chairman_profile_id: None,
        trains: Vec::new(),
        locomotive_catalog: Vec::new(),
        cargo_catalog: Vec::new(),
        territories: Vec::new(),
        company_territory_track_piece_counts: Vec::new(),
        company_territory_access: Vec::new(),
        packed_event_collection: None,
        event_runtime_records: vec![RuntimeEventRecord {
            record_id: 7,
            trigger_kind: 1,
            active: true,
            service_count: 0,
            marks_collection_dirty: false,
            one_shot: false,
            has_fired: false,
            conditions: Vec::new(),
            effects: vec![RuntimeEffect::AdjustCompanyCash {
                target: RuntimeCompanyTarget::Ids { ids: vec![2] },
                delta: 50,
            }],
        }],
        candidate_availability: BTreeMap::new(),
        named_locomotive_availability: BTreeMap::new(),
        named_locomotive_cost: BTreeMap::new(),
        all_cargo_price_override: None,
        named_cargo_price_overrides: BTreeMap::new(),
        all_cargo_production_override: None,
        factory_cargo_production_override: None,
        farm_mine_cargo_production_override: None,
        named_cargo_production_overrides: BTreeMap::new(),
        cargo_production_overrides: BTreeMap::new(),
        world_runtime_variables: BTreeMap::new(),
        company_runtime_variables: BTreeMap::new(),
        player_runtime_variables: BTreeMap::new(),
        territory_runtime_variables: BTreeMap::new(),
        world_scalar_overrides: BTreeMap::new(),
        special_conditions: BTreeMap::new(),
        service_state: RuntimeServiceState::default(),
    };

    assert!(state.validate().is_err());
}

#[test]
fn rejects_template_effect_targeting_unknown_company() {
    let state = RuntimeState {
        calendar: CalendarPoint {
            year: 1830,
            month_slot: 0,
            phase_slot: 0,
            tick_slot: 0,
        },
        world_flags: BTreeMap::new(),
        save_profile: RuntimeSaveProfileState::default(),
        world_restore: RuntimeWorldRestoreState {
            absolute_counter_raw_u32: Some(5),
            ..RuntimeWorldRestoreState::default()
        },
        metadata: BTreeMap::new(),
        companies: vec![RuntimeCompany {
            company_id: 1,
            current_cash: 100,
            debt: 0,
            credit_rating_score: None,
            prime_rate: None,
            track_piece_counts: RuntimeTrackPieceCounts::default(),
            active: true,
            available_track_laying_capacity: None,
            linked_chairman_profile_id: None,
            book_value_per_share: 0,
            investor_confidence: 0,
            management_attitude: 0,
            takeover_cooldown_year: None,
            merger_cooldown_year: None,
            controller_kind: RuntimeCompanyControllerKind::Unknown,
        }],
        selected_company_id: None,
        players: Vec::new(),
        selected_player_id: None,
        chairman_profiles: Vec::new(),
        selected_chairman_profile_id: None,
        trains: Vec::new(),
        locomotive_catalog: Vec::new(),
        cargo_catalog: Vec::new(),
        territories: Vec::new(),
        company_territory_track_piece_counts: Vec::new(),
        company_territory_access: Vec::new(),
        packed_event_collection: None,
        event_runtime_records: vec![RuntimeEventRecord {
            record_id: 7,
            trigger_kind: 1,
            active: true,
            service_count: 0,
            marks_collection_dirty: false,
            one_shot: false,
            has_fired: false,
            conditions: Vec::new(),
            effects: vec![RuntimeEffect::AppendEventRecord {
                record: Box::new(RuntimeEventRecordTemplate {
                    record_id: 8,
                    trigger_kind: 0x0a,
                    active: true,
                    marks_collection_dirty: false,
                    one_shot: false,
                    conditions: Vec::new(),
                    effects: vec![RuntimeEffect::AdjustCompanyCash {
                        target: RuntimeCompanyTarget::Ids { ids: vec![2] },
                        delta: 50,
                    }],
                }),
            }],
        }],
        candidate_availability: BTreeMap::new(),
        named_locomotive_availability: BTreeMap::new(),
        named_locomotive_cost: BTreeMap::new(),
        all_cargo_price_override: None,
        named_cargo_price_overrides: BTreeMap::new(),
        all_cargo_production_override: None,
        factory_cargo_production_override: None,
        farm_mine_cargo_production_override: None,
        named_cargo_production_overrides: BTreeMap::new(),
        cargo_production_overrides: BTreeMap::new(),
        world_runtime_variables: BTreeMap::new(),
        company_runtime_variables: BTreeMap::new(),
        player_runtime_variables: BTreeMap::new(),
        territory_runtime_variables: BTreeMap::new(),
        world_scalar_overrides: BTreeMap::new(),
        special_conditions: BTreeMap::new(),
        service_state: RuntimeServiceState::default(),
    };

    assert!(state.validate().is_err());
}

#[test]
fn rejects_invalid_packed_event_collection_summary() {
    let state = RuntimeState {
        calendar: CalendarPoint {
            year: 1830,
            month_slot: 0,
            phase_slot: 0,
            tick_slot: 0,
        },
        world_flags: BTreeMap::new(),
        save_profile: RuntimeSaveProfileState::default(),
        world_restore: RuntimeWorldRestoreState::default(),
        metadata: BTreeMap::new(),
        companies: Vec::new(),
        selected_company_id: None,
        players: Vec::new(),
        selected_player_id: None,
        chairman_profiles: Vec::new(),
        selected_chairman_profile_id: None,
        trains: Vec::new(),
        locomotive_catalog: Vec::new(),
        cargo_catalog: Vec::new(),
        territories: Vec::new(),
        company_territory_track_piece_counts: Vec::new(),
        company_territory_access: Vec::new(),
        packed_event_collection: Some(RuntimePackedEventCollectionSummary {
            source_kind: "packed-event-runtime-collection".to_string(),
            mechanism_family: "classic-save-rehydrate-v1".to_string(),
            mechanism_confidence: "grounded".to_string(),
            container_profile_family: Some("rt3-classic-save-container-v1".to_string()),
            packed_state_version: 0x3e9,
            packed_state_version_hex: "0x000003e9".to_string(),
            live_id_bound: 4,
            live_record_count: 2,
            live_entry_ids: vec![3, 3],
            decoded_record_count: 0,
            imported_runtime_record_count: 0,
            records: vec![
                RuntimePackedEventRecordSummary {
                    record_index: 0,
                    live_entry_id: 3,
                    payload_offset: None,
                    payload_len: None,
                    decode_status: "unsupported_framing".to_string(),
                    payload_family: "unsupported_framing".to_string(),
                    trigger_kind: None,
                    active: None,
                    marks_collection_dirty: None,
                    one_shot: None,
                    compact_control: None,
                    text_bands: Vec::new(),
                    standalone_condition_row_count: 0,
                    standalone_condition_rows: Vec::new(),
                    negative_sentinel_scope: None,
                    grouped_effect_row_counts: vec![0, 0, 0, 0],
                    grouped_effect_rows: Vec::new(),
                    grouped_company_targets: Vec::new(),
                    decoded_conditions: Vec::new(),
                    decoded_actions: Vec::new(),
                    executable_import_ready: false,
                    import_outcome: None,
                    notes: vec!["test".to_string()],
                },
                RuntimePackedEventRecordSummary {
                    record_index: 1,
                    live_entry_id: 3,
                    payload_offset: None,
                    payload_len: None,
                    decode_status: "unsupported_framing".to_string(),
                    payload_family: "unsupported_framing".to_string(),
                    trigger_kind: None,
                    active: None,
                    marks_collection_dirty: None,
                    one_shot: None,
                    compact_control: None,
                    text_bands: Vec::new(),
                    standalone_condition_row_count: 0,
                    standalone_condition_rows: Vec::new(),
                    negative_sentinel_scope: None,
                    grouped_effect_row_counts: vec![0, 0, 0, 0],
                    grouped_effect_rows: Vec::new(),
                    grouped_company_targets: Vec::new(),
                    decoded_conditions: Vec::new(),
                    decoded_actions: Vec::new(),
                    executable_import_ready: false,
                    import_outcome: None,
                    notes: vec!["test".to_string()],
                },
            ],
        }),
        event_runtime_records: Vec::new(),
        candidate_availability: BTreeMap::new(),
        named_locomotive_availability: BTreeMap::new(),
        named_locomotive_cost: BTreeMap::new(),
        all_cargo_price_override: None,
        named_cargo_price_overrides: BTreeMap::new(),
        all_cargo_production_override: None,
        factory_cargo_production_override: None,
        farm_mine_cargo_production_override: None,
        named_cargo_production_overrides: BTreeMap::new(),
        cargo_production_overrides: BTreeMap::new(),
        world_runtime_variables: BTreeMap::new(),
        company_runtime_variables: BTreeMap::new(),
        player_runtime_variables: BTreeMap::new(),
        territory_runtime_variables: BTreeMap::new(),
        world_scalar_overrides: BTreeMap::new(),
        special_conditions: BTreeMap::new(),
        service_state: RuntimeServiceState::default(),
    };

    assert!(state.validate().is_err());
}

#[test]
fn rejects_selected_company_id_that_does_not_exist() {
    let state = RuntimeState {
        calendar: CalendarPoint {
            year: 1830,
            month_slot: 0,
            phase_slot: 0,
            tick_slot: 0,
        },
        world_flags: BTreeMap::new(),
        save_profile: RuntimeSaveProfileState::default(),
        world_restore: RuntimeWorldRestoreState::default(),
        metadata: BTreeMap::new(),
        companies: vec![RuntimeCompany {
            company_id: 1,
            current_cash: 100,
            debt: 0,
            credit_rating_score: None,
            prime_rate: None,
            track_piece_counts: RuntimeTrackPieceCounts::default(),
            active: true,
            available_track_laying_capacity: None,
            linked_chairman_profile_id: None,
            book_value_per_share: 0,
            investor_confidence: 0,
            management_attitude: 0,
            takeover_cooldown_year: None,
            merger_cooldown_year: None,
            controller_kind: RuntimeCompanyControllerKind::Human,
        }],
        selected_company_id: Some(2),
        players: Vec::new(),
        selected_player_id: None,
        chairman_profiles: Vec::new(),
        selected_chairman_profile_id: None,
        trains: Vec::new(),
        locomotive_catalog: Vec::new(),
        cargo_catalog: Vec::new(),
        territories: Vec::new(),
        company_territory_track_piece_counts: Vec::new(),
        company_territory_access: Vec::new(),
        packed_event_collection: None,
        event_runtime_records: Vec::new(),
        candidate_availability: BTreeMap::new(),
        named_locomotive_availability: BTreeMap::new(),
        named_locomotive_cost: BTreeMap::new(),
        all_cargo_price_override: None,
        named_cargo_price_overrides: BTreeMap::new(),
        all_cargo_production_override: None,
        factory_cargo_production_override: None,
        farm_mine_cargo_production_override: None,
        named_cargo_production_overrides: BTreeMap::new(),
        cargo_production_overrides: BTreeMap::new(),
        world_runtime_variables: BTreeMap::new(),
        company_runtime_variables: BTreeMap::new(),
        player_runtime_variables: BTreeMap::new(),
        territory_runtime_variables: BTreeMap::new(),
        world_scalar_overrides: BTreeMap::new(),
        special_conditions: BTreeMap::new(),
        service_state: RuntimeServiceState::default(),
    };

    assert!(state.validate().is_err());
}

#[test]
fn rejects_selected_company_id_that_is_inactive() {
    let state = RuntimeState {
        calendar: CalendarPoint {
            year: 1830,
            month_slot: 0,
            phase_slot: 0,
            tick_slot: 0,
        },
        world_flags: BTreeMap::new(),
        save_profile: RuntimeSaveProfileState::default(),
        world_restore: RuntimeWorldRestoreState::default(),
        metadata: BTreeMap::new(),
        companies: vec![RuntimeCompany {
            company_id: 1,
            current_cash: 100,
            debt: 0,
            credit_rating_score: None,
            prime_rate: None,
            track_piece_counts: RuntimeTrackPieceCounts::default(),
            active: false,
            available_track_laying_capacity: None,
            linked_chairman_profile_id: None,
            book_value_per_share: 0,
            investor_confidence: 0,
            management_attitude: 0,
            takeover_cooldown_year: None,
            merger_cooldown_year: None,
            controller_kind: RuntimeCompanyControllerKind::Human,
        }],
        selected_company_id: Some(1),
        players: Vec::new(),
        selected_player_id: None,
        chairman_profiles: Vec::new(),
        selected_chairman_profile_id: None,
        trains: Vec::new(),
        locomotive_catalog: Vec::new(),
        cargo_catalog: Vec::new(),
        territories: Vec::new(),
        company_territory_track_piece_counts: Vec::new(),
        company_territory_access: Vec::new(),
        packed_event_collection: None,
        event_runtime_records: Vec::new(),
        candidate_availability: BTreeMap::new(),
        named_locomotive_availability: BTreeMap::new(),
        named_locomotive_cost: BTreeMap::new(),
        all_cargo_price_override: None,
        named_cargo_price_overrides: BTreeMap::new(),
        all_cargo_production_override: None,
        factory_cargo_production_override: None,
        farm_mine_cargo_production_override: None,
        named_cargo_production_overrides: BTreeMap::new(),
        cargo_production_overrides: BTreeMap::new(),
        world_runtime_variables: BTreeMap::new(),
        company_runtime_variables: BTreeMap::new(),
        player_runtime_variables: BTreeMap::new(),
        territory_runtime_variables: BTreeMap::new(),
        world_scalar_overrides: BTreeMap::new(),
        special_conditions: BTreeMap::new(),
        service_state: RuntimeServiceState::default(),
    };

    assert!(state.validate().is_err());
}

#[test]
fn rejects_duplicate_train_ids() {
    let state = RuntimeState {
        calendar: CalendarPoint {
            year: 1830,
            month_slot: 0,
            phase_slot: 0,
            tick_slot: 0,
        },
        world_flags: BTreeMap::new(),
        save_profile: RuntimeSaveProfileState::default(),
        world_restore: RuntimeWorldRestoreState::default(),
        metadata: BTreeMap::new(),
        companies: vec![RuntimeCompany {
            company_id: 1,
            current_cash: 100,
            debt: 0,
            credit_rating_score: None,
            prime_rate: None,
            track_piece_counts: RuntimeTrackPieceCounts::default(),
            active: true,
            available_track_laying_capacity: None,
            linked_chairman_profile_id: None,
            book_value_per_share: 0,
            investor_confidence: 0,
            management_attitude: 0,
            takeover_cooldown_year: None,
            merger_cooldown_year: None,
            controller_kind: RuntimeCompanyControllerKind::Human,
        }],
        selected_company_id: None,
        players: Vec::new(),
        selected_player_id: None,
        chairman_profiles: Vec::new(),
        selected_chairman_profile_id: None,
        trains: vec![
            RuntimeTrain {
                train_id: 7,
                owner_company_id: 1,
                territory_id: None,
                locomotive_name: Some("Mikado".to_string()),
                active: true,
                retired: false,
            },
            RuntimeTrain {
                train_id: 7,
                owner_company_id: 1,
                territory_id: None,
                locomotive_name: Some("Orca".to_string()),
                active: true,
                retired: false,
            },
        ],
        locomotive_catalog: Vec::new(),
        cargo_catalog: Vec::new(),
        territories: Vec::new(),
        company_territory_track_piece_counts: Vec::new(),
        company_territory_access: Vec::new(),
        packed_event_collection: None,
        event_runtime_records: Vec::new(),
        candidate_availability: BTreeMap::new(),
        named_locomotive_availability: BTreeMap::new(),
        named_locomotive_cost: BTreeMap::new(),
        all_cargo_price_override: None,
        named_cargo_price_overrides: BTreeMap::new(),
        all_cargo_production_override: None,
        factory_cargo_production_override: None,
        farm_mine_cargo_production_override: None,
        named_cargo_production_overrides: BTreeMap::new(),
        cargo_production_overrides: BTreeMap::new(),
        world_runtime_variables: BTreeMap::new(),
        company_runtime_variables: BTreeMap::new(),
        player_runtime_variables: BTreeMap::new(),
        territory_runtime_variables: BTreeMap::new(),
        world_scalar_overrides: BTreeMap::new(),
        special_conditions: BTreeMap::new(),
        service_state: RuntimeServiceState::default(),
    };

    assert!(state.validate().is_err());
}

#[test]
fn rejects_train_with_unknown_owner_company() {
    let state = RuntimeState {
        calendar: CalendarPoint {
            year: 1830,
            month_slot: 0,
            phase_slot: 0,
            tick_slot: 0,
        },
        world_flags: BTreeMap::new(),
        save_profile: RuntimeSaveProfileState::default(),
        world_restore: RuntimeWorldRestoreState::default(),
        metadata: BTreeMap::new(),
        companies: vec![RuntimeCompany {
            company_id: 1,
            current_cash: 100,
            debt: 0,
            credit_rating_score: None,
            prime_rate: None,
            track_piece_counts: RuntimeTrackPieceCounts::default(),
            active: true,
            available_track_laying_capacity: None,
            linked_chairman_profile_id: None,
            book_value_per_share: 0,
            investor_confidence: 0,
            management_attitude: 0,
            takeover_cooldown_year: None,
            merger_cooldown_year: None,
            controller_kind: RuntimeCompanyControllerKind::Human,
        }],
        selected_company_id: None,
        players: Vec::new(),
        selected_player_id: None,
        chairman_profiles: Vec::new(),
        selected_chairman_profile_id: None,
        trains: vec![RuntimeTrain {
            train_id: 7,
            owner_company_id: 2,
            territory_id: None,
            locomotive_name: Some("Mikado".to_string()),
            active: true,
            retired: false,
        }],
        locomotive_catalog: Vec::new(),
        cargo_catalog: Vec::new(),
        territories: Vec::new(),
        company_territory_track_piece_counts: Vec::new(),
        company_territory_access: Vec::new(),
        packed_event_collection: None,
        event_runtime_records: Vec::new(),
        candidate_availability: BTreeMap::new(),
        named_locomotive_availability: BTreeMap::new(),
        named_locomotive_cost: BTreeMap::new(),
        all_cargo_price_override: None,
        named_cargo_price_overrides: BTreeMap::new(),
        all_cargo_production_override: None,
        factory_cargo_production_override: None,
        farm_mine_cargo_production_override: None,
        named_cargo_production_overrides: BTreeMap::new(),
        cargo_production_overrides: BTreeMap::new(),
        world_runtime_variables: BTreeMap::new(),
        company_runtime_variables: BTreeMap::new(),
        player_runtime_variables: BTreeMap::new(),
        territory_runtime_variables: BTreeMap::new(),
        world_scalar_overrides: BTreeMap::new(),
        special_conditions: BTreeMap::new(),
        service_state: RuntimeServiceState::default(),
    };

    assert!(state.validate().is_err());
}

#[test]
fn rejects_train_with_unknown_territory() {
    let state = RuntimeState {
        calendar: CalendarPoint {
            year: 1830,
            month_slot: 0,
            phase_slot: 0,
            tick_slot: 0,
        },
        world_flags: BTreeMap::new(),
        save_profile: RuntimeSaveProfileState::default(),
        world_restore: RuntimeWorldRestoreState::default(),
        metadata: BTreeMap::new(),
        companies: vec![RuntimeCompany {
            company_id: 1,
            current_cash: 100,
            debt: 0,
            credit_rating_score: None,
            prime_rate: None,
            track_piece_counts: RuntimeTrackPieceCounts::default(),
            active: true,
            available_track_laying_capacity: None,
            linked_chairman_profile_id: None,
            book_value_per_share: 0,
            investor_confidence: 0,
            management_attitude: 0,
            takeover_cooldown_year: None,
            merger_cooldown_year: None,
            controller_kind: RuntimeCompanyControllerKind::Human,
        }],
        selected_company_id: None,
        players: Vec::new(),
        selected_player_id: None,
        chairman_profiles: Vec::new(),
        selected_chairman_profile_id: None,
        trains: vec![RuntimeTrain {
            train_id: 7,
            owner_company_id: 1,
            territory_id: Some(9),
            locomotive_name: Some("Mikado".to_string()),
            active: true,
            retired: false,
        }],
        locomotive_catalog: Vec::new(),
        cargo_catalog: Vec::new(),
        territories: vec![RuntimeTerritory {
            territory_id: 1,
            name: Some("Appalachia".to_string()),
            track_piece_counts: RuntimeTrackPieceCounts::default(),
        }],
        company_territory_track_piece_counts: Vec::new(),
        company_territory_access: Vec::new(),
        packed_event_collection: None,
        event_runtime_records: Vec::new(),
        candidate_availability: BTreeMap::new(),
        named_locomotive_availability: BTreeMap::new(),
        named_locomotive_cost: BTreeMap::new(),
        all_cargo_price_override: None,
        named_cargo_price_overrides: BTreeMap::new(),
        all_cargo_production_override: None,
        factory_cargo_production_override: None,
        farm_mine_cargo_production_override: None,
        named_cargo_production_overrides: BTreeMap::new(),
        cargo_production_overrides: BTreeMap::new(),
        world_runtime_variables: BTreeMap::new(),
        company_runtime_variables: BTreeMap::new(),
        player_runtime_variables: BTreeMap::new(),
        territory_runtime_variables: BTreeMap::new(),
        world_scalar_overrides: BTreeMap::new(),
        special_conditions: BTreeMap::new(),
        service_state: RuntimeServiceState::default(),
    };

    assert!(state.validate().is_err());
}

#[test]
fn rejects_train_marked_active_and_retired() {
    let state = RuntimeState {
        calendar: CalendarPoint {
            year: 1830,
            month_slot: 0,
            phase_slot: 0,
            tick_slot: 0,
        },
        world_flags: BTreeMap::new(),
        save_profile: RuntimeSaveProfileState::default(),
        world_restore: RuntimeWorldRestoreState::default(),
        metadata: BTreeMap::new(),
        companies: vec![RuntimeCompany {
            company_id: 1,
            current_cash: 100,
            debt: 0,
            credit_rating_score: None,
            prime_rate: None,
            track_piece_counts: RuntimeTrackPieceCounts::default(),
            active: true,
            available_track_laying_capacity: None,
            linked_chairman_profile_id: None,
            book_value_per_share: 0,
            investor_confidence: 0,
            management_attitude: 0,
            takeover_cooldown_year: None,
            merger_cooldown_year: None,
            controller_kind: RuntimeCompanyControllerKind::Human,
        }],
        selected_company_id: None,
        players: Vec::new(),
        selected_player_id: None,
        chairman_profiles: Vec::new(),
        selected_chairman_profile_id: None,
        trains: vec![RuntimeTrain {
            train_id: 7,
            owner_company_id: 1,
            territory_id: None,
            locomotive_name: Some("Mikado".to_string()),
            active: true,
            retired: true,
        }],
        locomotive_catalog: Vec::new(),
        cargo_catalog: Vec::new(),
        territories: Vec::new(),
        company_territory_track_piece_counts: Vec::new(),
        company_territory_access: Vec::new(),
        packed_event_collection: None,
        event_runtime_records: Vec::new(),
        candidate_availability: BTreeMap::new(),
        named_locomotive_availability: BTreeMap::new(),
        named_locomotive_cost: BTreeMap::new(),
        all_cargo_price_override: None,
        named_cargo_price_overrides: BTreeMap::new(),
        all_cargo_production_override: None,
        factory_cargo_production_override: None,
        farm_mine_cargo_production_override: None,
        named_cargo_production_overrides: BTreeMap::new(),
        cargo_production_overrides: BTreeMap::new(),
        world_runtime_variables: BTreeMap::new(),
        company_runtime_variables: BTreeMap::new(),
        player_runtime_variables: BTreeMap::new(),
        territory_runtime_variables: BTreeMap::new(),
        world_scalar_overrides: BTreeMap::new(),
        special_conditions: BTreeMap::new(),
        service_state: RuntimeServiceState::default(),
    };

    assert!(state.validate().is_err());
}

#[test]
fn rejects_duplicate_company_territory_access_pairs() {
    let state = RuntimeState {
        calendar: CalendarPoint {
            year: 1830,
            month_slot: 0,
            phase_slot: 0,
            tick_slot: 0,
        },
        world_flags: BTreeMap::new(),
        save_profile: RuntimeSaveProfileState::default(),
        world_restore: RuntimeWorldRestoreState::default(),
        metadata: BTreeMap::new(),
        companies: vec![RuntimeCompany {
            company_id: 1,
            current_cash: 100,
            debt: 0,
            credit_rating_score: None,
            prime_rate: None,
            track_piece_counts: RuntimeTrackPieceCounts::default(),
            active: true,
            available_track_laying_capacity: None,
            linked_chairman_profile_id: None,
            book_value_per_share: 0,
            investor_confidence: 0,
            management_attitude: 0,
            takeover_cooldown_year: None,
            merger_cooldown_year: None,
            controller_kind: RuntimeCompanyControllerKind::Human,
        }],
        selected_company_id: None,
        players: Vec::new(),
        selected_player_id: None,
        chairman_profiles: Vec::new(),
        selected_chairman_profile_id: None,
        trains: Vec::new(),
        locomotive_catalog: Vec::new(),
        cargo_catalog: Vec::new(),
        territories: vec![RuntimeTerritory {
            territory_id: 7,
            name: Some("Appalachia".to_string()),
            track_piece_counts: RuntimeTrackPieceCounts::default(),
        }],
        company_territory_track_piece_counts: Vec::new(),
        company_territory_access: vec![
            RuntimeCompanyTerritoryAccess {
                company_id: 1,
                territory_id: 7,
            },
            RuntimeCompanyTerritoryAccess {
                company_id: 1,
                territory_id: 7,
            },
        ],
        packed_event_collection: None,
        event_runtime_records: Vec::new(),
        candidate_availability: BTreeMap::new(),
        named_locomotive_availability: BTreeMap::new(),
        named_locomotive_cost: BTreeMap::new(),
        all_cargo_price_override: None,
        named_cargo_price_overrides: BTreeMap::new(),
        all_cargo_production_override: None,
        factory_cargo_production_override: None,
        farm_mine_cargo_production_override: None,
        named_cargo_production_overrides: BTreeMap::new(),
        cargo_production_overrides: BTreeMap::new(),
        world_runtime_variables: BTreeMap::new(),
        company_runtime_variables: BTreeMap::new(),
        player_runtime_variables: BTreeMap::new(),
        territory_runtime_variables: BTreeMap::new(),
        world_scalar_overrides: BTreeMap::new(),
        special_conditions: BTreeMap::new(),
        service_state: RuntimeServiceState::default(),
    };

    assert!(state.validate().is_err());
}

#[test]
fn rejects_company_territory_access_with_unknown_company() {
    let state = RuntimeState {
        calendar: CalendarPoint {
            year: 1830,
            month_slot: 0,
            phase_slot: 0,
            tick_slot: 0,
        },
        world_flags: BTreeMap::new(),
        save_profile: RuntimeSaveProfileState::default(),
        world_restore: RuntimeWorldRestoreState::default(),
        metadata: BTreeMap::new(),
        companies: vec![RuntimeCompany {
            company_id: 1,
            current_cash: 100,
            debt: 0,
            credit_rating_score: None,
            prime_rate: None,
            track_piece_counts: RuntimeTrackPieceCounts::default(),
            active: true,
            available_track_laying_capacity: None,
            linked_chairman_profile_id: None,
            book_value_per_share: 0,
            investor_confidence: 0,
            management_attitude: 0,
            takeover_cooldown_year: None,
            merger_cooldown_year: None,
            controller_kind: RuntimeCompanyControllerKind::Human,
        }],
        selected_company_id: None,
        players: Vec::new(),
        selected_player_id: None,
        chairman_profiles: Vec::new(),
        selected_chairman_profile_id: None,
        trains: Vec::new(),
        locomotive_catalog: Vec::new(),
        cargo_catalog: Vec::new(),
        territories: vec![RuntimeTerritory {
            territory_id: 7,
            name: Some("Appalachia".to_string()),
            track_piece_counts: RuntimeTrackPieceCounts::default(),
        }],
        company_territory_track_piece_counts: Vec::new(),
        company_territory_access: vec![RuntimeCompanyTerritoryAccess {
            company_id: 2,
            territory_id: 7,
        }],
        packed_event_collection: None,
        event_runtime_records: Vec::new(),
        candidate_availability: BTreeMap::new(),
        named_locomotive_availability: BTreeMap::new(),
        named_locomotive_cost: BTreeMap::new(),
        all_cargo_price_override: None,
        named_cargo_price_overrides: BTreeMap::new(),
        all_cargo_production_override: None,
        factory_cargo_production_override: None,
        farm_mine_cargo_production_override: None,
        named_cargo_production_overrides: BTreeMap::new(),
        cargo_production_overrides: BTreeMap::new(),
        world_runtime_variables: BTreeMap::new(),
        company_runtime_variables: BTreeMap::new(),
        player_runtime_variables: BTreeMap::new(),
        territory_runtime_variables: BTreeMap::new(),
        world_scalar_overrides: BTreeMap::new(),
        special_conditions: BTreeMap::new(),
        service_state: RuntimeServiceState::default(),
    };

    assert!(state.validate().is_err());
}

#[test]
fn rejects_company_territory_access_with_unknown_territory() {
    let state = RuntimeState {
        calendar: CalendarPoint {
            year: 1830,
            month_slot: 0,
            phase_slot: 0,
            tick_slot: 0,
        },
        world_flags: BTreeMap::new(),
        save_profile: RuntimeSaveProfileState::default(),
        world_restore: RuntimeWorldRestoreState::default(),
        metadata: BTreeMap::new(),
        companies: vec![RuntimeCompany {
            company_id: 1,
            current_cash: 100,
            debt: 0,
            credit_rating_score: None,
            prime_rate: None,
            track_piece_counts: RuntimeTrackPieceCounts::default(),
            active: true,
            available_track_laying_capacity: None,
            linked_chairman_profile_id: None,
            book_value_per_share: 0,
            investor_confidence: 0,
            management_attitude: 0,
            takeover_cooldown_year: None,
            merger_cooldown_year: None,
            controller_kind: RuntimeCompanyControllerKind::Human,
        }],
        selected_company_id: None,
        players: Vec::new(),
        selected_player_id: None,
        chairman_profiles: Vec::new(),
        selected_chairman_profile_id: None,
        trains: Vec::new(),
        locomotive_catalog: Vec::new(),
        cargo_catalog: Vec::new(),
        territories: vec![RuntimeTerritory {
            territory_id: 7,
            name: Some("Appalachia".to_string()),
            track_piece_counts: RuntimeTrackPieceCounts::default(),
        }],
        company_territory_track_piece_counts: Vec::new(),
        company_territory_access: vec![RuntimeCompanyTerritoryAccess {
            company_id: 1,
            territory_id: 8,
        }],
        packed_event_collection: None,
        event_runtime_records: Vec::new(),
        candidate_availability: BTreeMap::new(),
        named_locomotive_availability: BTreeMap::new(),
        named_locomotive_cost: BTreeMap::new(),
        all_cargo_price_override: None,
        named_cargo_price_overrides: BTreeMap::new(),
        all_cargo_production_override: None,
        factory_cargo_production_override: None,
        farm_mine_cargo_production_override: None,
        named_cargo_production_overrides: BTreeMap::new(),
        cargo_production_overrides: BTreeMap::new(),
        world_runtime_variables: BTreeMap::new(),
        company_runtime_variables: BTreeMap::new(),
        player_runtime_variables: BTreeMap::new(),
        territory_runtime_variables: BTreeMap::new(),
        world_scalar_overrides: BTreeMap::new(),
        special_conditions: BTreeMap::new(),
        service_state: RuntimeServiceState::default(),
    };

    assert!(state.validate().is_err());
}

#[test]
fn rejects_company_with_unknown_linked_chairman_profile() {
    let state = RuntimeState {
        calendar: CalendarPoint {
            year: 1830,
            month_slot: 0,
            phase_slot: 0,
            tick_slot: 0,
        },
        world_flags: BTreeMap::new(),
        save_profile: RuntimeSaveProfileState::default(),
        world_restore: RuntimeWorldRestoreState::default(),
        metadata: BTreeMap::new(),
        companies: vec![RuntimeCompany {
            company_id: 1,
            current_cash: 100,
            debt: 0,
            credit_rating_score: None,
            prime_rate: None,
            track_piece_counts: RuntimeTrackPieceCounts::default(),
            active: true,
            available_track_laying_capacity: None,
            linked_chairman_profile_id: Some(9),
            book_value_per_share: 0,
            investor_confidence: 0,
            management_attitude: 0,
            takeover_cooldown_year: None,
            merger_cooldown_year: None,
            controller_kind: RuntimeCompanyControllerKind::Human,
        }],
        selected_company_id: None,
        players: Vec::new(),
        selected_player_id: None,
        chairman_profiles: Vec::new(),
        selected_chairman_profile_id: None,
        trains: Vec::new(),
        locomotive_catalog: Vec::new(),
        cargo_catalog: Vec::new(),
        territories: Vec::new(),
        company_territory_track_piece_counts: Vec::new(),
        company_territory_access: Vec::new(),
        packed_event_collection: None,
        event_runtime_records: Vec::new(),
        candidate_availability: BTreeMap::new(),
        named_locomotive_availability: BTreeMap::new(),
        named_locomotive_cost: BTreeMap::new(),
        all_cargo_price_override: None,
        named_cargo_price_overrides: BTreeMap::new(),
        all_cargo_production_override: None,
        factory_cargo_production_override: None,
        farm_mine_cargo_production_override: None,
        named_cargo_production_overrides: BTreeMap::new(),
        cargo_production_overrides: BTreeMap::new(),
        world_runtime_variables: BTreeMap::new(),
        company_runtime_variables: BTreeMap::new(),
        player_runtime_variables: BTreeMap::new(),
        territory_runtime_variables: BTreeMap::new(),
        world_scalar_overrides: BTreeMap::new(),
        special_conditions: BTreeMap::new(),
        service_state: RuntimeServiceState::default(),
    };

    assert!(state.validate().is_err());
}

#[test]
fn rejects_mismatched_company_chairman_back_links() {
    let state = RuntimeState {
        calendar: CalendarPoint {
            year: 1830,
            month_slot: 0,
            phase_slot: 0,
            tick_slot: 0,
        },
        world_flags: BTreeMap::new(),
        save_profile: RuntimeSaveProfileState::default(),
        world_restore: RuntimeWorldRestoreState::default(),
        metadata: BTreeMap::new(),
        companies: vec![RuntimeCompany {
            company_id: 1,
            current_cash: 100,
            debt: 0,
            credit_rating_score: None,
            prime_rate: None,
            track_piece_counts: RuntimeTrackPieceCounts::default(),
            active: true,
            available_track_laying_capacity: None,
            linked_chairman_profile_id: Some(1),
            book_value_per_share: 0,
            investor_confidence: 0,
            management_attitude: 0,
            takeover_cooldown_year: None,
            merger_cooldown_year: None,
            controller_kind: RuntimeCompanyControllerKind::Human,
        }],
        selected_company_id: None,
        players: Vec::new(),
        selected_player_id: None,
        chairman_profiles: vec![RuntimeChairmanProfile {
            profile_id: 1,
            name: "Chairman One".to_string(),
            active: true,
            current_cash: 0,
            linked_company_id: None,
            company_holdings: BTreeMap::new(),
            holdings_value_total: 0,
            net_worth_total: 0,
            purchasing_power_total: 0,
        }],
        selected_chairman_profile_id: None,
        trains: Vec::new(),
        locomotive_catalog: Vec::new(),
        cargo_catalog: Vec::new(),
        territories: Vec::new(),
        company_territory_track_piece_counts: Vec::new(),
        company_territory_access: Vec::new(),
        packed_event_collection: None,
        event_runtime_records: Vec::new(),
        candidate_availability: BTreeMap::new(),
        named_locomotive_availability: BTreeMap::new(),
        named_locomotive_cost: BTreeMap::new(),
        all_cargo_price_override: None,
        named_cargo_price_overrides: BTreeMap::new(),
        all_cargo_production_override: None,
        factory_cargo_production_override: None,
        farm_mine_cargo_production_override: None,
        named_cargo_production_overrides: BTreeMap::new(),
        cargo_production_overrides: BTreeMap::new(),
        world_runtime_variables: BTreeMap::new(),
        company_runtime_variables: BTreeMap::new(),
        player_runtime_variables: BTreeMap::new(),
        territory_runtime_variables: BTreeMap::new(),
        world_scalar_overrides: BTreeMap::new(),
        special_conditions: BTreeMap::new(),
        service_state: RuntimeServiceState::default(),
    };

    assert!(state.validate().is_err());
}

#[test]
fn refreshes_chairman_totals_from_company_market_state() {
    let mut state = RuntimeState {
        calendar: CalendarPoint {
            year: 1830,
            month_slot: 0,
            phase_slot: 0,
            tick_slot: 0,
        },
        world_flags: BTreeMap::new(),
        save_profile: RuntimeSaveProfileState::default(),
        world_restore: RuntimeWorldRestoreState::default(),
        metadata: BTreeMap::new(),
        companies: vec![
            RuntimeCompany {
                company_id: 1,
                current_cash: 0,
                debt: 0,
                credit_rating_score: None,
                prime_rate: None,
                track_piece_counts: RuntimeTrackPieceCounts::default(),
                active: true,
                available_track_laying_capacity: None,
                linked_chairman_profile_id: None,
                book_value_per_share: 0,
                investor_confidence: 0,
                management_attitude: 0,
                takeover_cooldown_year: None,
                merger_cooldown_year: None,
                controller_kind: RuntimeCompanyControllerKind::Human,
            },
            RuntimeCompany {
                company_id: 2,
                current_cash: 0,
                debt: 0,
                credit_rating_score: None,
                prime_rate: None,
                track_piece_counts: RuntimeTrackPieceCounts::default(),
                active: true,
                available_track_laying_capacity: None,
                linked_chairman_profile_id: None,
                book_value_per_share: 0,
                investor_confidence: 0,
                management_attitude: 0,
                takeover_cooldown_year: None,
                merger_cooldown_year: None,
                controller_kind: RuntimeCompanyControllerKind::Human,
            },
        ],
        selected_company_id: None,
        players: Vec::new(),
        selected_player_id: None,
        chairman_profiles: vec![RuntimeChairmanProfile {
            profile_id: 1,
            name: "Chairman One".to_string(),
            active: true,
            current_cash: 100,
            linked_company_id: Some(1),
            company_holdings: BTreeMap::from([(1, 2), (2, 3)]),
            holdings_value_total: 0,
            net_worth_total: 0,
            purchasing_power_total: 400,
        }],
        selected_chairman_profile_id: None,
        trains: Vec::new(),
        locomotive_catalog: Vec::new(),
        cargo_catalog: Vec::new(),
        territories: Vec::new(),
        company_territory_track_piece_counts: Vec::new(),
        company_territory_access: Vec::new(),
        packed_event_collection: None,
        event_runtime_records: Vec::new(),
        candidate_availability: BTreeMap::new(),
        named_locomotive_availability: BTreeMap::new(),
        named_locomotive_cost: BTreeMap::new(),
        all_cargo_price_override: None,
        named_cargo_price_overrides: BTreeMap::new(),
        all_cargo_production_override: None,
        factory_cargo_production_override: None,
        farm_mine_cargo_production_override: None,
        named_cargo_production_overrides: BTreeMap::new(),
        cargo_production_overrides: BTreeMap::new(),
        world_runtime_variables: BTreeMap::new(),
        company_runtime_variables: BTreeMap::new(),
        player_runtime_variables: BTreeMap::new(),
        territory_runtime_variables: BTreeMap::new(),
        world_scalar_overrides: BTreeMap::new(),
        special_conditions: BTreeMap::new(),
        service_state: RuntimeServiceState {
            company_market_state: BTreeMap::from([
                (
                    1,
                    RuntimeCompanyMarketState {
                        cached_share_price_raw_u32: 0x41200000,
                        ..RuntimeCompanyMarketState::default()
                    },
                ),
                (
                    2,
                    RuntimeCompanyMarketState {
                        cached_share_price_raw_u32: 0x41a00000,
                        ..RuntimeCompanyMarketState::default()
                    },
                ),
            ]),
            ..RuntimeServiceState::default()
        },
    };

    state.refresh_derived_market_state();

    assert_eq!(state.chairman_profiles[0].holdings_value_total, 80);
    assert_eq!(state.chairman_profiles[0].net_worth_total, 180);
    assert_eq!(state.chairman_profiles[0].purchasing_power_total, 400);
}

#[test]
fn refreshes_chairman_purchasing_power_when_cash_changes() {
    let mut state = RuntimeState {
        calendar: CalendarPoint {
            year: 1830,
            month_slot: 0,
            phase_slot: 0,
            tick_slot: 0,
        },
        world_flags: BTreeMap::new(),
        save_profile: RuntimeSaveProfileState::default(),
        world_restore: RuntimeWorldRestoreState::default(),
        metadata: BTreeMap::new(),
        companies: vec![RuntimeCompany {
            company_id: 1,
            current_cash: 0,
            debt: 0,
            credit_rating_score: None,
            prime_rate: None,
            track_piece_counts: RuntimeTrackPieceCounts::default(),
            active: true,
            available_track_laying_capacity: None,
            linked_chairman_profile_id: None,
            book_value_per_share: 0,
            investor_confidence: 0,
            management_attitude: 0,
            takeover_cooldown_year: None,
            merger_cooldown_year: None,
            controller_kind: RuntimeCompanyControllerKind::Human,
        }],
        selected_company_id: None,
        players: Vec::new(),
        selected_player_id: None,
        chairman_profiles: vec![RuntimeChairmanProfile {
            profile_id: 1,
            name: "Chairman One".to_string(),
            active: true,
            current_cash: 50,
            linked_company_id: Some(1),
            company_holdings: BTreeMap::from([(1, 2)]),
            holdings_value_total: 20,
            net_worth_total: 70,
            purchasing_power_total: 130,
        }],
        selected_chairman_profile_id: None,
        trains: Vec::new(),
        locomotive_catalog: Vec::new(),
        cargo_catalog: Vec::new(),
        territories: Vec::new(),
        company_territory_track_piece_counts: Vec::new(),
        company_territory_access: Vec::new(),
        packed_event_collection: None,
        event_runtime_records: Vec::new(),
        candidate_availability: BTreeMap::new(),
        named_locomotive_availability: BTreeMap::new(),
        named_locomotive_cost: BTreeMap::new(),
        all_cargo_price_override: None,
        named_cargo_price_overrides: BTreeMap::new(),
        all_cargo_production_override: None,
        factory_cargo_production_override: None,
        farm_mine_cargo_production_override: None,
        named_cargo_production_overrides: BTreeMap::new(),
        cargo_production_overrides: BTreeMap::new(),
        world_runtime_variables: BTreeMap::new(),
        company_runtime_variables: BTreeMap::new(),
        player_runtime_variables: BTreeMap::new(),
        territory_runtime_variables: BTreeMap::new(),
        world_scalar_overrides: BTreeMap::new(),
        special_conditions: BTreeMap::new(),
        service_state: RuntimeServiceState {
            company_market_state: BTreeMap::from([(
                1,
                RuntimeCompanyMarketState {
                    cached_share_price_raw_u32: 0x41200000,
                    ..RuntimeCompanyMarketState::default()
                },
            )]),
            ..RuntimeServiceState::default()
        },
    };
    state.chairman_profiles[0].current_cash = 80;

    state.refresh_derived_market_state();

    assert_eq!(state.chairman_profiles[0].holdings_value_total, 20);
    assert_eq!(state.chairman_profiles[0].net_worth_total, 100);
    assert_eq!(state.chairman_profiles[0].purchasing_power_total, 130);
}

#[test]
fn refreshes_company_leaf_fields_from_owner_state() {
    let mut year_stat_family_qword_bits = vec![
        0u64;
        ((RUNTIME_COMPANY_STAT_SLOT_COUNT + 2) * RUNTIME_COMPANY_YEAR_STAT_FAMILY_SPAN)
            as usize
    ];
    year_stat_family_qword_bits[(RUNTIME_COMPANY_STAT_SLOT_CURRENT_CASH
        * RUNTIME_COMPANY_YEAR_STAT_FAMILY_SPAN) as usize] = 275.0f64.to_bits();

    let mut state = RuntimeState {
        calendar: CalendarPoint {
            year: 1830,
            month_slot: 0,
            phase_slot: 0,
            tick_slot: 0,
        },
        world_flags: BTreeMap::new(),
        save_profile: RuntimeSaveProfileState::default(),
        world_restore: RuntimeWorldRestoreState {
            issue_37_value: Some(5.0f32.to_bits()),
            ..RuntimeWorldRestoreState::default()
        },
        metadata: BTreeMap::new(),
        companies: vec![RuntimeCompany {
            company_id: 1,
            current_cash: 0,
            debt: 0,
            credit_rating_score: None,
            prime_rate: None,
            track_piece_counts: RuntimeTrackPieceCounts::default(),
            active: true,
            available_track_laying_capacity: None,
            linked_chairman_profile_id: None,
            book_value_per_share: 0,
            investor_confidence: 0,
            management_attitude: 0,
            takeover_cooldown_year: None,
            merger_cooldown_year: None,
            controller_kind: RuntimeCompanyControllerKind::Human,
        }],
        selected_company_id: None,
        players: Vec::new(),
        selected_player_id: None,
        chairman_profiles: Vec::new(),
        selected_chairman_profile_id: None,
        trains: Vec::new(),
        locomotive_catalog: Vec::new(),
        cargo_catalog: Vec::new(),
        territories: Vec::new(),
        company_territory_track_piece_counts: Vec::new(),
        company_territory_access: Vec::new(),
        packed_event_collection: None,
        event_runtime_records: Vec::new(),
        candidate_availability: BTreeMap::new(),
        named_locomotive_availability: BTreeMap::new(),
        named_locomotive_cost: BTreeMap::new(),
        all_cargo_price_override: None,
        named_cargo_price_overrides: BTreeMap::new(),
        all_cargo_production_override: None,
        factory_cargo_production_override: None,
        farm_mine_cargo_production_override: None,
        named_cargo_production_overrides: BTreeMap::new(),
        cargo_production_overrides: BTreeMap::new(),
        world_runtime_variables: BTreeMap::new(),
        company_runtime_variables: BTreeMap::new(),
        player_runtime_variables: BTreeMap::new(),
        territory_runtime_variables: BTreeMap::new(),
        world_scalar_overrides: BTreeMap::new(),
        special_conditions: BTreeMap::new(),
        service_state: RuntimeServiceState {
            world_issue_opinion_base_terms_raw_i32: {
                let mut terms = vec![0; 0x3b];
                terms[RUNTIME_WORLD_ISSUE_PRIME_RATE as usize] = 100;
                terms
            },
            company_market_state: BTreeMap::from([(
                1,
                RuntimeCompanyMarketState {
                    cached_share_price_raw_u32: 37.0f32.to_bits(),
                    issue_opinion_terms_raw_i32: {
                        let mut terms = vec![0; 0x3b];
                        terms[RUNTIME_WORLD_ISSUE_MANAGEMENT_ATTITUDE as usize] = 58;
                        terms
                    },
                    direct_control_transfer_float_fields_raw_u32: BTreeMap::from([(
                        0x32f,
                        2620.0f32.to_bits(),
                    )]),
                    year_stat_family_qword_bits,
                    ..RuntimeCompanyMarketState::default()
                },
            )]),
            ..RuntimeServiceState::default()
        },
    };

    state.refresh_derived_market_state();

    assert_eq!(state.companies[0].current_cash, 275);
    assert_eq!(state.companies[0].book_value_per_share, 2620);
    assert_eq!(state.companies[0].prime_rate, Some(6));
    assert_eq!(state.companies[0].investor_confidence, 37);
    assert_eq!(state.companies[0].management_attitude, 58);
}

#[test]
fn seeds_company_periodic_side_latch_state_from_company_market_state() {
    let mut state = RuntimeState {
        calendar: CalendarPoint {
            year: 1830,
            month_slot: 0,
            phase_slot: 0,
            tick_slot: 0,
        },
        world_flags: BTreeMap::new(),
        save_profile: RuntimeSaveProfileState::default(),
        world_restore: RuntimeWorldRestoreState::default(),
        metadata: BTreeMap::new(),
        companies: vec![RuntimeCompany {
            company_id: 1,
            current_cash: 0,
            debt: 0,
            credit_rating_score: None,
            prime_rate: None,
            track_piece_counts: RuntimeTrackPieceCounts::default(),
            active: true,
            available_track_laying_capacity: None,
            linked_chairman_profile_id: None,
            book_value_per_share: 0,
            investor_confidence: 0,
            management_attitude: 0,
            takeover_cooldown_year: None,
            merger_cooldown_year: None,
            controller_kind: RuntimeCompanyControllerKind::Unknown,
        }],
        selected_company_id: Some(1),
        players: Vec::new(),
        selected_player_id: None,
        chairman_profiles: Vec::new(),
        selected_chairman_profile_id: None,
        trains: Vec::new(),
        locomotive_catalog: Vec::new(),
        cargo_catalog: Vec::new(),
        territories: Vec::new(),
        company_territory_track_piece_counts: Vec::new(),
        company_territory_access: Vec::new(),
        packed_event_collection: None,
        event_runtime_records: Vec::new(),
        candidate_availability: BTreeMap::new(),
        named_locomotive_availability: BTreeMap::new(),
        named_locomotive_cost: BTreeMap::new(),
        all_cargo_price_override: None,
        named_cargo_price_overrides: BTreeMap::new(),
        all_cargo_production_override: None,
        factory_cargo_production_override: None,
        farm_mine_cargo_production_override: None,
        named_cargo_production_overrides: BTreeMap::new(),
        cargo_production_overrides: BTreeMap::new(),
        world_runtime_variables: BTreeMap::new(),
        company_runtime_variables: BTreeMap::new(),
        player_runtime_variables: BTreeMap::new(),
        territory_runtime_variables: BTreeMap::new(),
        world_scalar_overrides: BTreeMap::new(),
        special_conditions: BTreeMap::new(),
        service_state: RuntimeServiceState {
            company_market_state: BTreeMap::from([(
                1,
                RuntimeCompanyMarketState {
                    city_connection_latch: true,
                    linked_transit_latch: false,
                    ..RuntimeCompanyMarketState::default()
                },
            )]),
            ..RuntimeServiceState::default()
        },
    };

    state.refresh_derived_market_state();

    assert_eq!(
        state
            .service_state
            .company_periodic_side_latch_state
            .get(&1),
        Some(&RuntimeCompanyPeriodicSideLatchState {
            preferred_locomotive_engine_type_raw_u8: None,
            city_connection_latch: true,
            linked_transit_latch: false,
        })
    );
}

#[test]
fn preserves_company_periodic_side_latch_state_without_market_projection() {
    let mut state = RuntimeState {
        calendar: CalendarPoint {
            year: 1830,
            month_slot: 0,
            phase_slot: 0,
            tick_slot: 0,
        },
        world_flags: BTreeMap::new(),
        save_profile: RuntimeSaveProfileState::default(),
        world_restore: RuntimeWorldRestoreState::default(),
        metadata: BTreeMap::new(),
        companies: vec![RuntimeCompany {
            company_id: 1,
            current_cash: 0,
            debt: 0,
            credit_rating_score: None,
            prime_rate: None,
            track_piece_counts: RuntimeTrackPieceCounts::default(),
            active: true,
            available_track_laying_capacity: None,
            linked_chairman_profile_id: None,
            book_value_per_share: 0,
            investor_confidence: 0,
            management_attitude: 0,
            takeover_cooldown_year: None,
            merger_cooldown_year: None,
            controller_kind: RuntimeCompanyControllerKind::Unknown,
        }],
        selected_company_id: Some(1),
        players: Vec::new(),
        selected_player_id: None,
        chairman_profiles: Vec::new(),
        selected_chairman_profile_id: None,
        trains: Vec::new(),
        locomotive_catalog: Vec::new(),
        cargo_catalog: Vec::new(),
        territories: Vec::new(),
        company_territory_track_piece_counts: Vec::new(),
        company_territory_access: Vec::new(),
        packed_event_collection: None,
        event_runtime_records: Vec::new(),
        candidate_availability: BTreeMap::new(),
        named_locomotive_availability: BTreeMap::new(),
        named_locomotive_cost: BTreeMap::new(),
        all_cargo_price_override: None,
        named_cargo_price_overrides: BTreeMap::new(),
        all_cargo_production_override: None,
        factory_cargo_production_override: None,
        farm_mine_cargo_production_override: None,
        named_cargo_production_overrides: BTreeMap::new(),
        cargo_production_overrides: BTreeMap::new(),
        world_runtime_variables: BTreeMap::new(),
        company_runtime_variables: BTreeMap::new(),
        player_runtime_variables: BTreeMap::new(),
        territory_runtime_variables: BTreeMap::new(),
        world_scalar_overrides: BTreeMap::new(),
        special_conditions: BTreeMap::new(),
        service_state: RuntimeServiceState {
            company_periodic_side_latch_state: BTreeMap::from([(
                1,
                RuntimeCompanyPeriodicSideLatchState {
                    preferred_locomotive_engine_type_raw_u8: Some(2),
                    city_connection_latch: true,
                    linked_transit_latch: false,
                },
            )]),
            ..RuntimeServiceState::default()
        },
    };

    state.refresh_derived_market_state();

    assert_eq!(
        state
            .service_state
            .company_periodic_side_latch_state
            .get(&1),
        Some(&RuntimeCompanyPeriodicSideLatchState {
            preferred_locomotive_engine_type_raw_u8: Some(2),
            city_connection_latch: true,
            linked_transit_latch: false,
        })
    );
}

#[test]
fn reads_grounded_company_stat_family_slots_from_runtime_state() {
    let mut year_stat_family_qword_bits = vec![
        0u64;
        ((RUNTIME_COMPANY_STAT_SLOT_COUNT + 2) * RUNTIME_COMPANY_YEAR_STAT_FAMILY_SPAN)
            as usize
    ];
    year_stat_family_qword_bits[(0x12 * RUNTIME_COMPANY_YEAR_STAT_FAMILY_SPAN) as usize] =
        75.0f64.to_bits();
    let state = RuntimeState {
        calendar: CalendarPoint {
            year: 1830,
            month_slot: 0,
            phase_slot: 0,
            tick_slot: 0,
        },
        world_flags: BTreeMap::new(),
        save_profile: RuntimeSaveProfileState::default(),
        world_restore: RuntimeWorldRestoreState::default(),
        metadata: BTreeMap::new(),
        companies: vec![RuntimeCompany {
            company_id: 7,
            current_cash: 125_000,
            debt: 0,
            credit_rating_score: None,
            prime_rate: None,
            active: true,
            available_track_laying_capacity: None,
            controller_kind: RuntimeCompanyControllerKind::Unknown,
            linked_chairman_profile_id: None,
            book_value_per_share: 2_620,
            investor_confidence: 0,
            management_attitude: 0,
            takeover_cooldown_year: None,
            merger_cooldown_year: None,
            track_piece_counts: RuntimeTrackPieceCounts::default(),
        }],
        selected_company_id: None,
        players: Vec::new(),
        selected_player_id: None,
        chairman_profiles: Vec::new(),
        selected_chairman_profile_id: None,
        trains: Vec::new(),
        locomotive_catalog: Vec::new(),
        cargo_catalog: Vec::new(),
        territories: Vec::new(),
        company_territory_track_piece_counts: Vec::new(),
        company_territory_access: Vec::new(),
        packed_event_collection: None,
        event_runtime_records: Vec::new(),
        candidate_availability: BTreeMap::new(),
        named_locomotive_availability: BTreeMap::new(),
        named_locomotive_cost: BTreeMap::new(),
        all_cargo_price_override: None,
        named_cargo_price_overrides: BTreeMap::new(),
        all_cargo_production_override: None,
        factory_cargo_production_override: None,
        farm_mine_cargo_production_override: None,
        named_cargo_production_overrides: BTreeMap::new(),
        cargo_production_overrides: BTreeMap::new(),
        world_runtime_variables: BTreeMap::new(),
        company_runtime_variables: BTreeMap::new(),
        player_runtime_variables: BTreeMap::new(),
        territory_runtime_variables: BTreeMap::new(),
        world_scalar_overrides: BTreeMap::new(),
        special_conditions: BTreeMap::new(),
        service_state: RuntimeServiceState {
            world_issue_opinion_base_terms_raw_i32: vec![0; 0x3b],
            company_market_state: BTreeMap::from([(
                7,
                RuntimeCompanyMarketState {
                    year_stat_family_qword_bits,
                    ..RuntimeCompanyMarketState::default()
                },
            )]),
            ..RuntimeServiceState::default()
        },
    };

    assert_eq!(
        runtime_company_stat_value(
            &state,
            7,
            RuntimeCompanyStatSelector {
                family_id: RUNTIME_COMPANY_STAT_FAMILY_CONTROL_TRANSFER,
                slot_id: RUNTIME_COMPANY_STAT_SLOT_CURRENT_CASH,
            },
        ),
        Some(125_000)
    );
    assert_eq!(
        runtime_company_stat_value(
            &state,
            7,
            RuntimeCompanyStatSelector {
                family_id: RUNTIME_COMPANY_STAT_FAMILY_CONTROL_TRANSFER,
                slot_id: RUNTIME_COMPANY_STAT_SLOT_BOOK_VALUE_PER_SHARE,
            },
        ),
        Some(2_620)
    );
    assert_eq!(
        runtime_company_stat_value(
            &state,
            7,
            RuntimeCompanyStatSelector {
                family_id: RUNTIME_COMPANY_STAT_FAMILY_CONTROL_TRANSFER,
                slot_id: 0x12,
            },
        ),
        Some(75)
    );
    assert_eq!(
        runtime_company_stat_value(
            &state,
            7,
            RuntimeCompanyStatSelector {
                family_id: RUNTIME_COMPANY_STAT_FAMILY_CONTROL_TRANSFER,
                slot_id: 0x2b,
            },
        ),
        Some(0)
    );
    assert_eq!(
        runtime_company_stat_value(
            &state,
            99,
            RuntimeCompanyStatSelector {
                family_id: RUNTIME_COMPANY_STAT_FAMILY_CONTROL_TRANSFER,
                slot_id: RUNTIME_COMPANY_STAT_SLOT_CURRENT_CASH,
            },
        ),
        None
    );
}

#[test]
fn reads_book_value_per_share_from_rehosted_direct_company_field_band() {
    let state = RuntimeState {
        calendar: CalendarPoint {
            year: 1830,
            month_slot: 0,
            phase_slot: 0,
            tick_slot: 0,
        },
        world_flags: BTreeMap::new(),
        save_profile: RuntimeSaveProfileState::default(),
        world_restore: RuntimeWorldRestoreState::default(),
        metadata: BTreeMap::new(),
        companies: vec![RuntimeCompany {
            company_id: 7,
            current_cash: 0,
            debt: 0,
            credit_rating_score: None,
            prime_rate: None,
            active: true,
            available_track_laying_capacity: None,
            controller_kind: RuntimeCompanyControllerKind::Unknown,
            linked_chairman_profile_id: None,
            book_value_per_share: 0,
            investor_confidence: 0,
            management_attitude: 0,
            takeover_cooldown_year: None,
            merger_cooldown_year: None,
            track_piece_counts: RuntimeTrackPieceCounts::default(),
        }],
        selected_company_id: None,
        players: Vec::new(),
        selected_player_id: None,
        chairman_profiles: Vec::new(),
        selected_chairman_profile_id: None,
        trains: Vec::new(),
        locomotive_catalog: Vec::new(),
        cargo_catalog: Vec::new(),
        territories: Vec::new(),
        company_territory_track_piece_counts: Vec::new(),
        company_territory_access: Vec::new(),
        packed_event_collection: None,
        event_runtime_records: Vec::new(),
        candidate_availability: BTreeMap::new(),
        named_locomotive_availability: BTreeMap::new(),
        named_locomotive_cost: BTreeMap::new(),
        all_cargo_price_override: None,
        named_cargo_price_overrides: BTreeMap::new(),
        all_cargo_production_override: None,
        factory_cargo_production_override: None,
        farm_mine_cargo_production_override: None,
        named_cargo_production_overrides: BTreeMap::new(),
        cargo_production_overrides: BTreeMap::new(),
        world_runtime_variables: BTreeMap::new(),
        company_runtime_variables: BTreeMap::new(),
        player_runtime_variables: BTreeMap::new(),
        territory_runtime_variables: BTreeMap::new(),
        world_scalar_overrides: BTreeMap::new(),
        special_conditions: BTreeMap::new(),
        service_state: RuntimeServiceState {
            company_market_state: BTreeMap::from([(
                7,
                RuntimeCompanyMarketState {
                    direct_control_transfer_float_fields_raw_u32: BTreeMap::from([(
                        0x32f,
                        2620.0f32.to_bits(),
                    )]),
                    ..RuntimeCompanyMarketState::default()
                },
            )]),
            ..RuntimeServiceState::default()
        },
    };

    assert_eq!(runtime_company_book_value_per_share(&state, 7), Some(2620));
    assert_eq!(
        runtime_company_stat_value(
            &state,
            7,
            RuntimeCompanyStatSelector {
                family_id: RUNTIME_COMPANY_STAT_FAMILY_CONTROL_TRANSFER,
                slot_id: RUNTIME_COMPANY_STAT_SLOT_BOOK_VALUE_PER_SHARE,
            },
        ),
        Some(2620)
    );
}

#[test]
fn reads_investor_confidence_from_rehosted_company_share_price_cache() {
    let state = RuntimeState {
        calendar: CalendarPoint {
            year: 1830,
            month_slot: 0,
            phase_slot: 0,
            tick_slot: 0,
        },
        world_flags: BTreeMap::new(),
        save_profile: RuntimeSaveProfileState::default(),
        world_restore: RuntimeWorldRestoreState {
            absolute_counter_raw_u32: Some(5),
            ..RuntimeWorldRestoreState::default()
        },
        metadata: BTreeMap::new(),
        companies: vec![RuntimeCompany {
            company_id: 7,
            current_cash: 0,
            debt: 0,
            credit_rating_score: None,
            prime_rate: None,
            active: true,
            available_track_laying_capacity: None,
            controller_kind: RuntimeCompanyControllerKind::Unknown,
            linked_chairman_profile_id: None,
            book_value_per_share: 0,
            investor_confidence: 0,
            management_attitude: 0,
            takeover_cooldown_year: None,
            merger_cooldown_year: None,
            track_piece_counts: RuntimeTrackPieceCounts::default(),
        }],
        selected_company_id: None,
        players: Vec::new(),
        selected_player_id: None,
        chairman_profiles: Vec::new(),
        selected_chairman_profile_id: None,
        trains: Vec::new(),
        locomotive_catalog: Vec::new(),
        cargo_catalog: Vec::new(),
        territories: Vec::new(),
        company_territory_track_piece_counts: Vec::new(),
        company_territory_access: Vec::new(),
        packed_event_collection: None,
        event_runtime_records: Vec::new(),
        candidate_availability: BTreeMap::new(),
        named_locomotive_availability: BTreeMap::new(),
        named_locomotive_cost: BTreeMap::new(),
        all_cargo_price_override: None,
        named_cargo_price_overrides: BTreeMap::new(),
        all_cargo_production_override: None,
        factory_cargo_production_override: None,
        farm_mine_cargo_production_override: None,
        named_cargo_production_overrides: BTreeMap::new(),
        cargo_production_overrides: BTreeMap::new(),
        world_runtime_variables: BTreeMap::new(),
        company_runtime_variables: BTreeMap::new(),
        player_runtime_variables: BTreeMap::new(),
        territory_runtime_variables: BTreeMap::new(),
        world_scalar_overrides: BTreeMap::new(),
        special_conditions: BTreeMap::new(),
        service_state: RuntimeServiceState {
            company_market_state: BTreeMap::from([(
                7,
                RuntimeCompanyMarketState {
                    recent_per_share_cache_absolute_counter: 5,
                    recent_per_share_cached_value_bits: 14.5f64.to_bits(),
                    recent_per_share_subscore_raw_u32: 12.0f32.to_bits(),
                    cached_share_price_raw_u32: 37.0f32.to_bits(),
                    ..RuntimeCompanyMarketState::default()
                },
            )]),
            ..RuntimeServiceState::default()
        },
    };

    assert_eq!(
        runtime_company_recent_per_share_subscore(&state, 7),
        Some(14.5)
    );
    assert_eq!(runtime_company_investor_confidence(&state, 7), Some(37));
    assert_eq!(
        runtime_company_stat_value(
            &state,
            7,
            RuntimeCompanyStatSelector {
                family_id: RUNTIME_COMPANY_STAT_FAMILY_CONTROL_TRANSFER,
                slot_id: 0x13,
            },
        ),
        Some(37)
    );
}

#[test]
fn derives_company_management_attitude_from_issue3a_owner_state() {
    let mut company_terms = vec![0; 0x3b];
    company_terms[RUNTIME_WORLD_ISSUE_MANAGEMENT_ATTITUDE as usize] = 12;
    let mut chairman_terms = vec![0; 0x3b];
    chairman_terms[RUNTIME_WORLD_ISSUE_MANAGEMENT_ATTITUDE as usize] = 6;
    let mut world_terms = vec![0; 0x3b];
    world_terms[RUNTIME_WORLD_ISSUE_MANAGEMENT_ATTITUDE as usize] = 40;

    let state = RuntimeState {
        calendar: CalendarPoint {
            year: 1830,
            month_slot: 0,
            phase_slot: 0,
            tick_slot: 0,
        },
        world_flags: BTreeMap::new(),
        save_profile: RuntimeSaveProfileState::default(),
        world_restore: RuntimeWorldRestoreState::default(),
        metadata: BTreeMap::new(),
        companies: vec![RuntimeCompany {
            company_id: 7,
            current_cash: 0,
            debt: 0,
            credit_rating_score: None,
            prime_rate: None,
            active: true,
            available_track_laying_capacity: None,
            controller_kind: RuntimeCompanyControllerKind::Unknown,
            linked_chairman_profile_id: Some(3),
            book_value_per_share: 0,
            investor_confidence: 0,
            management_attitude: 0,
            takeover_cooldown_year: None,
            merger_cooldown_year: None,
            track_piece_counts: RuntimeTrackPieceCounts::default(),
        }],
        selected_company_id: None,
        players: Vec::new(),
        selected_player_id: None,
        chairman_profiles: vec![RuntimeChairmanProfile {
            profile_id: 3,
            name: "Chairman".to_string(),
            active: true,
            current_cash: 0,
            linked_company_id: Some(7),
            company_holdings: BTreeMap::new(),
            holdings_value_total: 0,
            net_worth_total: 0,
            purchasing_power_total: 0,
        }],
        selected_chairman_profile_id: None,
        trains: Vec::new(),
        locomotive_catalog: Vec::new(),
        cargo_catalog: Vec::new(),
        territories: Vec::new(),
        company_territory_track_piece_counts: Vec::new(),
        company_territory_access: Vec::new(),
        packed_event_collection: None,
        event_runtime_records: Vec::new(),
        candidate_availability: BTreeMap::new(),
        named_locomotive_availability: BTreeMap::new(),
        named_locomotive_cost: BTreeMap::new(),
        all_cargo_price_override: None,
        named_cargo_price_overrides: BTreeMap::new(),
        all_cargo_production_override: None,
        factory_cargo_production_override: None,
        farm_mine_cargo_production_override: None,
        named_cargo_production_overrides: BTreeMap::new(),
        cargo_production_overrides: BTreeMap::new(),
        world_runtime_variables: BTreeMap::new(),
        company_runtime_variables: BTreeMap::new(),
        player_runtime_variables: BTreeMap::new(),
        territory_runtime_variables: BTreeMap::new(),
        world_scalar_overrides: BTreeMap::new(),
        special_conditions: BTreeMap::new(),
        service_state: RuntimeServiceState {
            world_issue_opinion_base_terms_raw_i32: world_terms,
            company_market_state: BTreeMap::from([(
                7,
                RuntimeCompanyMarketState {
                    issue_opinion_terms_raw_i32: company_terms,
                    ..RuntimeCompanyMarketState::default()
                },
            )]),
            chairman_issue_opinion_terms_raw_i32: BTreeMap::from([(3, chairman_terms)]),
            ..RuntimeServiceState::default()
        },
    };

    assert_eq!(runtime_company_management_attitude(&state, 7), Some(58));
}

#[test]
fn reads_year_relative_company_stat_family_from_saved_market_matrix() {
    let mut year_stat_family_qword_bits = vec![
        0u64;
        ((RUNTIME_COMPANY_STAT_SLOT_COUNT + 2) * RUNTIME_COMPANY_YEAR_STAT_FAMILY_SPAN)
            as usize
    ];
    let write_year_value = |bits: &mut Vec<u64>, slot_id: u32, year_delta: u32, value: f64| {
        let index = (slot_id * RUNTIME_COMPANY_YEAR_STAT_FAMILY_SPAN + year_delta) as usize;
        bits[index] = value.to_bits();
    };
    write_year_value(&mut year_stat_family_qword_bits, 0x01, 1, 10.0);
    write_year_value(&mut year_stat_family_qword_bits, 0x02, 1, 20.0);
    write_year_value(&mut year_stat_family_qword_bits, 0x03, 1, 30.0);
    write_year_value(&mut year_stat_family_qword_bits, 0x04, 1, 40.0);
    write_year_value(&mut year_stat_family_qword_bits, 0x05, 1, 5.0);
    write_year_value(&mut year_stat_family_qword_bits, 0x06, 1, 6.0);
    write_year_value(&mut year_stat_family_qword_bits, 0x07, 1, 7.0);
    write_year_value(&mut year_stat_family_qword_bits, 0x08, 1, 8.0);
    write_year_value(&mut year_stat_family_qword_bits, 0x09, 1, 9.0);
    write_year_value(&mut year_stat_family_qword_bits, 0x0a, 1, 10.0);
    write_year_value(&mut year_stat_family_qword_bits, 0x0b, 1, 11.0);
    write_year_value(&mut year_stat_family_qword_bits, 0x0c, 1, 12.0);
    write_year_value(&mut year_stat_family_qword_bits, 0x0d, 1, 13.0);
    write_year_value(&mut year_stat_family_qword_bits, 0x0e, 1, 14.0);
    write_year_value(&mut year_stat_family_qword_bits, 0x0f, 1, 15.0);
    write_year_value(&mut year_stat_family_qword_bits, 0x10, 1, 16.0);
    write_year_value(&mut year_stat_family_qword_bits, 0x11, 1, 17.0);
    write_year_value(&mut year_stat_family_qword_bits, 0x12, 1, 18.0);
    write_year_value(&mut year_stat_family_qword_bits, 0x16, 1, 4.0);
    write_year_value(&mut year_stat_family_qword_bits, 0x17, 1, 10.0);
    write_year_value(&mut year_stat_family_qword_bits, 0x18, 1, 20.0);
    write_year_value(&mut year_stat_family_qword_bits, 0x19, 1, 25.0);
    write_year_value(&mut year_stat_family_qword_bits, 0x1a, 1, 50.0);
    write_year_value(&mut year_stat_family_qword_bits, 0x1b, 1, 100.0);
    write_year_value(&mut year_stat_family_qword_bits, 0x24, 1, 5.0);

    let mut special_stat_family_232a_qword_bits =
        vec![0u64; RUNTIME_COMPANY_STAT_SLOT_COUNT as usize];
    special_stat_family_232a_qword_bits[RUNTIME_COMPANY_STAT_SLOT_CURRENT_CASH as usize] =
        111.0f64.to_bits();

    let state = RuntimeState {
        calendar: CalendarPoint {
            year: 1845,
            month_slot: 0,
            phase_slot: 0,
            tick_slot: 0,
        },
        world_flags: BTreeMap::new(),
        save_profile: RuntimeSaveProfileState::default(),
        world_restore: RuntimeWorldRestoreState {
            packed_year_word_raw_u16: Some(1845),
            ..RuntimeWorldRestoreState::default()
        },
        metadata: BTreeMap::new(),
        companies: vec![RuntimeCompany {
            company_id: 7,
            current_cash: 125_000,
            debt: 0,
            credit_rating_score: None,
            prime_rate: None,
            active: true,
            available_track_laying_capacity: None,
            controller_kind: RuntimeCompanyControllerKind::Unknown,
            linked_chairman_profile_id: None,
            book_value_per_share: 2_620,
            investor_confidence: 0,
            management_attitude: 0,
            takeover_cooldown_year: None,
            merger_cooldown_year: None,
            track_piece_counts: RuntimeTrackPieceCounts::default(),
        }],
        selected_company_id: None,
        players: Vec::new(),
        selected_player_id: None,
        chairman_profiles: Vec::new(),
        selected_chairman_profile_id: None,
        trains: Vec::new(),
        locomotive_catalog: Vec::new(),
        cargo_catalog: Vec::new(),
        territories: Vec::new(),
        company_territory_track_piece_counts: Vec::new(),
        company_territory_access: Vec::new(),
        packed_event_collection: None,
        event_runtime_records: Vec::new(),
        candidate_availability: BTreeMap::new(),
        named_locomotive_availability: BTreeMap::new(),
        named_locomotive_cost: BTreeMap::new(),
        all_cargo_price_override: None,
        named_cargo_price_overrides: BTreeMap::new(),
        all_cargo_production_override: None,
        factory_cargo_production_override: None,
        farm_mine_cargo_production_override: None,
        named_cargo_production_overrides: BTreeMap::new(),
        cargo_production_overrides: BTreeMap::new(),
        world_runtime_variables: BTreeMap::new(),
        company_runtime_variables: BTreeMap::new(),
        player_runtime_variables: BTreeMap::new(),
        territory_runtime_variables: BTreeMap::new(),
        world_scalar_overrides: BTreeMap::new(),
        special_conditions: BTreeMap::new(),
        service_state: RuntimeServiceState {
            world_issue_opinion_base_terms_raw_i32: vec![0; 0x3b],
            company_market_state: BTreeMap::from([(
                7,
                RuntimeCompanyMarketState {
                    year_stat_family_qword_bits,
                    special_stat_family_232a_qword_bits,
                    ..RuntimeCompanyMarketState::default()
                },
            )]),
            ..RuntimeServiceState::default()
        },
    };

    let prior_year = RuntimeCompanyStatSelector {
        family_id: 1844,
        slot_id: 0x09,
    };
    assert_eq!(
        runtime_company_stat_value_f64(&state, 7, prior_year),
        Some(9.0)
    );
    assert_eq!(
        runtime_company_stat_value_f64(
            &state,
            7,
            RuntimeCompanyStatSelector {
                family_id: 1844,
                slot_id: 0x2c,
            },
        ),
        Some(100.0)
    );
    assert_eq!(
        runtime_company_stat_value_f64(
            &state,
            7,
            RuntimeCompanyStatSelector {
                family_id: 1844,
                slot_id: 0x2b,
            },
        ),
        Some(168.0)
    );
    assert_eq!(
        runtime_company_stat_value_f64(
            &state,
            7,
            RuntimeCompanyStatSelector {
                family_id: 1844,
                slot_id: 0x32,
            },
        ),
        Some(20.0)
    );
    assert_eq!(
        runtime_company_stat_value_f64(
            &state,
            7,
            RuntimeCompanyStatSelector {
                family_id: 1844,
                slot_id: 0x38,
            },
        ),
        Some(1.0)
    );
    assert_eq!(
        runtime_company_stat_value_f64(
            &state,
            7,
            RuntimeCompanyStatSelector {
                family_id: RUNTIME_COMPANY_STAT_FAMILY_SPECIAL_232A,
                slot_id: RUNTIME_COMPANY_STAT_SLOT_CURRENT_CASH,
            },
        ),
        Some(111.0)
    );
}

#[test]
fn carries_trailing_full_year_finance_lanes_into_annual_finance_state() {
    let mut year_stat_family_qword_bits = vec![
        0u64;
        (RUNTIME_COMPANY_STAT_SLOT_COUNT * RUNTIME_COMPANY_YEAR_STAT_FAMILY_SPAN)
            as usize
    ];
    let write_year_value = |bits: &mut Vec<u64>, slot_id: u32, year_delta: u32, value: f64| {
        let index = (slot_id * RUNTIME_COMPANY_YEAR_STAT_FAMILY_SPAN + year_delta) as usize;
        bits[index] = value.to_bits();
    };
    for (year_delta, revenue_parts, extra_profit_parts, fuel_cost) in [
        (
            1,
            [60.0, 50.0, 40.0, 30.0],
            [10.0, 9.0, 8.0, 7.0, 6.0, 5.0, 4.0],
            18.0,
        ),
        (
            2,
            [50.0, 45.0, 40.0, 35.0],
            [9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0],
            17.0,
        ),
        (
            3,
            [50.0, 40.0, 35.0, 35.0],
            [8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0],
            16.0,
        ),
        (
            4,
            [45.0, 40.0, 35.0, 30.0],
            [7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0],
            15.0,
        ),
    ] {
        for (slot_id, value) in [0x01, 0x02, 0x03, 0x04].into_iter().zip(revenue_parts) {
            write_year_value(&mut year_stat_family_qword_bits, slot_id, year_delta, value);
        }
        for (slot_id, value) in [0x05, 0x06, 0x07, 0x08, 0x0a, 0x0b, 0x0c]
            .into_iter()
            .zip(extra_profit_parts)
        {
            write_year_value(&mut year_stat_family_qword_bits, slot_id, year_delta, value);
        }
        write_year_value(
            &mut year_stat_family_qword_bits,
            0x09,
            year_delta,
            fuel_cost,
        );
    }

    let state = RuntimeState {
        calendar: CalendarPoint {
            year: 1845,
            month_slot: 0,
            phase_slot: 0,
            tick_slot: 0,
        },
        world_flags: BTreeMap::new(),
        save_profile: RuntimeSaveProfileState::default(),
        world_restore: RuntimeWorldRestoreState {
            packed_year_word_raw_u16: Some(1845),
            ..RuntimeWorldRestoreState::default()
        },
        metadata: BTreeMap::new(),
        companies: vec![RuntimeCompany {
            company_id: 7,
            current_cash: 125_000,
            debt: 0,
            credit_rating_score: None,
            prime_rate: None,
            active: true,
            available_track_laying_capacity: None,
            controller_kind: RuntimeCompanyControllerKind::Unknown,
            linked_chairman_profile_id: None,
            book_value_per_share: 2_620,
            investor_confidence: 0,
            management_attitude: 0,
            takeover_cooldown_year: None,
            merger_cooldown_year: None,
            track_piece_counts: RuntimeTrackPieceCounts::default(),
        }],
        selected_company_id: None,
        players: Vec::new(),
        selected_player_id: None,
        chairman_profiles: Vec::new(),
        selected_chairman_profile_id: None,
        trains: Vec::new(),
        locomotive_catalog: Vec::new(),
        cargo_catalog: Vec::new(),
        territories: Vec::new(),
        company_territory_track_piece_counts: Vec::new(),
        company_territory_access: Vec::new(),
        packed_event_collection: None,
        event_runtime_records: Vec::new(),
        candidate_availability: BTreeMap::new(),
        named_locomotive_availability: BTreeMap::new(),
        named_locomotive_cost: BTreeMap::new(),
        all_cargo_price_override: None,
        named_cargo_price_overrides: BTreeMap::new(),
        all_cargo_production_override: None,
        factory_cargo_production_override: None,
        farm_mine_cargo_production_override: None,
        named_cargo_production_overrides: BTreeMap::new(),
        cargo_production_overrides: BTreeMap::new(),
        world_runtime_variables: BTreeMap::new(),
        company_runtime_variables: BTreeMap::new(),
        player_runtime_variables: BTreeMap::new(),
        territory_runtime_variables: BTreeMap::new(),
        world_scalar_overrides: BTreeMap::new(),
        special_conditions: BTreeMap::new(),
        service_state: RuntimeServiceState {
            world_issue_opinion_base_terms_raw_i32: vec![0; 0x3b],
            company_market_state: BTreeMap::from([(
                7,
                RuntimeCompanyMarketState {
                    outstanding_shares: 20_000,
                    year_stat_family_qword_bits,
                    ..RuntimeCompanyMarketState::default()
                },
            )]),
            ..RuntimeServiceState::default()
        },
    };

    let finance_state =
        runtime_company_annual_finance_state(&state, 7).expect("annual finance state");
    assert_eq!(
        finance_state.trailing_full_year_year_words,
        vec![1844, 1843, 1842, 1841]
    );
    assert_eq!(
        finance_state.trailing_full_year_net_profits,
        vec![247, 229, 211, 193]
    );
    assert_eq!(
        finance_state.trailing_full_year_revenues,
        vec![180, 170, 160, 150]
    );
    assert_eq!(
        finance_state.trailing_full_year_fuel_costs,
        vec![18, 17, 16, 15]
    );
}
