use super::*;

#[test]
fn derives_company_credit_rating_from_rehosted_finance_state() {
    let mut year_stat_family_qword_bits = vec![
        0u64;
        (RUNTIME_COMPANY_STAT_SLOT_COUNT * RUNTIME_COMPANY_YEAR_STAT_FAMILY_SPAN)
            as usize
    ];
    year_stat_family_qword_bits[(0x12 * RUNTIME_COMPANY_YEAR_STAT_FAMILY_SPAN) as usize] =
        20.0f64.to_bits();
    year_stat_family_qword_bits[(0x01 * RUNTIME_COMPANY_YEAR_STAT_FAMILY_SPAN + 1) as usize] =
        100.0f64.to_bits();
    year_stat_family_qword_bits[(0x09 * RUNTIME_COMPANY_YEAR_STAT_FAMILY_SPAN + 1) as usize] =
        0.0f64.to_bits();

    let state = RuntimeState {
        calendar: CalendarPoint {
            year: 1835,
            month_slot: 0,
            phase_slot: 0,
            tick_slot: 0,
        },
        world_flags: BTreeMap::new(),
        save_profile: RuntimeSaveProfileState::default(),
        world_restore: RuntimeWorldRestoreState {
            issue_37_value: Some(5.0f32.to_bits()),
            issue_38_value: Some(2),
            packed_year_word_raw_u16: Some(1835),
            ..RuntimeWorldRestoreState::default()
        },
        metadata: BTreeMap::new(),
        companies: vec![RuntimeCompany {
            company_id: 7,
            current_cash: 100,
            debt: 0,
            credit_rating_score: None,
            prime_rate: None,
            active: true,
            available_track_laying_capacity: None,
            controller_kind: RuntimeCompanyControllerKind::Unknown,
            linked_chairman_profile_id: None,
            book_value_per_share: 0,
            investor_confidence: 0,
            management_attitude: 0,
            takeover_cooldown_year: None,
            merger_cooldown_year: None,
            track_piece_counts: RuntimeTrackPieceCounts::default(),
        }],
        selected_company_id: None,
        players: Vec::new(),
        selected_player_id: None,
        chairman_profiles: Vec::new(),
        selected_chairman_profile_id: None,
        trains: Vec::new(),
        locomotive_catalog: Vec::new(),
        cargo_catalog: Vec::new(),
        territories: Vec::new(),
        company_territory_track_piece_counts: Vec::new(),
        company_territory_access: Vec::new(),
        packed_event_collection: None,
        event_runtime_records: Vec::new(),
        candidate_availability: BTreeMap::new(),
        named_locomotive_availability: BTreeMap::new(),
        named_locomotive_cost: BTreeMap::new(),
        all_cargo_price_override: None,
        named_cargo_price_overrides: BTreeMap::new(),
        all_cargo_production_override: None,
        factory_cargo_production_override: None,
        farm_mine_cargo_production_override: None,
        named_cargo_production_overrides: BTreeMap::new(),
        cargo_production_overrides: BTreeMap::new(),
        world_runtime_variables: BTreeMap::new(),
        company_runtime_variables: BTreeMap::new(),
        player_runtime_variables: BTreeMap::new(),
        territory_runtime_variables: BTreeMap::new(),
        world_scalar_overrides: BTreeMap::new(),
        special_conditions: BTreeMap::new(),
        service_state: RuntimeServiceState {
            world_issue_opinion_base_terms_raw_i32: vec![0; 0x3b],
            company_market_state: BTreeMap::from([(
                7,
                RuntimeCompanyMarketState {
                    outstanding_shares: 10_000,
                    founding_year: 1830,
                    last_bankruptcy_year: 1800,
                    year_stat_family_qword_bits,
                    live_bond_slots: vec![RuntimeCompanyBondSlot {
                        slot_index: 0,
                        principal: 100_000,
                        maturity_year: 0,
                        coupon_rate_raw_u32: 0.05f32.to_bits(),
                    }],
                    ..RuntimeCompanyMarketState::default()
                },
            )]),
            ..RuntimeServiceState::default()
        },
    };

    let annual_finance_state =
        runtime_company_annual_finance_state(&state, 7).expect("annual finance state");
    assert_eq!(
        annual_finance_state.trailing_full_year_net_profits,
        vec![100, 0, 0, 0]
    );
    assert_eq!(
        runtime_company_control_transfer_stat_value_f64(&state, 7, 0x12),
        Some(20.0)
    );
    assert_eq!(
        runtime_company_derived_stat_value(
            &state,
            7,
            RUNTIME_COMPANY_STAT_FAMILY_CONTROL_TRANSFER,
            0x30,
        ),
        Some(100.0)
    );
    assert_eq!(
        runtime_company_derived_stat_value(
            &state,
            7,
            RUNTIME_COMPANY_STAT_FAMILY_CONTROL_TRANSFER,
            0x31,
        ),
        Some(120.0)
    );
    let average_live_bond_coupon =
        runtime_company_average_live_bond_coupon(&state, 7).expect("average coupon");
    assert!((average_live_bond_coupon - 0.05).abs() < 1e-6);
    assert_eq!(
        annual_finance_state.live_bond_coupon_burden_total,
        Some(5_000)
    );
    assert_eq!(runtime_world_prime_rate_baseline(&state), Some(5.0));
    assert_eq!(
        runtime_world_issue_opinion_term_sum_raw(
            &state,
            RUNTIME_WORLD_ISSUE_PRIME_RATE,
            None,
            Some(7),
            None,
        ),
        Some(0)
    );
    assert_eq!(
        runtime_world_issue_opinion_term_sum_raw(
            &state,
            RUNTIME_WORLD_ISSUE_CREDIT_MARKET,
            None,
            Some(7),
            None,
        ),
        Some(0)
    );
    assert_eq!(runtime_world_credit_market_scale(&state), Some(1.0));

    assert_eq!(runtime_company_credit_rating(&state, 7), Some(10));
    assert_eq!(
        runtime_company_stat_value(
            &state,
            7,
            RuntimeCompanyStatSelector {
                family_id: RUNTIME_COMPANY_STAT_FAMILY_CONTROL_TRANSFER,
                slot_id: RUNTIME_COMPANY_STAT_SLOT_CREDIT_RATING,
            },
        ),
        Some(10)
    );
}

