use crate::Binary;
use crate::Result;
use anyhow::bail;
use linker_utils::elf::SectionType;
use linker_utils::elf::sht;
use object::LittleEndian;
use object::Object as _;
use object::ObjectSymbol;
use object::read::elf::SectionHeader as _;
use std::ops::Not;

pub(crate) fn validate_debug(object: &Binary) -> Result {
    validate(object, false)
}

pub(crate) fn validate_dynamic(object: &Binary) -> Result {
    validate(object, true)
}

fn validate(object: &Binary, dynamic: bool) -> Result {
    let mut symtab_info = 0;
    let (symtab_section_type, mut symbols) = if dynamic {
        (sht::DYNSYM, object.elf_file.dynamic_symbols())
    } else {
        (sht::SYMTAB, object.elf_file.symbols())
    };
    for section in object.elf_file.elf_section_table().iter() {
        if SectionType::from_header(section) == symtab_section_type {
            symtab_info = section.sh_info(LittleEndian);
        }
    }
    let first_non_local = symbols.find_map(|sym| sym.is_local().not().then(|| sym.index()));
    if let Some(first_non_local) = first_non_local
        && first_non_local.0 != symtab_info as usize
    {
        bail!("info={symtab_info}, but first non-local is {first_non_local}")
    }

    Ok(())
}
