use std::collections::BTreeMap;

use crate::inspect::smp::save_load::SmpLoadedSaveSlice;
use crate::state::{
    RuntimeChairmanProfile, RuntimeCompany, RuntimeCompanyMarketState,
    RuntimeCompanyPeriodicSideLatchState,
};

pub(super) struct CompanyProjection {
    pub(super) companies: Vec<RuntimeCompany>,
    pub(super) has_company_projection: bool,
    pub(super) has_company_selection_override: bool,
    pub(super) selected_company_id: Option<u32>,
    pub(super) company_market_state: BTreeMap<u32, RuntimeCompanyMarketState>,
    pub(super) company_periodic_side_latch_state:
        BTreeMap<u32, RuntimeCompanyPeriodicSideLatchState>,
    pub(super) world_issue_opinion_base_terms_raw_i32: Vec<i32>,
    pub(super) has_company_market_projection: bool,
}

pub(super) struct ChairmanProjection {
    pub(super) chairman_profiles: Vec<RuntimeChairmanProfile>,
    pub(super) has_chairman_projection: bool,
    pub(super) has_chairman_selection_override: bool,
    pub(super) selected_chairman_profile_id: Option<u32>,
    pub(super) chairman_issue_opinion_terms_raw_i32: BTreeMap<u32, Vec<i32>>,
    pub(super) chairman_personality_raw_u8: BTreeMap<u32, u8>,
}

pub(super) fn project_company_projection(
    save_slice: &SmpLoadedSaveSlice,
    metadata: &mut BTreeMap<String, String>,
) -> CompanyProjection {
    let (
        companies,
        has_company_projection,
        has_company_selection_override,
        selected_company_id,
        company_market_state,
        company_periodic_side_latch_state,
        world_issue_opinion_base_terms_raw_i32,
        has_company_market_projection,
    ) = if let Some(roster) = &save_slice.company_roster {
        metadata.insert(
            "save_slice.company_roster_source_kind".to_string(),
            roster.source_kind.clone(),
        );
        metadata.insert(
            "save_slice.company_roster_semantic_family".to_string(),
            roster.semantic_family.clone(),
        );
        metadata.insert(
            "save_slice.company_roster_entry_count".to_string(),
            roster.observed_entry_count.to_string(),
        );
        let market_state = roster
            .entries
            .iter()
            .filter_map(|entry| {
                entry
                    .market_state
                    .as_ref()
                    .map(|state| (entry.company_id, state.clone()))
            })
            .collect::<BTreeMap<_, _>>();
        let periodic_side_latch_state = roster
            .entries
            .iter()
            .map(|entry| {
                (
                    entry.company_id,
                    RuntimeCompanyPeriodicSideLatchState {
                        preferred_locomotive_engine_type_raw_u8: entry
                            .preferred_locomotive_engine_type_raw_u8,
                        city_connection_latch: entry
                            .market_state
                            .as_ref()
                            .map(|state| state.city_connection_latch)
                            .unwrap_or(false),
                        linked_transit_latch: entry
                            .market_state
                            .as_ref()
                            .map(|state| state.linked_transit_latch)
                            .unwrap_or(false),
                    },
                )
            })
            .collect::<BTreeMap<_, _>>();
        metadata.insert(
            "save_slice.company_market_state_owner_count".to_string(),
            market_state.len().to_string(),
        );
        if let Some(selected_company_id) = roster.selected_company_id {
            metadata.insert(
                "save_slice.selected_company_id".to_string(),
                selected_company_id.to_string(),
            );
        }
        if roster.entries.is_empty() {
            (
                Vec::new(),
                false,
                roster.selected_company_id.is_some(),
                roster.selected_company_id,
                BTreeMap::new(),
                periodic_side_latch_state,
                save_slice
                    .world_issue_37_state
                    .as_ref()
                    .map(|state| state.issue_opinion_base_terms_raw_i32.clone())
                    .unwrap_or_default(),
                false,
            )
        } else {
            (
                roster
                    .entries
                    .iter()
                    .map(|entry| RuntimeCompany {
                        company_id: entry.company_id,
                        current_cash: entry.current_cash,
                        debt: entry.debt,
                        credit_rating_score: entry.credit_rating_score,
                        prime_rate: entry.prime_rate,
                        active: entry.active,
                        available_track_laying_capacity: entry.available_track_laying_capacity,
                        controller_kind: entry.controller_kind,
                        linked_chairman_profile_id: entry.linked_chairman_profile_id,
                        book_value_per_share: entry.book_value_per_share,
                        investor_confidence: entry.investor_confidence,
                        management_attitude: entry.management_attitude,
                        takeover_cooldown_year: entry.takeover_cooldown_year,
                        merger_cooldown_year: entry.merger_cooldown_year,
                        track_piece_counts: entry.track_piece_counts,
                    })
                    .collect::<Vec<_>>(),
                true,
                roster.selected_company_id.is_some(),
                roster.selected_company_id,
                market_state,
                periodic_side_latch_state,
                save_slice
                    .world_issue_37_state
                    .as_ref()
                    .map(|state| state.issue_opinion_base_terms_raw_i32.clone())
                    .unwrap_or_default(),
                true,
            )
        }
    } else {
        (
            Vec::new(),
            false,
            false,
            None,
            BTreeMap::new(),
            BTreeMap::new(),
            save_slice
                .world_issue_37_state
                .as_ref()
                .map(|state| state.issue_opinion_base_terms_raw_i32.clone())
                .unwrap_or_default(),
            false,
        )
    };

    CompanyProjection {
        companies,
        has_company_projection,
        has_company_selection_override,
        selected_company_id,
        company_market_state,
        company_periodic_side_latch_state,
        world_issue_opinion_base_terms_raw_i32,
        has_company_market_projection,
    }
}

