use std::collections::{BTreeMap, BTreeSet};

use crate::derived::{
    derive_runtime_chairman_holdings_share_price_total, rounded_cached_share_price_i64,
    runtime_company_control_transfer_stat_value_f64, runtime_company_credit_rating,
    runtime_company_direct_float_field_value_f64, runtime_company_investor_confidence,
    runtime_company_management_attitude, runtime_company_prime_rate, runtime_round_f64_to_i64,
};
use crate::event::metrics::RUNTIME_COMPANY_STAT_SLOT_CURRENT_CASH;
use crate::state::{RuntimeCompanyPeriodicSideLatchState, RuntimeState};

impl RuntimeState {
    pub fn refresh_derived_market_state(&mut self) {
        let company_share_prices = self
            .service_state
            .company_market_state
            .iter()
            .filter_map(|(company_id, market_state)| {
                rounded_cached_share_price_i64(market_state.cached_share_price_raw_u32)
                    .map(|share_price| (*company_id, share_price))
            })
            .collect::<BTreeMap<_, _>>();

        let company_refresh = self
            .companies
            .iter()
            .map(|company| {
                let current_cash = runtime_company_control_transfer_stat_value_f64(
                    self,
                    company.company_id,
                    RUNTIME_COMPANY_STAT_SLOT_CURRENT_CASH,
                )
                .and_then(runtime_round_f64_to_i64);
                let book_value_per_share =
                    runtime_company_direct_float_field_value_f64(self, company.company_id, 0x32f)
                        .and_then(runtime_round_f64_to_i64);
                let prime_rate = runtime_company_prime_rate(self, company.company_id);
                let credit_rating_score = runtime_company_credit_rating(self, company.company_id);
                let investor_confidence =
                    runtime_company_investor_confidence(self, company.company_id);
                let management_attitude =
                    runtime_company_management_attitude(self, company.company_id);
                (
                    company.company_id,
                    current_cash,
                    book_value_per_share,
                    credit_rating_score,
                    prime_rate,
                    investor_confidence,
                    management_attitude,
                )
            })
            .collect::<Vec<_>>();

        for company in &mut self.companies {
            if let Some((
                _,
                current_cash,
                book_value_per_share,
                credit_rating_score,
                prime_rate,
                investor_confidence,
                management_attitude,
            )) = company_refresh
                .iter()
                .find(|(company_id, _, _, _, _, _, _)| *company_id == company.company_id)
            {
                if let Some(current_cash) = current_cash {
                    company.current_cash = *current_cash;
                }
                if let Some(book_value_per_share) = book_value_per_share {
                    company.book_value_per_share = *book_value_per_share;
                }
                if let Some(credit_rating_score) = credit_rating_score {
                    company.credit_rating_score = Some(*credit_rating_score);
                }
                if let Some(prime_rate) = prime_rate {
                    company.prime_rate = Some(*prime_rate);
                }
                if let Some(investor_confidence) = investor_confidence {
                    company.investor_confidence = *investor_confidence;
                }
                if let Some(management_attitude) = management_attitude {
                    company.management_attitude = *management_attitude;
                }
            }
        }

        let known_company_ids = self
            .companies
            .iter()
            .map(|company| company.company_id)
            .collect::<BTreeSet<_>>();
        self.service_state
            .company_periodic_side_latch_state
            .retain(|company_id, _| known_company_ids.contains(company_id));
        for (company_id, market_state) in &self.service_state.company_market_state {
            self.service_state
                .company_periodic_side_latch_state
                .entry(*company_id)
                .or_insert_with(|| RuntimeCompanyPeriodicSideLatchState {
                    preferred_locomotive_engine_type_raw_u8: None,
                    city_connection_latch: market_state.city_connection_latch,
                    linked_transit_latch: market_state.linked_transit_latch,
                });
        }

        for profile in &mut self.chairman_profiles {
            let preserved_threshold_adjusted_holdings_component = profile
                .purchasing_power_total
                .saturating_sub(profile.current_cash)
                .max(0);
            if let Some(holdings_value_total) = derive_runtime_chairman_holdings_share_price_total(
                &profile.company_holdings,
                &company_share_prices,
            ) {
                profile.holdings_value_total = holdings_value_total;
            }
            profile.net_worth_total = profile
                .current_cash
                .saturating_add(profile.holdings_value_total);
            profile.purchasing_power_total = profile
                .current_cash
                .saturating_add(preserved_threshold_adjusted_holdings_component)
                .max(profile.net_worth_total);
        }
    }
}
