use crate::inspect::smp::save_load::*;

pub(super) struct LoadedSaveSliceParts {
    pub(super) profile: Option<SmpLoadedProfile>,
    pub(super) candidate_availability_table: Option<SmpLoadedCandidateAvailabilityTable>,
    pub(super) named_locomotive_availability_table:
        Option<SmpLoadedNamedLocomotiveAvailabilityTable>,
    pub(super) locomotive_catalog: Option<SmpLoadedLocomotiveCatalog>,
    pub(super) cargo_catalog: Option<SmpLoadedCargoCatalog>,
    pub(super) world_issue_37_state: Option<SmpLoadedWorldIssue37State>,
    pub(super) world_economic_tuning_state: Option<SmpLoadedWorldEconomicTuningState>,
    pub(super) world_finance_neighborhood_state: Option<SmpLoadedWorldFinanceNeighborhoodState>,
    pub(super) world_locomotive_policy_state: Option<SmpLoadedWorldLocomotivePolicyState>,
    pub(super) company_roster: Option<SmpLoadedCompanyRoster>,
    pub(super) chairman_profile_table: Option<SmpLoadedChairmanProfileTable>,
    pub(super) region_collection: Option<SmpLoadedRegionCollection>,
    pub(super) region_fixed_row_run_summary: Option<SmpLoadedRegionFixedRowRunSummary>,
    pub(super) placed_structure_collection: Option<SmpLoadedPlacedStructureCollection>,
    pub(super) placed_structure_dynamic_side_buffer_probe:
        Option<SmpSavePlacedStructureDynamicSideBufferProbe>,
    pub(super) placed_structure_dynamic_side_buffer_summary:
        Option<SmpLoadedPlacedStructureDynamicSideBufferSummary>,
    pub(super) special_conditions_table: Option<SmpLoadedSpecialConditionsTable>,
    pub(super) event_runtime_collection: Option<SmpLoadedEventRuntimeCollectionSummary>,
}