pub(super) fn project_chairman_projection(
    save_slice: &SmpLoadedSaveSlice,
    metadata: &mut BTreeMap<String, String>,
) -> ChairmanProjection {
    let (
        chairman_profiles,
        has_chairman_projection,
        has_chairman_selection_override,
        selected_chairman_profile_id,
        chairman_issue_opinion_terms_raw_i32,
        chairman_personality_raw_u8,
    ) = if let Some(table) = &save_slice.chairman_profile_table {
        metadata.insert(
            "save_slice.chairman_profile_table_source_kind".to_string(),
            table.source_kind.clone(),
        );
        metadata.insert(
            "save_slice.chairman_profile_table_semantic_family".to_string(),
            table.semantic_family.clone(),
        );
        metadata.insert(
            "save_slice.chairman_profile_table_entry_count".to_string(),
            table.observed_entry_count.to_string(),
        );
        if let Some(selected_chairman_profile_id) = table.selected_chairman_profile_id {
            metadata.insert(
                "save_slice.selected_chairman_profile_id".to_string(),
                selected_chairman_profile_id.to_string(),
            );
        }
        if table.entries.is_empty() {
            (
                Vec::new(),
                false,
                table.selected_chairman_profile_id.is_some(),
                table.selected_chairman_profile_id,
                BTreeMap::new(),
                BTreeMap::new(),
            )
        } else {
            (
                table
                    .entries
                    .iter()
                    .map(|entry| RuntimeChairmanProfile {
                        profile_id: entry.profile_id,
                        name: entry.name.clone(),
                        active: entry.active,
                        current_cash: entry.current_cash,
                        linked_company_id: entry.linked_company_id,
                        company_holdings: entry.company_holdings.clone(),
                        holdings_value_total: entry.holdings_value_total,
                        net_worth_total: entry.net_worth_total,
                        purchasing_power_total: entry.purchasing_power_total,
                    })
                    .collect::<Vec<_>>(),
                true,
                table.selected_chairman_profile_id.is_some(),
                table.selected_chairman_profile_id,
                table
                    .entries
                    .iter()
                    .map(|entry| (entry.profile_id, entry.issue_opinion_terms_raw_i32.clone()))
                    .collect::<BTreeMap<_, _>>(),
                table
                    .entries
                    .iter()
                    .filter_map(|entry| {
                        entry
                            .personality_byte_0x291
                            .map(|value| (entry.profile_id, value))
                    })
                    .collect::<BTreeMap<_, _>>(),
            )
        }
    } else {
        (
            Vec::new(),
            false,
            false,
            None,
            BTreeMap::new(),
            BTreeMap::new(),
        )
    };

    ChairmanProjection {
        chairman_profiles,
        has_chairman_projection,
        has_chairman_selection_override,
        selected_chairman_profile_id,
        chairman_issue_opinion_terms_raw_i32,
        chairman_personality_raw_u8,
    }
}
