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_zero_company_current_cash(state: &mut RuntimeState, company_id: u32) -> bool {
    let Some(current_cash) = crate::derived::runtime_company_stat_value(
        state,
        company_id,
        crate::event::metrics::RuntimeCompanyStatSelector {
            family_id: crate::event::metrics::RUNTIME_COMPANY_STAT_FAMILY_CONTROL_TRANSFER,
            slot_id: crate::event::metrics::RUNTIME_COMPANY_STAT_SLOT_CURRENT_CASH,
        },
    ) else {
        return false;
    };
    if current_cash == 0 {
        return true;
    }
    service_post_company_stat_delta(
        state,
        company_id,
        RUNTIME_COMPANY_STAT_SLOT_CURRENT_CASH,
        -(current_cash as f64),
        false,
    )
}

pub(crate) fn service_clear_company_live_bonds(state: &mut RuntimeState, company_id: u32) -> bool {
    let Some(market_state) = state
        .service_state
        .company_market_state
        .get_mut(&company_id)
    else {
        return false;
    };
    market_state.live_bond_slots.clear();
    market_state.bond_count = 0;
    market_state.largest_live_bond_principal = None;
    market_state.highest_coupon_live_bond_principal = None;
    true
}

pub(crate) fn service_apply_company_bankruptcy(state: &mut RuntimeState, company_id: u32) -> bool {
    let Some(bankruptcy_year) = state
        .world_restore
        .packed_year_word_raw_u16
        .map(u32::from)
        .or_else(|| Some(state.calendar.year))
    else {
        return false;
    };

    let mut company_mutated = false;
    if let Some(market_state) = state
        .service_state
        .company_market_state
        .get_mut(&company_id)
    {
        market_state.last_bankruptcy_year = bankruptcy_year;
        for slot in &mut market_state.live_bond_slots {
            slot.principal /= 2;
        }
        market_state
            .live_bond_slots
            .retain(|slot| slot.principal > 0);
        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;
    }

    let remaining_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>()
        });
    if let Some(company) = state
        .companies
        .iter_mut()
        .find(|company| company.company_id == company_id)
    {
        if let Some(remaining_debt) = remaining_debt {
            company.debt = remaining_debt.min(u64::from(u32::MAX)) as u64;
        }
        company_mutated = true;
    }

    company_mutated |= service_zero_company_current_cash(state, company_id);

    company_mutated
}