pub(super) fn derive_loaded_save_slice_parts(report: &SmpInspectionReport) -> LoadedSaveSliceParts {
    let profile = if let Some(probe) = &report.classic_rehydrate_profile_probe {
        Some(SmpLoadedProfile {
            profile_kind: "classic-rehydrate-profile".to_string(),
            profile_family: probe.profile_family.clone(),
            packed_profile_offset: probe.packed_profile_offset,
            packed_profile_len: probe.packed_profile_len,
            packed_profile_len_hex: probe.packed_profile_len_hex.clone(),
            leading_word_0: probe.packed_profile_block.leading_word_0,
            leading_word_0_hex: probe.packed_profile_block.leading_word_0_hex.clone(),
            header_flag_word_3: None,
            header_flag_word_3_hex: None,
            map_path: probe.packed_profile_block.map_path.clone(),
            display_name: probe.packed_profile_block.display_name.clone(),
            profile_byte_0x77: probe.packed_profile_block.profile_byte_0x77,
            profile_byte_0x77_hex: probe.packed_profile_block.profile_byte_0x77_hex.clone(),
            profile_byte_0x82: probe.packed_profile_block.profile_byte_0x82,
            profile_byte_0x82_hex: probe.packed_profile_block.profile_byte_0x82_hex.clone(),
            profile_byte_0x97: probe.packed_profile_block.profile_byte_0x97,
            profile_byte_0x97_hex: probe.packed_profile_block.profile_byte_0x97_hex.clone(),
            profile_byte_0xc5: probe.packed_profile_block.profile_byte_0xc5,
            profile_byte_0xc5_hex: probe.packed_profile_block.profile_byte_0xc5_hex.clone(),
        })
    } else {
        report
            .rt3_105_packed_profile_probe
            .as_ref()
            .map(|probe| SmpLoadedProfile {
                profile_kind: "rt3-105-packed-profile".to_string(),
                profile_family: probe.profile_family.clone(),
                packed_profile_offset: probe.packed_profile_offset,
                packed_profile_len: probe.packed_profile_len,
                packed_profile_len_hex: probe.packed_profile_len_hex.clone(),
                leading_word_0: probe.packed_profile_block.leading_word_0,
                leading_word_0_hex: probe.packed_profile_block.leading_word_0_hex.clone(),
                header_flag_word_3: Some(probe.packed_profile_block.header_flag_word_3),
                header_flag_word_3_hex: Some(
                    probe.packed_profile_block.header_flag_word_3_hex.clone(),
                ),
                map_path: probe.packed_profile_block.map_path.clone(),
                display_name: probe.packed_profile_block.display_name.clone(),
                profile_byte_0x77: probe.packed_profile_block.profile_byte_0x77,
                profile_byte_0x77_hex: probe.packed_profile_block.profile_byte_0x77_hex.clone(),
                profile_byte_0x82: probe.packed_profile_block.profile_byte_0x82,
                profile_byte_0x82_hex: probe.packed_profile_block.profile_byte_0x82_hex.clone(),
                profile_byte_0x97: probe.packed_profile_block.profile_byte_0x97,
                profile_byte_0x97_hex: probe.packed_profile_block.profile_byte_0x97_hex.clone(),
                profile_byte_0xc5: probe.packed_profile_block.profile_byte_0xc5,
                profile_byte_0xc5_hex: probe.packed_profile_block.profile_byte_0xc5_hex.clone(),
            })
    };
    let candidate_availability_table = report.rt3_105_save_name_table_probe.as_ref().map(|probe| {
        SmpLoadedCandidateAvailabilityTable {
            source_kind: probe.source_kind.clone(),
            semantic_family: probe.semantic_family.clone(),
            header_offset: probe.header_offset,
            entries_offset: probe.entries_offset,
            entries_end_offset: probe.entries_end_offset,
            observed_entry_count: probe.observed_entry_count,
            zero_availability_count: probe.zero_trailer_entry_count,
            zero_availability_names: probe.zero_trailer_entry_names.clone(),
            footer_progress_hex_words: vec![
                probe.footer_progress_word_0_hex.clone(),
                probe.footer_progress_word_1_hex.clone(),
            ],
            entries: probe.entries.clone(),
        }
    });
    let named_locomotive_availability_table = report
        .rt3_105_save_named_locomotive_availability_probe
        .as_ref()
        .map(|probe| SmpLoadedNamedLocomotiveAvailabilityTable {
            source_kind: probe.source_kind.clone(),
            semantic_family: probe.semantic_family.clone(),
            header_offset: None,
            entries_offset: Some(probe.entries_offset),
            entries_end_offset: Some(probe.entries_end_offset),
            observed_entry_count: probe.observed_entry_count,
            zero_availability_count: probe.zero_availability_count,
            zero_availability_names: probe.zero_availability_names.clone(),
            entries: probe.entries.clone(),
        });
    let locomotive_catalog = named_locomotive_availability_table
        .as_ref()
        .and_then(derive_locomotive_catalog_from_named_availability_table);
    let cargo_catalog = report
        .recipe_book_summary_probe
        .as_ref()
        .and_then(derive_cargo_catalog_from_recipe_book_probe);
    let world_issue_37_state = report
        .save_world_issue_37_probe
        .as_ref()
        .map(derive_loaded_world_issue_37_state_from_probe);
    let world_economic_tuning_state = report
        .save_world_economic_tuning_probe
        .as_ref()
        .map(derive_loaded_world_economic_tuning_state_from_probe);
    let world_finance_neighborhood_state = report
        .save_world_finance_neighborhood_probe
        .as_ref()
        .map(derive_loaded_world_finance_neighborhood_state_from_probe);
    let world_locomotive_policy_state = derive_loaded_world_locomotive_policy_state_from_probes(
        report.post_text_field_neighborhood_probe.as_ref(),
        report.locomotive_policy_neighborhood_probe.as_ref(),
    );
    let company_roster = report.save_company_roster_probe.clone().or_else(|| {
        report
            .save_world_selection_context_probe
            .as_ref()
            .and_then(|probe| {
                derive_selection_only_company_roster_from_save_world_probe(
                    probe,
                    report.save_company_collection_header_probe.as_ref(),
                )
            })
    });
    let chairman_profile_table = report
        .save_chairman_profile_table_probe
        .clone()
        .or_else(|| {
            report
                .save_world_selection_context_probe
                .as_ref()
                .and_then(|probe| {
                    derive_selection_only_chairman_profile_table_from_save_world_probe(
                        probe,
                        report
                            .save_chairman_profile_collection_header_probe
                            .as_ref(),
                    )
                })
        });
    let region_collection = report
        .save_region_record_triplet_probe
        .as_ref()
        .map(derive_loaded_region_collection_from_probe);
    let region_fixed_row_run_summary = report
        .save_region_fixed_row_run_candidate_probe
        .as_ref()
        .map(derive_loaded_region_fixed_row_run_summary_from_probe);
    let placed_structure_collection = report
        .save_placed_structure_record_triplet_probe
        .as_ref()
        .map(derive_loaded_placed_structure_collection_from_probe);
    let special_conditions_table =
        report
            .special_conditions_probe
            .as_ref()
            .map(|probe| SmpLoadedSpecialConditionsTable {
                source_kind: probe.source_kind.clone(),
                table_offset: probe.table_offset,
                table_len: probe.table_len,
                enabled_visible_count: probe.enabled_visible_count,
                enabled_visible_labels: probe.enabled_visible_labels.clone(),
                entries: probe.entries.clone(),
            });
    let placed_structure_dynamic_side_buffer_probe = report
        .save_placed_structure_dynamic_side_buffer_probe
        .clone();
    let placed_structure_dynamic_side_buffer_alignment = report
        .save_placed_structure_dynamic_side_buffer_probe
        .as_ref()
        .zip(report.save_placed_structure_record_triplet_probe.as_ref())
        .map(|(side_buffer, triplets)| {
            summarize_placed_structure_dynamic_side_buffer_alignment(side_buffer, triplets)
        });
    let placed_structure_dynamic_side_buffer_summary = report
        .save_placed_structure_dynamic_side_buffer_probe
        .as_ref()
        .map(|probe| {
            derive_loaded_placed_structure_dynamic_side_buffer_summary(
                probe,
                placed_structure_dynamic_side_buffer_alignment.as_ref(),
            )
        });

    LoadedSaveSliceParts {
        profile,
        candidate_availability_table,
        named_locomotive_availability_table,
        locomotive_catalog,
        cargo_catalog,
        world_issue_37_state,
        world_economic_tuning_state,
        world_finance_neighborhood_state,
        world_locomotive_policy_state,
        company_roster,
        chairman_profile_table,
        region_collection,
        region_fixed_row_run_summary,
        placed_structure_collection,
        placed_structure_dynamic_side_buffer_probe,
        placed_structure_dynamic_side_buffer_summary,
        special_conditions_table,
        event_runtime_collection: report.event_runtime_collection_summary.clone(),
    }
}

