use super::offsets::*;
use crate::inspect::smp::common::{read_i32_at, read_u8_at, read_u32_at};

pub(in crate::inspect::smp) fn parse_save_company_total_debt(
    bytes: &[u8],
    record_offset: usize,
) -> Option<u64> {
    let bond_count =
        read_u8_at(bytes, record_offset + SAVE_COMPANY_RECORD_BOND_COUNT_OFFSET)? as usize;
    let mut total = 0u64;
    for slot_index in 0usize..bond_count {
        let slot_offset = record_offset
            .checked_add(SAVE_COMPANY_RECORD_BOND_TABLE_OFFSET)?
            .checked_add(slot_index.checked_mul(SAVE_COMPANY_RECORD_BOND_SLOT_STRIDE)?)?;
        let principal = read_i32_at(bytes, slot_offset)?;
        if principal > 0 {
            total = total.checked_add(principal as u64)?;
        }
    }
    Some(total)
}

pub(in crate::inspect::smp) fn parse_save_company_live_bond_slots(
    bytes: &[u8],
    record_offset: usize,
) -> Option<Vec<crate::state::RuntimeCompanyBondSlot>> {
    let bond_count =
        read_u8_at(bytes, record_offset + SAVE_COMPANY_RECORD_BOND_COUNT_OFFSET)? as usize;
    let mut slots = Vec::new();
    for slot_index in 0usize..bond_count {
        let slot_offset = record_offset
            .checked_add(SAVE_COMPANY_RECORD_BOND_TABLE_OFFSET)?
            .checked_add(slot_index.checked_mul(SAVE_COMPANY_RECORD_BOND_SLOT_STRIDE)?)?;
        let principal = read_i32_at(bytes, slot_offset)?;
        if principal <= 0 {
            continue;
        }
        let maturity_year = read_u32_at(bytes, slot_offset + 4)?;
        let coupon_rate_raw_u32 = read_u32_at(bytes, slot_offset + 8)?;
        let coupon_rate = f32::from_bits(coupon_rate_raw_u32);
        if !coupon_rate.is_finite() {
            continue;
        }
        slots.push(crate::state::RuntimeCompanyBondSlot {
            slot_index: slot_index as u32,
            principal: principal as u32,
            maturity_year,
            coupon_rate_raw_u32,
        });
    }
    Some(slots)
}

pub(in crate::inspect::smp) fn parse_save_company_largest_live_bond_principal(
    bytes: &[u8],
    record_offset: usize,
) -> Option<Option<u32>> {
    let mut largest_live_principal: Option<u32> = None;
    for slot in parse_save_company_live_bond_slots(bytes, record_offset)? {
        largest_live_principal = Some(match largest_live_principal {
            Some(current) => current.max(slot.principal),
            None => slot.principal,
        });
    }
    Some(largest_live_principal)
}

pub(in crate::inspect::smp) fn parse_save_company_highest_coupon_live_bond_principal(
    bytes: &[u8],
    record_offset: usize,
) -> Option<Option<u32>> {
    let mut highest_coupon_principal = None;
    let mut highest_coupon_rate = None;
    for slot in parse_save_company_live_bond_slots(bytes, record_offset)? {
        let coupon_rate = f32::from_bits(slot.coupon_rate_raw_u32);
        match highest_coupon_rate {
            Some(current_rate) if coupon_rate < current_rate => {}
            Some(current_rate) if coupon_rate == current_rate => {
                if let Some(current_principal) = highest_coupon_principal {
                    if slot.principal > current_principal {
                        highest_coupon_principal = Some(slot.principal);
                    }
                }
            }
            _ => {
                highest_coupon_rate = Some(coupon_rate);
                highest_coupon_principal = Some(slot.principal);
            }
        }
    }
    Some(highest_coupon_principal)
}
