use std::collections::BTreeMap;

use crate::inspect::smp::common::{read_i32_at, read_u32_at, read_u64_at};
use crate::inspect::smp::world::SmpSaveDwordCandidate;

pub(in crate::inspect::smp) fn runtime_company_stat_band_candidate_from_save(
    candidate: &SmpSaveDwordCandidate,
) -> crate::state::RuntimeCompanyStatBandCandidate {
    crate::state::RuntimeCompanyStatBandCandidate {
        label: candidate.label.clone(),
        relative_offset: candidate.relative_offset,
        relative_offset_hex: candidate.relative_offset_hex.clone(),
        raw_u32: candidate.raw_u32,
        raw_u32_hex: candidate.raw_u32_hex.clone(),
        value_i32: candidate.value_i32,
        value_f32_text: format!("{:.6}", candidate.value_f32),
    }
}

pub(in crate::inspect::smp) fn build_save_company_stat_band_candidates(
    bytes: &[u8],
    record_offset: usize,
    root_offset: usize,
    label_prefix: &str,
    word_count: usize,
) -> Option<Vec<SmpSaveDwordCandidate>> {
    (0..word_count)
        .map(|index| {
            let relative_offset = root_offset.checked_add(index.checked_mul(4)?)?;
            let label = format!("{label_prefix}_word_{}", index + 1);
            super::scan::build_save_dword_candidate(bytes, record_offset, &label, relative_offset)
        })
        .collect::<Option<Vec<_>>>()
}

pub(in crate::inspect::smp) fn build_save_company_stat_qword_bits(
    bytes: &[u8],
    record_offset: usize,
    root_offset: usize,
    qword_count: usize,
) -> Option<Vec<u64>> {
    (0..qword_count)
        .map(|index| {
            let relative_offset = root_offset.checked_add(index.checked_mul(8)?)?;
            read_u64_at(bytes, record_offset + relative_offset)
        })
        .collect::<Option<Vec<_>>>()
}

pub(in crate::inspect::smp) fn build_save_i32_term_strip(
    bytes: &[u8],
    record_offset: usize,
    root_offset: usize,
    value_count: usize,
) -> Option<Vec<i32>> {
    (0..value_count)
        .map(|index| {
            let relative_offset = root_offset.checked_add(index.checked_mul(4)?)?;
            read_i32_at(bytes, record_offset + relative_offset)
        })
        .collect::<Option<Vec<_>>>()
}

pub(in crate::inspect::smp) fn build_save_u32_field_map(
    bytes: &[u8],
    record_offset: usize,
    offsets: &[usize],
) -> Option<BTreeMap<u32, u32>> {
    let mut fields = BTreeMap::new();
    for relative_offset in offsets {
        fields.insert(
            u32::try_from(*relative_offset).ok()?,
            read_u32_at(bytes, record_offset + *relative_offset)?,
        );
    }
    Some(fields)
}

pub(in crate::inspect::smp) fn decode_save_company_current_year_stat_slot(
    year_stat_family_qword_bits: &[u64],
    slot_id: u32,
) -> Option<f64> {
    let index =
        slot_id.checked_mul(crate::event::metrics::RUNTIME_COMPANY_YEAR_STAT_FAMILY_SPAN)? as usize;
    let value = f64::from_bits(*year_stat_family_qword_bits.get(index)?);
    value.is_finite().then_some(value)
}