pub(super) fn finish_loaded_save_slice(
    summary: &SmpSaveLoadSummary,
    parts: LoadedSaveSliceParts,
    notes: Vec<String>,
) -> SmpLoadedSaveSlice {
    SmpLoadedSaveSlice {
        file_extension_hint: summary.file_extension_hint.clone(),
        container_profile_family: summary.container_profile_family.clone(),
        mechanism_family: summary.mechanism_family.clone(),
        mechanism_confidence: summary.mechanism_confidence.clone(),
        trailer_family: summary.trailer_family.clone(),
        bridge_family: summary.bridge_family.clone(),
        profile: parts.profile,
        candidate_availability_table: parts.candidate_availability_table,
        named_locomotive_availability_table: parts.named_locomotive_availability_table,
        locomotive_catalog: parts.locomotive_catalog,
        cargo_catalog: parts.cargo_catalog,
        world_issue_37_state: parts.world_issue_37_state,
        world_economic_tuning_state: parts.world_economic_tuning_state,
        world_finance_neighborhood_state: parts.world_finance_neighborhood_state,
        world_locomotive_policy_state: parts.world_locomotive_policy_state,
        company_roster: parts.company_roster,
        chairman_profile_table: parts.chairman_profile_table,
        region_collection: parts.region_collection,
        region_fixed_row_run_summary: parts.region_fixed_row_run_summary,
        placed_structure_collection: parts.placed_structure_collection,
        placed_structure_dynamic_side_buffer_summary: parts
            .placed_structure_dynamic_side_buffer_summary,
        special_conditions_table: parts.special_conditions_table,
        event_runtime_collection: parts.event_runtime_collection,
        notes,
    }
}
