use crate::inspect::smp::save_load::{
    SmpLoadedCargoCatalog, SmpLoadedCargoCatalogEntry, SmpLoadedLocomotiveCatalog,
    SmpLoadedLocomotiveCatalogEntry, SmpLoadedNamedLocomotiveAvailabilityTable,
};
use crate::inspect::smp::special_conditions::SmpRecipeBookSummaryProbe;
use crate::inspect::smp::*;

pub(in crate::inspect::smp) fn derive_locomotive_catalog_from_named_availability_table(
    table: &SmpLoadedNamedLocomotiveAvailabilityTable,
) -> Option<SmpLoadedLocomotiveCatalog> {
    if table.entries.is_empty() {
        return None;
    }

    let entries = table
        .entries
        .iter()
        .enumerate()
        .map(|(index, entry)| SmpLoadedLocomotiveCatalogEntry {
            locomotive_id: (index + 1) as u32,
            name: entry.text.clone(),
        })
        .collect::<Vec<_>>();

    Some(SmpLoadedLocomotiveCatalog {
        source_kind: format!("{}-ordinal-catalog", table.source_kind),
        semantic_family: "scenario-save-derived-locomotive-catalog".to_string(),
        entries_offset: table.entries_offset,
        observed_entry_count: entries.len(),
        entries,
    })
}

pub(in crate::inspect::smp) fn derive_cargo_catalog_from_recipe_book_probe(
    probe: &SmpRecipeBookSummaryProbe,
) -> Option<SmpLoadedCargoCatalog> {
    if probe.books.is_empty() {
        return None;
    }

    let entries = probe
        .books
        .iter()
        .filter(|book| book.book_index < 11)
        .filter_map(|book| {
            let line = book
                .lines
                .iter()
                .find(|line| line.imports_to_runtime_descriptor)
                .or_else(|| book.lines.first())?;
            let slot_id = (book.book_index + 1) as u32;
            let definition = known_cargo_slot_definition(slot_id)?;
            Some(SmpLoadedCargoCatalogEntry {
                slot_id,
                label: definition.label.to_string(),
                cargo_class: definition.cargo_class,
                book_index: book.book_index,
                max_annual_production_word: book.max_annual_production_word,
                mode_word: line.mode_word,
                runtime_import_branch_kind: line.runtime_import_branch_kind.clone(),
                annual_amount_word: line.annual_amount_word,
                supplied_cargo_token_word: line.supplied_cargo_token_word,
                supplied_cargo_token_probable_high16_ascii_stem: line
                    .supplied_cargo_token_probable_high16_ascii_stem
                    .clone(),
                demanded_cargo_token_word: line.demanded_cargo_token_word,
                demanded_cargo_token_probable_high16_ascii_stem: line
                    .demanded_cargo_token_probable_high16_ascii_stem
                    .clone(),
            })
        })
        .collect::<Vec<_>>();

    if entries.is_empty() {
        return None;
    }

    Some(SmpLoadedCargoCatalog {
        source_kind: format!("{}-slot-catalog", probe.source_kind),
        semantic_family: "scenario-save-derived-cargo-catalog".to_string(),
        root_offset: Some(probe.root_offset),
        observed_entry_count: entries.len(),
        entries,
    })
}

pub(in crate::inspect::smp) fn known_cargo_slot_definition(
    slot_id: u32,
) -> Option<KnownCargoSlotDefinition> {
    KNOWN_CARGO_SLOT_DEFINITIONS
        .iter()
        .copied()
        .find(|definition| definition.slot_id == slot_id)
}

pub(in crate::inspect::smp) fn known_cargo_slot_definition_for_descriptor_id(
    descriptor_id: u32,
) -> Option<KnownCargoSlotDefinition> {
    KNOWN_CARGO_SLOT_DEFINITIONS
        .iter()
        .copied()
        .find(|definition| definition.descriptor_id == descriptor_id)
}

pub(in crate::inspect::smp) fn runtime_cargo_class_name(
    cargo_class: RuntimeCargoClass,
) -> &'static str {
    match cargo_class {
        RuntimeCargoClass::Factory => "factory",
        RuntimeCargoClass::FarmMine => "farm_mine",
        RuntimeCargoClass::Other => "other",
    }
}
