use crate::engine::service::service_post_company_stat_delta;
use crate::event::metrics::RUNTIME_COMPANY_STAT_SLOT_CURRENT_CASH;
use crate::state::RuntimeState;

pub(crate) fn service_repay_matured_company_live_bonds_and_compact(
    state: &mut RuntimeState,
    company_id: u32,
) -> Option<u64> {
    let Some(current_year_word) = state
        .world_restore
        .packed_year_word_raw_u16
        .map(u32::from)
        .or_else(|| Some(state.calendar.year))
    else {
        return None;
    };
    let retired_principal_total = state
        .service_state
        .company_market_state
        .get(&company_id)
        .map(|market_state| {
            market_state
                .live_bond_slots
                .iter()
                .filter(|slot| slot.maturity_year != 0 && slot.maturity_year <= current_year_word)
                .map(|slot| u64::from(slot.principal))
                .sum::<u64>()
        })
        .unwrap_or(0);
    if retired_principal_total == 0 {
        return None;
    }

    let retired_principal_total_f64 = retired_principal_total as f64;
    let mut company_mutated = false;
    company_mutated |= service_post_company_stat_delta(
        state,
        company_id,
        RUNTIME_COMPANY_STAT_SLOT_CURRENT_CASH,
        -retired_principal_total_f64,
        false,
    );
    company_mutated |= service_post_company_stat_delta(
        state,
        company_id,
        0x12,
        retired_principal_total_f64,
        false,
    );

    if let Some(market_state) = state
        .service_state
        .company_market_state
        .get_mut(&company_id)
    {
        market_state
            .live_bond_slots
            .retain(|slot| slot.maturity_year == 0 || slot.maturity_year > current_year_word);
        for (slot_index, slot) in market_state.live_bond_slots.iter_mut().enumerate() {
            slot.slot_index = slot_index as u32;
        }
        market_state.bond_count = market_state.live_bond_slots.len().min(u8::MAX as usize) as u8;
        market_state.largest_live_bond_principal = market_state
            .live_bond_slots
            .iter()
            .map(|slot| slot.principal)
            .max();
        market_state.highest_coupon_live_bond_principal = market_state
            .live_bond_slots
            .iter()
            .filter_map(|slot| {
                let coupon = f32::from_bits(slot.coupon_rate_raw_u32) as f64;
                coupon.is_finite().then_some((coupon, slot.principal))
            })
            .max_by(|left, right| {
                left.0
                    .partial_cmp(&right.0)
                    .unwrap_or(std::cmp::Ordering::Equal)
            })
            .map(|(_, principal)| principal);
        company_mutated = true;
    }

    if let Some(company) = state
        .companies
        .iter_mut()
        .find(|company| company.company_id == company_id)
    {
        company.debt = state
            .service_state
            .company_market_state
            .get(&company_id)
            .map(|market_state| {
                market_state
                    .live_bond_slots
                    .iter()
                    .map(|slot| u64::from(slot.principal))
                    .sum::<u64>()
            })
            .unwrap_or(0);
        company_mutated = true;
    }

    company_mutated.then_some(retired_principal_total)
}
