use crate::derived::{
    runtime_company_annual_bond_policy_state, runtime_company_annual_creditor_pressure_state,
    runtime_company_annual_deep_distress_state, runtime_company_annual_finance_state,
    runtime_company_book_value_per_share, runtime_company_control_transfer_stat_value_f64,
    runtime_company_highest_live_bond_coupon_rate,
    runtime_company_support_adjusted_share_price_scalar,
    runtime_company_support_adjusted_share_price_scalar_with_pressure_f64,
    runtime_company_unassigned_share_pool, runtime_round_f64_to_i64,
    runtime_world_annual_finance_mode_active, runtime_world_bond_issue_and_repayment_allowed,
    runtime_world_building_density_growth_setting, runtime_world_stock_issue_and_buyback_allowed,
};
use crate::event::metrics::RUNTIME_COMPANY_STAT_SLOT_CURRENT_CASH;
use crate::state::{
    RuntimeCompanyAnnualStockIssueState, RuntimeCompanyAnnualStockRepurchaseState, RuntimeState,
};

pub(super) fn runtime_chairman_stock_repurchase_factor_f64(
    state: &RuntimeState,
    chairman_profile_id: Option<u32>,
) -> Option<f64> {
    let personality_byte = chairman_profile_id
        .and_then(|profile_id| {
            state
                .service_state
                .chairman_personality_raw_u8
                .get(&profile_id)
        })
        .copied();
    let mut factor = personality_byte
        .map(|byte| (f64::from(byte) * 39.0 + 300.0) / 400.0)
        .unwrap_or(1.0);
    if runtime_world_building_density_growth_setting(state) == Some(1) {
        factor *= 1.6;
    }
    Some(factor)
}

pub fn runtime_company_annual_stock_repurchase_state(
    state: &RuntimeState,
    company_id: u32,
) -> Option<RuntimeCompanyAnnualStockRepurchaseState> {
    let annual_finance_state = runtime_company_annual_finance_state(state, company_id)?;
    let company = state
        .companies
        .iter()
        .find(|company| company.company_id == company_id)?;
    let current_cash = runtime_company_control_transfer_stat_value_f64(
        state,
        company_id,
        RUNTIME_COMPANY_STAT_SLOT_CURRENT_CASH,
    )
    .and_then(runtime_round_f64_to_i64);
    let support_adjusted_share_price_scalar =
        runtime_company_support_adjusted_share_price_scalar(state, company_id);
    let repurchase_factor =
        runtime_chairman_stock_repurchase_factor_f64(state, company.linked_chairman_profile_id)?;
    let repurchase_factor_basis_points = runtime_round_f64_to_i64(repurchase_factor * 100.0);
    let stock_value_gate_cash_floor = runtime_round_f64_to_i64(repurchase_factor * 800_000.0);
    let affordability_cash_floor = support_adjusted_share_price_scalar
        .and_then(|value| runtime_round_f64_to_i64(value * repurchase_factor * 1_000.0 * 1.2));
    let support_adjusted_share_price_scalar =
        support_adjusted_share_price_scalar.and_then(runtime_round_f64_to_i64);
    let unassigned_share_pool = runtime_company_unassigned_share_pool(state, company_id);
    let eligible_for_single_batch_repurchase = runtime_world_annual_finance_mode_active(state)
        == Some(true)
        && runtime_world_stock_issue_and_buyback_allowed(state) == Some(true)
        && annual_finance_state.city_connection_latch
        && current_cash
            .zip(stock_value_gate_cash_floor)
            .is_some_and(|(value, floor)| value >= floor)
        && current_cash
            .zip(affordability_cash_floor)
            .is_some_and(|(value, floor)| value >= floor)
        && unassigned_share_pool.is_some_and(|value| value >= 1_000);
    Some(RuntimeCompanyAnnualStockRepurchaseState {
        company_id,
        annual_mode_active: runtime_world_annual_finance_mode_active(state),
        stock_issue_and_buyback_allowed: runtime_world_stock_issue_and_buyback_allowed(state),
        city_connection_latch: annual_finance_state.city_connection_latch,
        building_density_growth_setting: runtime_world_building_density_growth_setting(state),
        linked_chairman_profile_id: company.linked_chairman_profile_id,
        linked_chairman_personality_raw_u8: company
            .linked_chairman_profile_id
            .and_then(|profile_id| {
                state
                    .service_state
                    .chairman_personality_raw_u8
                    .get(&profile_id)
            })
            .copied(),
        repurchase_batch_size: Some(1_000),
        repurchase_factor_basis_points,
        current_cash,
        stock_value_gate_cash_floor,
        support_adjusted_share_price_scalar,
        affordability_cash_floor,
        unassigned_share_pool,
        eligible_for_single_batch_repurchase,
    })
}

