use std::collections::BTreeMap;

use super::super::SaveSliceProjectionMode;
use crate::inspect::smp::save_load::SmpLoadedSaveSlice;

pub(super) struct ProjectionMetadata {
    pub(super) world_flags: BTreeMap<String, bool>,
    pub(super) metadata: BTreeMap<String, String>,
}

pub(super) fn build_projection_metadata(
    save_slice: &SmpLoadedSaveSlice,
    mode: SaveSliceProjectionMode,
) -> ProjectionMetadata {
    let mut world_flags: BTreeMap<String, bool> = BTreeMap::new();
    world_flags.insert(
        "save_slice.profile_present".to_string(),
        save_slice.profile.is_some(),
    );
    world_flags.insert(
        "save_slice.candidate_availability_present".to_string(),
        save_slice.candidate_availability_table.is_some(),
    );
    world_flags.insert(
        "save_slice.special_conditions_present".to_string(),
        save_slice.special_conditions_table.is_some(),
    );
    world_flags.insert(
        "save_slice.named_locomotive_availability_present".to_string(),
        save_slice.named_locomotive_availability_table.is_some(),
    );
    world_flags.insert(
        "save_slice.locomotive_catalog_present".to_string(),
        save_slice.locomotive_catalog.is_some()
            || save_slice.named_locomotive_availability_table.is_some(),
    );
    world_flags.insert(
        "save_slice.cargo_catalog_present".to_string(),
        save_slice.cargo_catalog.is_some(),
    );
    world_flags.insert(
        "save_slice.world_issue_37_state_present".to_string(),
        save_slice.world_issue_37_state.is_some(),
    );
    world_flags.insert(
        "save_slice.world_economic_tuning_state_present".to_string(),
        save_slice.world_economic_tuning_state.is_some(),
    );
    world_flags.insert(
        "save_slice.world_finance_neighborhood_state_present".to_string(),
        save_slice.world_finance_neighborhood_state.is_some(),
    );
    world_flags.insert(
        "save_slice.event_runtime_collection_present".to_string(),
        save_slice.event_runtime_collection.is_some(),
    );
    world_flags.insert(
        "save_slice.mechanism_confidence_grounded".to_string(),
        save_slice.mechanism_confidence == "grounded",
    );
    if let Some(profile) = &save_slice.profile {
        world_flags.insert(
            "save_slice.profile_byte_0x82_nonzero".to_string(),
            profile.profile_byte_0x82 != 0,
        );
        world_flags.insert(
            "save_slice.profile_byte_0x97_nonzero".to_string(),
            profile.profile_byte_0x97 != 0,
        );
        world_flags.insert(
            "save_slice.profile_byte_0xc5_nonzero".to_string(),
            profile.profile_byte_0xc5 != 0,
        );
    }

    let mut metadata: BTreeMap<String, String> = BTreeMap::new();
    metadata.insert(
        "save_slice.import_projection".to_string(),
        match mode {
            SaveSliceProjectionMode::Standalone => "partial-runtime-restore-v1",
            SaveSliceProjectionMode::Overlay => "overlay-runtime-restore-v1",
        }
        .to_string(),
    );
    metadata.insert(
        "save_slice.calendar_source".to_string(),
        match mode {
            SaveSliceProjectionMode::Standalone => "default-1830-placeholder",
            SaveSliceProjectionMode::Overlay => "base-snapshot-preserved",
        }
        .to_string(),
    );
    metadata.insert(
        "save_slice.selected_year_seed_tuple_source".to_string(),
        "raw-lane-via-0x51d3f0".to_string(),
    );
    metadata.insert(
        "save_slice.selected_year_absolute_counter_source".to_string(),
        if save_slice.world_finance_neighborhood_state.is_some() {
            "save-direct-world-block-absolute-counter".to_string()
        } else {
            "mode-adjusted-lane-via-0x51d390-0x409e80".to_string()
        },
    );
    metadata.insert(
        "save_slice.selected_year_absolute_counter_reconstructible_from_save".to_string(),
        save_slice
            .world_finance_neighborhood_state
            .is_some()
            .to_string(),
    );
    metadata.insert(
        "save_slice.disable_cargo_economy_special_condition_slot".to_string(),
        "30".to_string(),
    );
    metadata.insert(
        "save_slice.disable_cargo_economy_special_condition_reconstructible_from_save".to_string(),
        "true".to_string(),
    );
    metadata.insert(
        "save_slice.disable_cargo_economy_special_condition_write_side_grounded".to_string(),
        "true".to_string(),
    );
    metadata.insert(
        "save_slice.selected_year_absolute_counter_adjustment_context".to_string(),
        if save_slice.world_finance_neighborhood_state.is_some() {
            "save-direct-world-block-0x32c8".to_string()
        } else {
            "editor-map-mode,shell-selected-year-adjust-policy-0x9d26-0x9d28,save-special-condition-disable-cargo-economy-slot-30"
                .to_string()
        },
    );
    metadata.insert(
        "save_slice.mechanism_family".to_string(),
        save_slice.mechanism_family.clone(),
    );
    metadata.insert(
        "save_slice.mechanism_confidence".to_string(),
        save_slice.mechanism_confidence.clone(),
    );
    if let Some(family) = &save_slice.container_profile_family {
        metadata.insert(
            "save_slice.container_profile_family".to_string(),
            family.clone(),
        );
    }
    if let Some(family) = &save_slice.trailer_family {
        metadata.insert("save_slice.trailer_family".to_string(), family.clone());
    }
    if let Some(family) = &save_slice.bridge_family {
        metadata.insert("save_slice.bridge_family".to_string(), family.clone());
    }
    if let Some(issue_state) = &save_slice.world_issue_37_state {
        metadata.insert(
            "save_slice.world_issue_37_source_kind".to_string(),
            issue_state.source_kind.clone(),
        );
        metadata.insert(
            "save_slice.world_issue_37_semantic_family".to_string(),
            issue_state.semantic_family.clone(),
        );
        metadata.insert(
            "save_slice.world_issue_37_value".to_string(),
            issue_state.issue_value.to_string(),
        );
        metadata.insert(
            "save_slice.world_issue_37_value_hex".to_string(),
            issue_state.issue_value_hex.clone(),
        );
        metadata.insert(
            "save_slice.world_issue_38_value".to_string(),
            issue_state.issue_38_value.to_string(),
        );
        metadata.insert(
            "save_slice.world_issue_38_value_hex".to_string(),
            issue_state.issue_38_value_hex.clone(),
        );
        metadata.insert(
            "save_slice.world_issue_39_value".to_string(),
            issue_state.issue_39_value.to_string(),
        );
        metadata.insert(
            "save_slice.world_issue_39_value_hex".to_string(),
            issue_state.issue_39_value_hex.clone(),
        );
        metadata.insert(
            "save_slice.world_issue_3a_value".to_string(),
            issue_state.issue_3a_value.to_string(),
        );
        metadata.insert(
            "save_slice.world_issue_3a_value_hex".to_string(),
            issue_state.issue_3a_value_hex.clone(),
        );
        metadata.insert(
            "save_slice.world_issue_37_multiplier_raw_hex".to_string(),
            issue_state.multiplier_raw_hex.clone(),
        );
        metadata.insert(
            "save_slice.world_issue_37_multiplier_value_f32".to_string(),
            issue_state.multiplier_value_f32_text.clone(),
        );
    }
    if let Some(tuning_state) = &save_slice.world_economic_tuning_state {
        metadata.insert(
            "save_slice.world_economic_tuning_source_kind".to_string(),
            tuning_state.source_kind.clone(),
        );
        metadata.insert(
            "save_slice.world_economic_tuning_semantic_family".to_string(),
            tuning_state.semantic_family.clone(),
        );
        metadata.insert(
            "save_slice.world_economic_tuning_mirror_raw_hex".to_string(),
            tuning_state.mirror_raw_hex.clone(),
        );
        metadata.insert(
            "save_slice.world_economic_tuning_mirror_value_f32".to_string(),
            tuning_state.mirror_value_f32_text.clone(),
        );
        metadata.insert(
            "save_slice.world_economic_tuning_lane_count".to_string(),
            tuning_state.lane_raw_u32.len().to_string(),
        );
        for (index, value) in tuning_state.lane_value_f32_text.iter().enumerate() {
            metadata.insert(
                format!("save_slice.world_economic_tuning_lane_{index}_f32"),
                value.clone(),
            );
        }
    }
    if let Some(finance_state) = &save_slice.world_finance_neighborhood_state {
        metadata.insert(
            "save_slice.world_finance_neighborhood_source_kind".to_string(),
            finance_state.source_kind.clone(),
        );
        metadata.insert(
            "save_slice.world_finance_neighborhood_semantic_family".to_string(),
            finance_state.semantic_family.clone(),
        );
        metadata.insert(
            "save_slice.world_finance_neighborhood_candidate_count".to_string(),
            finance_state.raw_u32.len().to_string(),
        );
        for (index, label) in finance_state.labels.iter().enumerate() {
            metadata.insert(
                format!("save_slice.world_finance_neighborhood_label_{index}"),
                label.clone(),
            );
        }
    }

    ProjectionMetadata {
        world_flags,
        metadata,
    }
}

