use std::collections::BTreeMap;

use super::super::SaveSliceProjection;
use crate::state::{RuntimeServiceState, RuntimeWorldRestoreState};
use crate::{CalendarPoint, RuntimeState};

pub(super) fn build_standalone_runtime_state(projection: SaveSliceProjection) -> RuntimeState {
    RuntimeState {
        calendar: CalendarPoint {
            year: 1830,
            month_slot: 0,
            phase_slot: 0,
            tick_slot: 0,
        },
        world_flags: projection.world_flags,
        save_profile: projection.save_profile,
        world_restore: projection.world_restore,
        metadata: projection.metadata,
        companies: projection.companies,
        selected_company_id: if projection.has_company_projection {
            projection.selected_company_id
        } else {
            None
        },
        players: Vec::new(),
        selected_player_id: None,
        chairman_profiles: projection.chairman_profiles,
        selected_chairman_profile_id: if projection.has_chairman_projection {
            projection.selected_chairman_profile_id
        } else {
            None
        },
        trains: Vec::new(),
        locomotive_catalog: projection.locomotive_catalog.unwrap_or_default(),
        cargo_catalog: projection.cargo_catalog.unwrap_or_default(),
        territories: Vec::new(),
        company_territory_track_piece_counts: Vec::new(),
        company_territory_access: Vec::new(),
        packed_event_collection: projection.packed_event_collection,
        event_runtime_records: projection.event_runtime_records,
        candidate_availability: projection.candidate_availability,
        named_locomotive_availability: projection.named_locomotive_availability,
        named_locomotive_cost: projection.named_locomotive_cost,
        all_cargo_price_override: projection.all_cargo_price_override,
        named_cargo_price_overrides: projection.named_cargo_price_overrides,
        all_cargo_production_override: projection.all_cargo_production_override,
        factory_cargo_production_override: projection.factory_cargo_production_override,
        farm_mine_cargo_production_override: projection.farm_mine_cargo_production_override,
        named_cargo_production_overrides: projection.named_cargo_production_overrides,
        cargo_production_overrides: projection.cargo_production_overrides,
        world_runtime_variables: BTreeMap::new(),
        company_runtime_variables: BTreeMap::new(),
        player_runtime_variables: BTreeMap::new(),
        territory_runtime_variables: BTreeMap::new(),
        world_scalar_overrides: projection.world_scalar_overrides,
        special_conditions: projection.special_conditions,
        service_state: RuntimeServiceState {
            world_issue_opinion_base_terms_raw_i32: projection
                .world_issue_opinion_base_terms_raw_i32,
            company_market_state: projection.company_market_state,
            company_periodic_side_latch_state: projection.company_periodic_side_latch_state,
            chairman_issue_opinion_terms_raw_i32: projection.chairman_issue_opinion_terms_raw_i32,
            chairman_personality_raw_u8: projection.chairman_personality_raw_u8,
            near_city_acquisition_regions: projection.near_city_acquisition_regions,
            near_city_acquisition_sites: projection.near_city_acquisition_sites,
            ..RuntimeServiceState::default()
        },
    }
}