#[test]
fn computes_weighted_average_live_bond_coupon_from_owned_market_slots() {
    let state = RuntimeState {
        calendar: CalendarPoint {
            year: 1830,
            month_slot: 0,
            phase_slot: 0,
            tick_slot: 0,
        },
        world_flags: BTreeMap::new(),
        save_profile: RuntimeSaveProfileState::default(),
        world_restore: RuntimeWorldRestoreState::default(),
        metadata: BTreeMap::new(),
        companies: vec![RuntimeCompany {
            company_id: 7,
            current_cash: 0,
            debt: 0,
            credit_rating_score: None,
            prime_rate: None,
            active: true,
            available_track_laying_capacity: None,
            controller_kind: RuntimeCompanyControllerKind::Unknown,
            linked_chairman_profile_id: None,
            book_value_per_share: 0,
            investor_confidence: 0,
            management_attitude: 0,
            takeover_cooldown_year: None,
            merger_cooldown_year: None,
            track_piece_counts: RuntimeTrackPieceCounts::default(),
        }],
        selected_company_id: None,
        players: Vec::new(),
        selected_player_id: None,
        chairman_profiles: Vec::new(),
        selected_chairman_profile_id: None,
        trains: Vec::new(),
        locomotive_catalog: Vec::new(),
        cargo_catalog: Vec::new(),
        territories: Vec::new(),
        company_territory_track_piece_counts: Vec::new(),
        company_territory_access: Vec::new(),
        packed_event_collection: None,
        event_runtime_records: Vec::new(),
        candidate_availability: BTreeMap::new(),
        named_locomotive_availability: BTreeMap::new(),
        named_locomotive_cost: BTreeMap::new(),
        all_cargo_price_override: None,
        named_cargo_price_overrides: BTreeMap::new(),
        all_cargo_production_override: None,
        factory_cargo_production_override: None,
        farm_mine_cargo_production_override: None,
        named_cargo_production_overrides: BTreeMap::new(),
        cargo_production_overrides: BTreeMap::new(),
        world_runtime_variables: BTreeMap::new(),
        company_runtime_variables: BTreeMap::new(),
        player_runtime_variables: BTreeMap::new(),
        territory_runtime_variables: BTreeMap::new(),
        world_scalar_overrides: BTreeMap::new(),
        special_conditions: BTreeMap::new(),
        service_state: RuntimeServiceState {
            company_market_state: BTreeMap::from([(
                7,
                RuntimeCompanyMarketState {
                    live_bond_slots: vec![
                        RuntimeCompanyBondSlot {
                            slot_index: 0,
                            principal: 100_000,
                            maturity_year: 0,
                            coupon_rate_raw_u32: 0.04f32.to_bits(),
                        },
                        RuntimeCompanyBondSlot {
                            slot_index: 1,
                            principal: 300_000,
                            maturity_year: 0,
                            coupon_rate_raw_u32: 0.08f32.to_bits(),
                        },
                    ],
                    ..RuntimeCompanyMarketState::default()
                },
            )]),
            ..RuntimeServiceState::default()
        },
    };

    let average = runtime_company_average_live_bond_coupon(&state, 7)
        .expect("weighted average live bond coupon");
    assert!((average - 0.07).abs() < 1e-6);
}