pub(super) fn append_projection_collection_metadata(
    save_slice: &SmpLoadedSaveSlice,
    metadata: &mut BTreeMap<String, String>,
) {
    if let Some(collection) = &save_slice.placed_structure_collection {
        metadata.insert(
            "save_slice.placed_structure_collection_source_kind".to_string(),
            collection.source_kind.clone(),
        );
        metadata.insert(
            "save_slice.placed_structure_collection_semantic_family".to_string(),
            collection.semantic_family.clone(),
        );
        metadata.insert(
            "save_slice.placed_structure_collection_entry_count".to_string(),
            collection.observed_entry_count.to_string(),
        );
        metadata.insert(
            "save_slice.placed_structure_collection_farm_growth_stage_count".to_string(),
            collection
                .entries
                .iter()
                .filter(|entry| entry.farm_growth_stage_index.is_some())
                .count()
                .to_string(),
        );
        metadata.insert(
            "save_slice.placed_structure_collection_nondefault_status_count".to_string(),
            collection
                .entries
                .iter()
                .filter(|entry| entry.profile_status_kind != "unset")
                .count()
                .to_string(),
        );
    }
    if let Some(summary) = &save_slice.placed_structure_dynamic_side_buffer_summary {
        metadata.insert(
            "save_slice.placed_structure_dynamic_side_buffer_source_kind".to_string(),
            summary.source_kind.clone(),
        );
        metadata.insert(
            "save_slice.placed_structure_dynamic_side_buffer_semantic_family".to_string(),
            summary.semantic_family.clone(),
        );
        metadata.insert(
            "save_slice.placed_structure_dynamic_side_buffer_entry_count".to_string(),
            summary.observed_entry_count.to_string(),
        );
        metadata.insert(
            "save_slice.placed_structure_dynamic_side_buffer_name_pair_count".to_string(),
            summary.unique_embedded_name_pair_count.to_string(),
        );
        metadata.insert(
            "save_slice.placed_structure_dynamic_side_buffer_triplet_overlap_count".to_string(),
            summary.triplet_alignment_overlap_count.to_string(),
        );
        metadata.insert(
            "save_slice.placed_structure_dynamic_side_buffer_side_buffer_only_name_pair_count"
                .to_string(),
            summary
                .triplet_alignment_side_buffer_only_name_pair_count
                .to_string(),
        );
    }
    if let Some(collection) = &save_slice.region_collection {
        metadata.insert(
            "save_slice.region_collection_source_kind".to_string(),
            collection.source_kind.clone(),
        );
        metadata.insert(
            "save_slice.region_collection_semantic_family".to_string(),
            collection.semantic_family.clone(),
        );
        metadata.insert(
            "save_slice.region_collection_entry_count".to_string(),
            collection.observed_entry_count.to_string(),
        );
        metadata.insert(
            "save_slice.region_collection_profile_entry_count".to_string(),
            collection
                .entries
                .iter()
                .map(|entry| {
                    entry
                        .profile_collection
                        .as_ref()
                        .map(|collection| collection.entries.len())
                        .unwrap_or_default()
                })
                .sum::<usize>()
                .to_string(),
        );
        metadata.insert(
            "save_slice.region_collection_nonzero_prefix_count".to_string(),
            collection
                .entries
                .iter()
                .filter(|entry| entry.pre_name_prefix_len != 0)
                .count()
                .to_string(),
        );
        metadata.insert(
            "save_slice.region_collection_nonzero_reserved_policy_count".to_string(),
            collection
                .entries
                .iter()
                .filter(|entry| entry.policy_reserved_dwords.iter().any(|raw| *raw != 0))
                .count()
                .to_string(),
        );
    }
    if let Some(summary) = &save_slice.region_fixed_row_run_summary {
        metadata.insert(
            "save_slice.region_fixed_row_run_source_kind".to_string(),
            summary.source_kind.clone(),
        );
        metadata.insert(
            "save_slice.region_fixed_row_run_semantic_family".to_string(),
            summary.semantic_family.clone(),
        );
        metadata.insert(
            "save_slice.region_fixed_row_run_candidate_count".to_string(),
            summary.candidates.len().to_string(),
        );
        metadata.insert(
            "save_slice.region_fixed_row_run_target_row_stride_hex".to_string(),
            summary.target_row_stride_hex.clone(),
        );
        metadata.insert(
            "save_slice.region_fixed_row_run_best_rows_offset_hex".to_string(),
            summary
                .candidates
                .first()
                .map(|candidate| candidate.rows_offset_hex.clone())
                .unwrap_or_default(),
        );
        metadata.insert(
            "save_slice.region_fixed_row_run_best_shape_signature".to_string(),
            summary
                .candidates
                .first()
                .map(|candidate| candidate.shape_signature.clone())
                .unwrap_or_default(),
        );
    }
}

pub(super) fn append_projection_note_metadata(
    save_slice: &SmpLoadedSaveSlice,
    metadata: &mut BTreeMap<String, String>,
) {
    for (index, note) in save_slice.notes.iter().enumerate() {
        metadata.insert(format!("save_slice.note.{index}"), note.clone());
    }
}
