use crate::derived::runtime_round_f64_to_i64;
use crate::event::metrics::{
    RUNTIME_COMPANY_STAT_SLOT_COUNT, RUNTIME_COMPANY_STAT_SLOT_CURRENT_CASH,
    RUNTIME_COMPANY_YEAR_STAT_FAMILY_SPAN,
};
use crate::state::{RuntimeCompanyMarketState, RuntimeState};

pub(crate) fn service_decode_saved_f64_bits(raw_bits: u64) -> Option<f64> {
    let value = f64::from_bits(raw_bits);
    value.is_finite().then_some(value)
}

pub(crate) fn service_ensure_company_stat_post_capacity(
    market_state: &mut RuntimeCompanyMarketState,
    slot_id: u32,
) -> Option<usize> {
    let index = slot_id
        .checked_mul(RUNTIME_COMPANY_YEAR_STAT_FAMILY_SPAN)?
        .try_into()
        .ok()?;
    let required_year_len =
        ((RUNTIME_COMPANY_STAT_SLOT_COUNT + 2) * RUNTIME_COMPANY_YEAR_STAT_FAMILY_SPAN) as usize;
    if market_state.year_stat_family_qword_bits.len() < required_year_len {
        market_state
            .year_stat_family_qword_bits
            .resize(required_year_len, 0.0f64.to_bits());
    }
    let required_special_len = RUNTIME_COMPANY_STAT_SLOT_COUNT as usize;
    if market_state.special_stat_family_232a_qword_bits.len() < required_special_len {
        market_state
            .special_stat_family_232a_qword_bits
            .resize(required_special_len, 0.0f64.to_bits());
    }
    Some(index)
}

pub(crate) fn service_post_company_stat_delta(
    state: &mut RuntimeState,
    company_id: u32,
    slot_id: u32,
    delta: f64,
    mirror_cash_totals: bool,
) -> bool {
    if !delta.is_finite() {
        return false;
    }

    let Some(refreshed_current_cash) = ({
        let Some(market_state) = state
            .service_state
            .company_market_state
            .get_mut(&company_id)
        else {
            return false;
        };
        let Some(index) = service_ensure_company_stat_post_capacity(market_state, slot_id) else {
            return false;
        };
        let prior_year_value = market_state
            .year_stat_family_qword_bits
            .get(index)
            .copied()
            .and_then(service_decode_saved_f64_bits)
            .unwrap_or(0.0);
        market_state.year_stat_family_qword_bits[index] = (prior_year_value + delta).to_bits();

        let special_index = slot_id as usize;
        let prior_special_value = market_state
            .special_stat_family_232a_qword_bits
            .get(special_index)
            .copied()
            .and_then(service_decode_saved_f64_bits)
            .unwrap_or(0.0);
        market_state.special_stat_family_232a_qword_bits[special_index] =
            (prior_special_value + delta).to_bits();

        if mirror_cash_totals {
            let cash_index = RUNTIME_COMPANY_STAT_SLOT_CURRENT_CASH as usize;
            let prior_cash_shadow_value = market_state
                .special_stat_family_232a_qword_bits
                .get(cash_index)
                .copied()
                .and_then(service_decode_saved_f64_bits)
                .unwrap_or(0.0);
            market_state.special_stat_family_232a_qword_bits[cash_index] =
                (prior_cash_shadow_value + delta).to_bits();
        }

        market_state
            .year_stat_family_qword_bits
            .get(
                (RUNTIME_COMPANY_STAT_SLOT_CURRENT_CASH * RUNTIME_COMPANY_YEAR_STAT_FAMILY_SPAN)
                    as usize,
            )
            .copied()
            .and_then(service_decode_saved_f64_bits)
            .and_then(runtime_round_f64_to_i64)
    }) else {
        return false;
    };

    if let Some(company) = state
        .companies
        .iter_mut()
        .find(|company| company.company_id == company_id)
    {
        company.current_cash = refreshed_current_cash;
        true
    } else {
        false
    }
}

pub(crate) fn service_set_company_direct_float_field(
    state: &mut RuntimeState,
    company_id: u32,
    field_offset: u32,
    value: f64,
) -> bool {
    if !value.is_finite() {
        return false;
    }
    let Some(market_state) = state
        .service_state
        .company_market_state
        .get_mut(&company_id)
    else {
        return false;
    };
    market_state
        .direct_control_transfer_float_fields_raw_u32
        .insert(field_offset, (value as f32).to_bits());
    true
}

pub(crate) fn service_set_company_cached_share_price(
    state: &mut RuntimeState,
    company_id: u32,
    value: f64,
) -> bool {
    if !value.is_finite() {
        return false;
    }
    let Some(market_state) = state
        .service_state
        .company_market_state
        .get_mut(&company_id)
    else {
        return false;
    };
    market_state.cached_share_price_raw_u32 = (value as f32).to_bits();
    true
}

pub(crate) fn service_set_company_issue_opinion_total(
    state: &mut RuntimeState,
    company_id: u32,
    issue_id: u32,
    target_total: i64,
) -> bool {
    let current_total = crate::derived::runtime_world_issue_opinion_term_sum_raw(
        state,
        issue_id,
        state
            .companies
            .iter()
            .find(|company| company.company_id == company_id)
            .and_then(|company| company.linked_chairman_profile_id),
        Some(company_id),
        None,
    )
    .unwrap_or(0);
    let Some(market_state) = state
        .service_state
        .company_market_state
        .get_mut(&company_id)
    else {
        return false;
    };
    let issue_index = issue_id as usize;
    if market_state.issue_opinion_terms_raw_i32.len() <= issue_index {
        market_state
            .issue_opinion_terms_raw_i32
            .resize(issue_index + 1, 0);
    }
    let prior_company_term = i64::from(market_state.issue_opinion_terms_raw_i32[issue_index]);
    let next_company_term = prior_company_term.saturating_add(target_total - current_total);
    let Ok(next_company_term_i32) = i32::try_from(next_company_term) else {
        return false;
    };
    market_state.issue_opinion_terms_raw_i32[issue_index] = next_company_term_i32;
    true
}

pub(crate) fn service_set_company_prime_rate_target(
    state: &mut RuntimeState,
    company_id: u32,
    value: i64,
) -> bool {
    let Some(baseline) = crate::derived::runtime_world_prime_rate_baseline(state) else {
        return false;
    };
    let target_raw_sum = ((value as f64 - baseline) * 100.0).round();
    if !target_raw_sum.is_finite() {
        return false;
    }
    service_set_company_issue_opinion_total(
        state,
        company_id,
        crate::event::metrics::RUNTIME_WORLD_ISSUE_PRIME_RATE,
        target_raw_sum as i64,
    )
}

pub(crate) fn service_set_company_credit_rating_target(
    state: &mut RuntimeState,
    company_id: u32,
    value: i64,
) -> bool {
    let Some(current_rating) = crate::derived::runtime_company_credit_rating(state, company_id)
    else {
        return false;
    };
    let current_issue_total = crate::derived::runtime_world_issue_opinion_term_sum_raw(
        state,
        crate::event::metrics::RUNTIME_WORLD_ISSUE_CREDIT_MARKET,
        state
            .companies
            .iter()
            .find(|company| company.company_id == company_id)
            .and_then(|company| company.linked_chairman_profile_id),
        Some(company_id),
        None,
    )
    .unwrap_or(0);
    service_set_company_issue_opinion_total(
        state,
        company_id,
        crate::event::metrics::RUNTIME_WORLD_ISSUE_CREDIT_MARKET,
        current_issue_total.saturating_add(value.saturating_sub(current_rating)),
    )
}
