use super::*;

#[test]
fn decodes_and_packs_company_issue_calendar_tuple() {
    let tuple = runtime_decode_packed_calendar_tuple(0x0101_0726, 0x0001_0001);
    assert_eq!(
        tuple,
        RuntimePackedCalendarTuple {
            year_word: 0x0726,
            month_1_based: 1,
            week_1_based: 1,
            day_1_based: 1,
            hour_0_based: 0,
            quarter_day_1_based: 1,
            minute_0_based: 0,
        }
    );
    assert_eq!(
        runtime_pack_packed_calendar_tuple_to_absolute_counter(tuple),
        Some(885_427_200)
    );
    assert_eq!(
        runtime_pack_packed_calendar_tuple_to_absolute_counter(RuntimePackedCalendarTuple {
            year_word: 1830,
            month_1_based: 13,
            week_1_based: 1,
            day_1_based: 1,
            hour_0_based: 0,
            quarter_day_1_based: 1,
            minute_0_based: 0,
        }),
        None
    );
}

#[test]
fn derives_and_encodes_packed_calendar_tuple_from_runtime_calendar() {
    let tuple = runtime_derive_packed_calendar_tuple_from_calendar_point(CalendarPoint {
        year: 1830,
        month_slot: 11,
        phase_slot: 27,
        tick_slot: 179,
    })
    .expect("runtime calendar tuple");
    assert_eq!(
        tuple,
        RuntimePackedCalendarTuple {
            year_word: 1830,
            month_1_based: 12,
            week_1_based: 4,
            day_1_based: 28,
            hour_0_based: 23,
            quarter_day_1_based: 4,
            minute_0_based: 52,
        }
    );
    assert_eq!(
        runtime_encode_packed_calendar_tuple(tuple),
        (0x040c_0726, 0x3404_171c)
    );
}

#[test]
fn derives_selected_year_gap_scalar_from_year_word() {
    assert_eq!(
        runtime_world_selected_year_bucket_scalar_from_year_word(1830),
        Some(25.0)
    );
    assert_eq!(
        runtime_world_selected_year_bucket_scalar_from_year_word(1835),
        Some(31.5)
    );
    assert_eq!(
        runtime_world_selected_year_bucket_scalar_from_year_word(2000),
        Some(123.0)
    );
    let bands = runtime_selected_year_bucket_bands_from_scalar(25.0)
        .expect("selected-year bucket companion bands");
    assert!((bands.direct[0] - 22.5).abs() < 1e-6);
    assert!((bands.direct[1] - 26.25).abs() < 1e-5);
    assert!((bands.direct[2] - 17.5).abs() < 1e-6);
    assert!((bands.complement[0] - 0.999121).abs() < 1e-6);
    assert!((bands.scaled_companion[0] - 139.16667).abs() < 1e-4);
    assert_eq!(
        runtime_world_selected_year_gap_scalar_from_year_word(1830),
        Some((1.0f32 / 3.0).clamp(1.0 / 3.0, 1.0))
    );
    assert_eq!(
        runtime_world_selected_year_gap_scalar_from_year_word(1900),
        Some((50.0f32 / 150.0).clamp(1.0 / 3.0, 1.0))
    );
    assert_eq!(
        runtime_world_selected_year_gap_scalar_from_year_word(2000),
        Some(1.0)
    );
}

#[test]
fn refreshes_selected_year_gap_scalar_from_world_restore_calendar() {
    let mut 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 {
            packed_year_word_raw_u16: Some(1900),
            economic_tuning_lane_raw_u32: vec![0x3f400000],
            ..RuntimeWorldRestoreState::default()
        },
        metadata: BTreeMap::new(),
        companies: Vec::new(),
        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::default(),
    };

    state.refresh_derived_world_state();

    assert_eq!(
        state.world_restore.economic_tuning_mirror_raw_u32,
        Some(0x3f400000)
    );
    assert_eq!(
        state
            .world_restore
            .economic_tuning_mirror_value_f32_text
            .as_deref(),
        Some("0.750000")
    );
    assert_eq!(
        state.world_restore.selected_year_bucket_scalar_raw_u32,
        Some(70.0f32.to_bits())
    );
    assert_eq!(
        state
            .world_restore
            .selected_year_bucket_scalar_value_f32_text
            .as_deref(),
        Some("70.000000")
    );
    assert_eq!(
        state
            .world_restore
            .selected_year_bucket_direct_lane_value_f32_text,
        vec![
            "63.000000".to_string(),
            "73.500000".to_string(),
            "49.000000".to_string()
        ]
    );
    assert_eq!(
        state
            .world_restore
            .selected_year_bucket_complement_lane_value_f32_text,
        vec![
            "0.998400".to_string(),
            "0.998213".to_string(),
            "0.998649".to_string()
        ]
    );
    assert_eq!(
        state
            .world_restore
            .selected_year_bucket_scaled_companion_lane_value_f32_text,
        vec![
            "64.166672".to_string(),
            "58.214291".to_string(),
            "76.071426".to_string()
        ]
    );
    assert_eq!(
        state.world_restore.selected_year_gap_scalar_raw_u32,
        Some(((50.0f32 / 150.0).clamp(1.0 / 3.0, 1.0)).to_bits())
    );
    assert_eq!(
        state
            .world_restore
            .selected_year_gap_scalar_value_f32_text
            .as_deref(),
        Some("0.333333")
    );
}