pub(super) fn runtime_company_stock_issue_price_to_book_ratio_f64(
    pressured_support_adjusted_share_price_scalar: f64,
    book_value_per_share: f64,
) -> Option<f64> {
    let denominator = book_value_per_share.max(1.0);
    if !pressured_support_adjusted_share_price_scalar.is_finite() || !denominator.is_finite() {
        return None;
    }
    Some(pressured_support_adjusted_share_price_scalar / denominator)
}

pub(super) fn runtime_company_stock_issue_minimum_price_to_book_ratio_f64(
    highest_coupon_rate: f64,
) -> Option<f64> {
    if !highest_coupon_rate.is_finite() || highest_coupon_rate <= 0.0 {
        return None;
    }
    Some(if highest_coupon_rate <= 0.07 {
        1.30
    } else if highest_coupon_rate <= 0.08 {
        1.20
    } else if highest_coupon_rate <= 0.09 {
        1.10
    } else if highest_coupon_rate <= 0.10 {
        0.95
    } else if highest_coupon_rate <= 0.11 {
        0.80
    } else if highest_coupon_rate <= 0.12 {
        0.62
    } else if highest_coupon_rate <= 0.13 {
        0.50
    } else if highest_coupon_rate <= 0.14 {
        0.35
    } else {
        return None;
    })
}