pub(super) fn build_overlay_runtime_state(
    base_state: &RuntimeState,
    projection: SaveSliceProjection,
) -> RuntimeState {
    let mut world_flags = base_state.world_flags.clone();
    world_flags.retain(|key, _| !key.starts_with("save_slice."));
    world_flags.extend(projection.world_flags);

    let mut metadata = base_state.metadata.clone();
    metadata.retain(|key, _| !key.starts_with("save_slice."));
    metadata.extend(projection.metadata);

    RuntimeState {
        calendar: base_state.calendar,
        world_flags,
        save_profile: projection.save_profile,
        world_restore: RuntimeWorldRestoreState {
            territory_access_cost: base_state.world_restore.territory_access_cost,
            ..projection.world_restore
        },
        metadata,
        companies: if projection.has_company_projection {
            projection.companies
        } else {
            base_state.companies.clone()
        },
        selected_company_id: if projection.has_company_projection
            || projection.has_company_selection_override
        {
            projection.selected_company_id
        } else {
            base_state.selected_company_id
        },
        players: base_state.players.clone(),
        selected_player_id: base_state.selected_player_id,
        chairman_profiles: if projection.has_chairman_projection {
            projection.chairman_profiles
        } else {
            base_state.chairman_profiles.clone()
        },
        selected_chairman_profile_id: if projection.has_chairman_projection
            || projection.has_chairman_selection_override
        {
            projection.selected_chairman_profile_id
        } else {
            base_state.selected_chairman_profile_id
        },
        trains: base_state.trains.clone(),
        locomotive_catalog: projection
            .locomotive_catalog
            .unwrap_or_else(|| base_state.locomotive_catalog.clone()),
        cargo_catalog: projection
            .cargo_catalog
            .unwrap_or_else(|| base_state.cargo_catalog.clone()),
        territories: base_state.territories.clone(),
        company_territory_track_piece_counts: base_state
            .company_territory_track_piece_counts
            .clone(),
        company_territory_access: base_state.company_territory_access.clone(),
        packed_event_collection: projection.packed_event_collection,
        event_runtime_records: projection.event_runtime_records,
        candidate_availability: projection.candidate_availability,
        named_locomotive_availability: projection.named_locomotive_availability,
        named_locomotive_cost: base_state.named_locomotive_cost.clone(),
        all_cargo_price_override: base_state.all_cargo_price_override,
        named_cargo_price_overrides: base_state.named_cargo_price_overrides.clone(),
        all_cargo_production_override: base_state.all_cargo_production_override,
        factory_cargo_production_override: base_state.factory_cargo_production_override,
        farm_mine_cargo_production_override: base_state.farm_mine_cargo_production_override,
        named_cargo_production_overrides: base_state.named_cargo_production_overrides.clone(),
        cargo_production_overrides: base_state.cargo_production_overrides.clone(),
        world_runtime_variables: base_state.world_runtime_variables.clone(),
        company_runtime_variables: base_state.company_runtime_variables.clone(),
        player_runtime_variables: base_state.player_runtime_variables.clone(),
        territory_runtime_variables: base_state.territory_runtime_variables.clone(),
        world_scalar_overrides: base_state.world_scalar_overrides.clone(),
        special_conditions: projection.special_conditions,
        service_state: RuntimeServiceState {
            world_issue_opinion_base_terms_raw_i32: if projection
                .world_issue_opinion_base_terms_raw_i32
                .is_empty()
            {
                base_state
                    .service_state
                    .world_issue_opinion_base_terms_raw_i32
                    .clone()
            } else {
                projection.world_issue_opinion_base_terms_raw_i32
            },
            company_market_state: if projection.has_company_market_projection {
                projection.company_market_state
            } else {
                base_state.service_state.company_market_state.clone()
            },
            company_periodic_side_latch_state: if projection.has_company_market_projection {
                projection.company_periodic_side_latch_state
            } else {
                base_state
                    .service_state
                    .company_periodic_side_latch_state
                    .clone()
            },
            chairman_issue_opinion_terms_raw_i32: if projection.has_chairman_projection {
                projection.chairman_issue_opinion_terms_raw_i32
            } else {
                base_state
                    .service_state
                    .chairman_issue_opinion_terms_raw_i32
                    .clone()
            },
            chairman_personality_raw_u8: if projection.has_chairman_projection {
                projection.chairman_personality_raw_u8
            } else {
                base_state.service_state.chairman_personality_raw_u8.clone()
            },
            near_city_acquisition_regions: if projection.has_near_city_projection {
                projection.near_city_acquisition_regions
            } else {
                base_state
                    .service_state
                    .near_city_acquisition_regions
                    .clone()
            },
            near_city_acquisition_sites: if projection.has_near_city_projection {
                projection.near_city_acquisition_sites
            } else {
                base_state.service_state.near_city_acquisition_sites.clone()
            },
            ..base_state.service_state.clone()
        },
    }
}
