use std::collections::HashMap;

use super::*;

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
struct ImportedMaterialPreviewKey {
    asset_id: String,
    sub_asset_id: String,
    source: String,
    fingerprint: String,
}

#[derive(Resource, Default)]
struct ImportedMaterialPreviewCache {
    entries: HashMap<ImportedMaterialPreviewKey, Result<MaterialAsset, String>>,
}

pub(super) fn imported_material_parameters_ui(
    world: &mut World,
    ui: &mut egui::Ui,
    reference: &MaterialRef,
) {
    let record = world.get_resource::<AssetRegistry>().and_then(|registry| {
        registry
            .records
            .iter()
            .find(|record| record.id.as_string() == reference.0.asset_id)
    });
    let source = reference
        .0
        .source_path
        .clone()
        .or_else(|| record.map(|record| record.path.clone()));
    let Some(source) = source else {
        ui.colored_label(crate::ui::theme::ERROR, "Material reference is unresolved");
        return;
    };
    let key = ImportedMaterialPreviewKey {
        asset_id: reference.0.asset_id.clone(),
        sub_asset_id: reference.0.sub_asset_id.clone(),
        source: source.clone(),
        fingerprint: record
            .and_then(|record| record.source_fingerprint.as_ref())
            .map(|fingerprint| fingerprint.content_hash.clone())
            .unwrap_or_default(),
    };
    if !world.contains_resource::<ImportedMaterialPreviewCache>() {
        world.init_resource::<ImportedMaterialPreviewCache>();
    }
    let cached = world
        .resource::<ImportedMaterialPreviewCache>()
        .entries
        .get(&key)
        .cloned();
    let preview = cached.unwrap_or_else(|| {
        let result = crate::assets::plan_model_material_extraction(
            Path::new(&source),
            Path::new("assets/materials"),
        )
        .map_err(|error| format!("Imported material parameters are unavailable: {error}"))
        .and_then(|planned| {
            planned
                .into_iter()
                .find(|material| {
                    material
                        .asset
                        .provenance
                        .as_ref()
                        .is_some_and(|provenance| {
                            provenance.source_sub_asset_id == reference.0.sub_asset_id
                        })
                })
                .map(|material| material.asset)
                .ok_or_else(|| "Imported material slot is missing".to_string())
        });
        world
            .resource_mut::<ImportedMaterialPreviewCache>()
            .entries
            .insert(key, result.clone());
        result
    });
    let asset = match preview {
        Ok(asset) => asset,
        Err(error) => {
            ui.colored_label(crate::ui::theme::ERROR, error);
            return;
        }
    };
    let mut inputs = asset.inputs.clone();
    ui.add_enabled_ui(false, |ui| {
        property_row(ui, "Shader", |ui| {
            ui.label(match asset.shader.kind {
                MaterialShaderKind::StandardLit => "Standard Lit",
                MaterialShaderKind::Unlit => "Unlit",
                MaterialShaderKind::Custom => "Custom",
            });
        });
        egui::CollapsingHeader::new("Surface Options")
            .default_open(true)
            .show(ui, |ui| {
                ui.label(format!("Alpha mode: {:?}", asset.render_state.alpha_mode));
                let mut double_sided = asset.render_state.double_sided;
                ui.checkbox(&mut double_sided, "Double sided");
            });
        material_input_schema_editor(ui, &standard_lit_input_schema(), &mut inputs, &[], None);
    });
    ui.small(egui::RichText::new("Imported source · read-only").color(TEXT_DIM));
}