pub fn runtime_company_annual_stock_issue_state(
    state: &RuntimeState,
    company_id: u32,
) -> Option<RuntimeCompanyAnnualStockIssueState> {
    const ISSUE_PROCEEDS_CAP: i64 = 55_000;
    const SHARE_PRICE_FLOOR: i64 = 22;
    const ONE_YEAR_ABSOLUTE_COUNTER_SPAN: i64 = 12 * 28 * 24 * 60;

    let annual_finance_state = runtime_company_annual_finance_state(state, company_id)?;
    let current_cash = runtime_company_control_transfer_stat_value_f64(
        state,
        company_id,
        RUNTIME_COMPANY_STAT_SLOT_CURRENT_CASH,
    )
    .and_then(runtime_round_f64_to_i64);
    let highest_coupon_live_bond_principal =
        annual_finance_state.highest_coupon_live_bond_principal;
    let highest_coupon_live_bond_rate =
        runtime_company_highest_live_bond_coupon_rate(state, company_id);
    let highest_coupon_live_bond_rate_basis_points =
        highest_coupon_live_bond_rate.and_then(|value| runtime_round_f64_to_i64(value * 10_000.0));
    let mut initial_issue_batch_size =
        (annual_finance_state.outstanding_shares / 10 / 1_000) * 1_000;
    if initial_issue_batch_size < 2_000 {
        initial_issue_batch_size = 2_000;
    }
    let initial_issue_batch_size = Some(initial_issue_batch_size);
    let mut trimmed_issue_batch_size = initial_issue_batch_size?;
    let mut pressured_support_adjusted_share_price_scalar =
        runtime_company_support_adjusted_share_price_scalar_with_pressure_f64(
            state,
            company_id,
            -(trimmed_issue_batch_size as i64),
        );
    let mut pressured_proceeds = pressured_support_adjusted_share_price_scalar
        .and_then(|value| runtime_round_f64_to_i64(value * trimmed_issue_batch_size as f64));
    while trimmed_issue_batch_size > 2_000
        && pressured_proceeds.is_some_and(|value| value > ISSUE_PROCEEDS_CAP)
    {
        trimmed_issue_batch_size = trimmed_issue_batch_size.saturating_sub(1_000);
        pressured_support_adjusted_share_price_scalar =
            runtime_company_support_adjusted_share_price_scalar_with_pressure_f64(
                state,
                company_id,
                -(trimmed_issue_batch_size as i64),
            );
        pressured_proceeds = pressured_support_adjusted_share_price_scalar
            .and_then(|value| runtime_round_f64_to_i64(value * trimmed_issue_batch_size as f64));
    }
    let pressured_support_adjusted_share_price_scalar_i64 =
        pressured_support_adjusted_share_price_scalar.and_then(runtime_round_f64_to_i64);
    let book_value_per_share_floor_applied =
        runtime_company_book_value_per_share(state, company_id).map(|value| value.max(1));
    let price_to_book_ratio = pressured_support_adjusted_share_price_scalar
        .zip(book_value_per_share_floor_applied)
        .and_then(|(share_price, book_value)| {
            runtime_company_stock_issue_price_to_book_ratio_f64(share_price, book_value as f64)
        });
    let price_to_book_ratio_basis_points =
        price_to_book_ratio.and_then(|value| runtime_round_f64_to_i64(value * 10_000.0));
    let minimum_price_to_book_ratio = highest_coupon_live_bond_rate
        .and_then(runtime_company_stock_issue_minimum_price_to_book_ratio_f64);
    let minimum_price_to_book_ratio_basis_points =
        minimum_price_to_book_ratio.and_then(|value| runtime_round_f64_to_i64(value * 10_000.0));
    let passes_share_price_floor =
        pressured_support_adjusted_share_price_scalar_i64.map(|value| value >= SHARE_PRICE_FLOOR);
    let passes_proceeds_floor = pressured_proceeds.map(|value| value >= ISSUE_PROCEEDS_CAP);
    let passes_cash_gate = current_cash
        .zip(highest_coupon_live_bond_principal)
        .map(|(cash, principal)| cash <= i64::from(principal) + 5_000);
    let passes_issue_cooldown_gate = Some(
        annual_finance_state
            .current_issue_age_absolute_counter_delta
            .is_none_or(|delta| delta >= ONE_YEAR_ABSOLUTE_COUNTER_SPAN),
    );
    let passes_coupon_price_to_book_gate = price_to_book_ratio_basis_points
        .zip(minimum_price_to_book_ratio_basis_points)
        .map(|(actual, minimum)| actual >= minimum);
    let eligible_for_double_tranche_issue = runtime_world_annual_finance_mode_active(state)
        == Some(true)
        && runtime_world_stock_issue_and_buyback_allowed(state) == Some(true)
        && runtime_world_bond_issue_and_repayment_allowed(state) == Some(true)
        && annual_finance_state.bond_count >= 2
        && annual_finance_state
            .years_since_founding
            .is_some_and(|years| years >= 1)
        && !runtime_company_annual_creditor_pressure_state(state, company_id)?
            .eligible_for_bankruptcy_branch
        && !runtime_company_annual_deep_distress_state(state, company_id)?
            .eligible_for_bankruptcy_fallback
        && !runtime_company_annual_bond_policy_state(state, company_id)?
            .eligible_for_bond_issue_branch
        && !runtime_company_annual_stock_repurchase_state(state, company_id)?
            .eligible_for_single_batch_repurchase
        && passes_share_price_floor == Some(true)
        && passes_proceeds_floor == Some(true)
        && passes_cash_gate == Some(true)
        && passes_issue_cooldown_gate == Some(true)
        && passes_coupon_price_to_book_gate == Some(true);
    Some(RuntimeCompanyAnnualStockIssueState {
        company_id,
        annual_mode_active: runtime_world_annual_finance_mode_active(state),
        stock_issue_and_buyback_allowed: runtime_world_stock_issue_and_buyback_allowed(state),
        bond_issue_and_repayment_allowed: runtime_world_bond_issue_and_repayment_allowed(state),
        years_since_founding: annual_finance_state.years_since_founding,
        live_bond_count: Some(annual_finance_state.bond_count),
        initial_issue_batch_size,
        trimmed_issue_batch_size: Some(trimmed_issue_batch_size),
        share_pressure_basis_points: runtime_round_f64_to_i64(
            -(trimmed_issue_batch_size as f64) / annual_finance_state.outstanding_shares as f64
                * 10_000.0,
        ),
        pressured_support_adjusted_share_price_scalar:
            pressured_support_adjusted_share_price_scalar_i64,
        pressured_proceeds,
        book_value_per_share_floor_applied,
        price_to_book_ratio_basis_points,
        current_cash,
        highest_coupon_live_bond_principal,
        highest_coupon_live_bond_rate_basis_points,
        current_issue_age_absolute_counter_delta: annual_finance_state
            .current_issue_age_absolute_counter_delta,
        current_issue_cooldown_floor: Some(ONE_YEAR_ABSOLUTE_COUNTER_SPAN),
        minimum_price_to_book_ratio_basis_points,
        passes_share_price_floor,
        passes_proceeds_floor,
        passes_cash_gate,
        passes_issue_cooldown_gate,
        passes_coupon_price_to_book_gate,
        eligible_for_double_tranche_issue,
    })
}
