use super::*;

pub(super) fn import_settings_editor(
    world: &mut World,
    ui: &mut egui::Ui,
    _asset: &EditorAsset,
    path: &str,
    current: &ImportSettings,
) {
    let material_slots = current
        .static_mesh_manifest_path
        .as_deref()
        .and_then(|manifest_path| load_static_mesh_manifest(manifest_path).ok())
        .map(|manifest| {
            manifest
                .parts
                .into_iter()
                .map(|part| {
                    let part_id = if part.id.trim().is_empty() {
                        part_id_from_label(&part.mesh_label)
                    } else {
                        part.id
                    };
                    (
                        shared::ComponentInstanceId::new(format!("slot:{part_id}")),
                        part.material_slot_name,
                        part.material_id.is_some() || part.material_label.is_some(),
                    )
                })
                .collect::<Vec<_>>()
        })
        .unwrap_or_default();
    let project_materials = world
        .resource::<AssetRegistry>()
        .records
        .iter()
        .filter(|record| {
            matches!(
                record.kind,
                AssetKind::Material | AssetKind::MaterialInstance
            )
        })
        .map(|record| {
            (
                record.label.clone(),
                MaterialRef::new(
                    EditorAssetRef::new(record.id.as_string(), "", record.label.clone())
                        .with_source_path(record.path.clone()),
                ),
            )
        })
        .collect::<Vec<_>>();
    if Path::new(path)
        .extension()
        .and_then(|extension| extension.to_str())
        .is_some_and(|extension| {
            matches!(
                extension.to_ascii_lowercase().as_str(),
                "gltf" | "glb" | "fbx"
            )
        })
        && ui.button("Extract Editable Materials Here").clicked()
    {
        begin_gltf_material_extraction(world, path);
    }
    let animation_clip_options = current
        .animation_manifest_path
        .as_deref()
        .and_then(|manifest_path| load_animation_manifest(manifest_path).ok())
        .map(|manifest| {
            manifest
                .clips
                .into_iter()
                .map(|clip| (clip.id, clip.label))
                .collect::<Vec<_>>()
        })
        .unwrap_or_default();
    let registry_record = world
        .resource::<AssetRegistry>()
        .records
        .iter()
        .find(|record| record.path == path)
        .cloned()
        .expect("model details require a registry record");
    let document_key =
        crate::asset_documents::ensure_model_import_document(world, &registry_record);
    let mut draft_settings = world
        .resource::<crate::asset_documents::AuthoredAssetDocumentStore>()
        .model_import(&document_key)
        .cloned()
        .unwrap_or_else(|| current.clone());
    let original_settings = draft_settings.clone();
    if let Some(snapshot) = world
        .resource::<crate::asset_documents::AuthoredAssetDocumentStore>()
        .snapshot(&document_key)
    {
        authored_document_status_ui(ui, &snapshot);
    }
    let mut locate_material_path = None;
    ui.add(egui::Slider::new(&mut draft_settings.scale, 0.01..=10.0).text("Scale"));
    ui.checkbox(&mut draft_settings.generate_collider, "Generate collider");
    ui.checkbox(&mut draft_settings.lod0_only, "LOD0 only");
    egui::ComboBox::from_id_salt("model_placement_mode")
        .selected_text(match draft_settings.placement_mode {
            ModelPlacementMode::StaticAsset => "Renderable Asset (Auto)",
            ModelPlacementMode::SceneInstance => "Scene Instance",
        })
        .show_ui(ui, |ui| {
            ui.selectable_value(
                &mut draft_settings.placement_mode,
                ModelPlacementMode::StaticAsset,
                "Renderable Asset (Auto)",
            );
            ui.selectable_value(
                &mut draft_settings.placement_mode,
                ModelPlacementMode::SceneInstance,
                "Scene Instance",
            );
        });
    egui::ComboBox::from_id_salt("model_hierarchy_mode")
        .selected_text(match draft_settings.hierarchy_mode {
            ModelHierarchyMode::SingleActor => "One Actor",
            ModelHierarchyMode::SourceHierarchy => "Source Hierarchy",
        })
        .show_ui(ui, |ui| {
            ui.selectable_value(
                &mut draft_settings.hierarchy_mode,
                ModelHierarchyMode::SingleActor,
                "One Actor",
            );
            ui.selectable_value(
                &mut draft_settings.hierarchy_mode,
                ModelHierarchyMode::SourceHierarchy,
                "Source Hierarchy",
            );
        });
    if !material_slots.is_empty() {
        ui.separator();
        ui.label(egui::RichText::new("Model Material Slots").strong());
        ui.horizontal(|ui| {
            if ui.small_button("All Source").clicked() {
                draft_settings.material_slots = material_slots
                    .iter()
                    .map(|(slot_id, _, _)| ModelMaterialSlotSelection {
                        slot_id: slot_id.clone(),
                        selection: ModelMaterialSelection::Source,
                    })
                    .collect();
            }
            if ui.small_button("All Default").clicked() {
                draft_settings.material_slots = material_slots
                    .iter()
                    .map(|(slot_id, _, _)| ModelMaterialSlotSelection {
                        slot_id: slot_id.clone(),
                        selection: ModelMaterialSelection::Default,
                    })
                    .collect();
            }
        });
        for (slot_id, name, source_valid) in &material_slots {
            let selection = draft_settings
                .material_slots
                .iter()
                .find(|entry| entry.slot_id == *slot_id)
                .map(|entry| entry.selection.clone())
                .unwrap_or_default();
            let selected_text = match &selection {
                ModelMaterialSelection::Source if *source_valid => "Source".to_string(),
                ModelMaterialSelection::Source => "Source (missing → DefaultGrid)".to_string(),
                ModelMaterialSelection::Project(reference) => reference.0.label.clone(),
                ModelMaterialSelection::Default => {
                    "Default (project fallback → DefaultGrid)".to_string()
                }
            };
            ui.horizontal(|ui| {
                    ui.vertical(|ui| {
                        ui.label(name);
                        ui.small(format!("{} · source {}", slot_id.0, if *source_valid { "valid" } else { "missing" }));
                    });
                    egui::ComboBox::from_id_salt(("model_material_slot", &slot_id.0))
                        .selected_text(selected_text)
                        .show_ui(ui, |ui| {
                            let mut chosen = None;
                            if ui.selectable_label(matches!(selection, ModelMaterialSelection::Source), "Source").clicked() {
                                chosen = Some(ModelMaterialSelection::Source);
                            }
                            for (label, reference) in &project_materials {
                                let selected = matches!(&selection, ModelMaterialSelection::Project(current) if current == reference);
                                if ui.selectable_label(selected, label).clicked() {
                                    chosen = Some(ModelMaterialSelection::Project(reference.clone()));
                                }
                            }
                            if ui.selectable_label(matches!(selection, ModelMaterialSelection::Default), "Default (project fallback → DefaultGrid)").clicked() {
                                chosen = Some(ModelMaterialSelection::Default);
                            }
                            if let Some(selection) = chosen {
                                if let Some(entry) = draft_settings.material_slots.iter_mut().find(|entry| entry.slot_id == *slot_id) {
                                    entry.selection = selection;
                                } else {
                                    draft_settings.material_slots.push(ModelMaterialSlotSelection { slot_id: slot_id.clone(), selection });
                                }
                            }
                        });
                    if let ModelMaterialSelection::Project(reference) = &selection {
                        let source_path = reference.0.source_path.clone();
                        if ui
                            .add_enabled(source_path.is_some(), egui::Button::new("Locate"))
                            .on_disabled_hover_text("The referenced project Material has no content path")
                            .clicked()
                        {
                            locate_material_path = source_path;
                        }
                    }
                    if !matches!(selection, ModelMaterialSelection::Source)
                        && ui.small_button("Clear").clicked()
                    {
                        set_model_material_slot_selection(
                            &mut draft_settings,
                            slot_id,
                            ModelMaterialSelection::Source,
                        );
                    }
                });
        }
        let mut orphan_to_clear = None;
        for orphan in &draft_settings.orphaned_material_slots {
            ui.horizontal(|ui| {
                ui.colored_label(
                    WARNING,
                    format!(
                        "Orphaned {} → {}",
                        orphan.slot_id.0, orphan.material.0.label
                    ),
                );
                let source_path = orphan.material.0.source_path.clone();
                if ui
                    .add_enabled(source_path.is_some(), egui::Button::new("Locate"))
                    .on_disabled_hover_text("The referenced project Material has no content path")
                    .clicked()
                {
                    locate_material_path = source_path;
                }
                if ui.small_button("Clear Orphan").clicked() {
                    orphan_to_clear = Some(orphan.slot_id.clone());
                }
            });
        }
        if let Some(slot_id) = orphan_to_clear {
            clear_orphaned_model_material_selection(&mut draft_settings, &slot_id);
        }
        ui.small("Precedence: scene slot → model slot → imported source → project default → DefaultGrid.");
    }
    if !animation_clip_options.is_empty() {
        let selected_default = draft_settings
            .default_animation_clip_id
            .as_deref()
            .and_then(|id| {
                animation_clip_options
                    .iter()
                    .find(|(clip_id, _)| clip_id == id)
                    .map(|(_, label)| label.as_str())
            })
            .unwrap_or_else(|| {
                if draft_settings.default_animation_clip_id.is_some() {
                    "Missing clip"
                } else {
                    "Imported rest pose"
                }
            });
        egui::ComboBox::from_id_salt("model_default_animation_clip")
            .selected_text(selected_default)
            .show_ui(ui, |ui| {
                ui.selectable_value(
                    &mut draft_settings.default_animation_clip_id,
                    None,
                    "Imported rest pose",
                );
                for (clip_id, label) in &animation_clip_options {
                    ui.selectable_value(
                        &mut draft_settings.default_animation_clip_id,
                        Some(clip_id.clone()),
                        label,
                    );
                }
            });
        ui.small("Default animation is sampled and paused in edit mode; no clip is guessed.");
    }
    if draft_settings != original_settings {
        world
            .resource_mut::<crate::asset_documents::AuthoredAssetDocumentStore>()
            .update_model_import(&document_key, draft_settings);
    }
    if let Some(path) = locate_material_path {
        locate_content_asset(world, &path);
    }
}

pub(super) fn set_model_material_slot_selection(
    settings: &mut ImportSettings,
    slot_id: &shared::ComponentInstanceId,
    selection: ModelMaterialSelection,
) {
    if let Some(entry) = settings
        .material_slots
        .iter_mut()
        .find(|entry| entry.slot_id == *slot_id)
    {
        entry.selection = selection;
    } else {
        settings.material_slots.push(ModelMaterialSlotSelection {
            slot_id: slot_id.clone(),
            selection,
        });
    }
}

pub(super) fn clear_orphaned_model_material_selection(
    settings: &mut ImportSettings,
    slot_id: &shared::ComponentInstanceId,
) -> bool {
    let previous_len = settings.orphaned_material_slots.len();
    settings
        .orphaned_material_slots
        .retain(|orphan| orphan.slot_id != *slot_id);
    settings.orphaned_material_slots.len() != previous_len
}

pub(super) fn texture_import_settings_editor(
    world: &mut World,
    ui: &mut egui::Ui,
    path: &str,
    record: &crate::asset_db::AssetRecord,
    current: &TextureImportSettings,
) {
    let document_key = crate::asset_documents::ensure_texture_import_document(world, record);
    let mut draft_settings = world
        .resource::<crate::asset_documents::AuthoredAssetDocumentStore>()
        .texture_import(&document_key)
        .cloned()
        .unwrap_or_else(|| current.clone());
    let original_settings = draft_settings.clone();
    if let Some(snapshot) = world
        .resource::<crate::asset_documents::AuthoredAssetDocumentStore>()
        .snapshot(&document_key)
    {
        authored_document_status_ui(ui, &snapshot);
    }
    egui::Grid::new(("texture_import_settings", path))
        .num_columns(2)
        .spacing([12.0, 6.0])
        .show(ui, |ui| {
            ui.label("Semantic");
            egui::ComboBox::from_id_salt(("texture_semantic", path))
                .selected_text(texture_semantic_label(draft_settings.semantic))
                .show_ui(ui, |ui| {
                    for (value, label) in [
                        (TextureAssetSemantic::Auto, "Auto"),
                        (TextureAssetSemantic::Color, "Color"),
                        (TextureAssetSemantic::Normal, "Normal"),
                        (TextureAssetSemantic::MaskData, "Mask / Data"),
                        (TextureAssetSemantic::Ui, "UI"),
                        (TextureAssetSemantic::Hdr, "HDR"),
                    ] {
                        ui.selectable_value(&mut draft_settings.semantic, value, label);
                    }
                });
            ui.end_row();

            ui.label("Color space");
            egui::ComboBox::from_id_salt(("texture_color_space", path))
                .selected_text(match draft_settings.color_space {
                    TextureColorSpace::Auto => "Auto",
                    TextureColorSpace::Srgb => "sRGB",
                    TextureColorSpace::Linear => "Linear",
                })
                .show_ui(ui, |ui| {
                    ui.selectable_value(
                        &mut draft_settings.color_space,
                        TextureColorSpace::Auto,
                        "Auto",
                    );
                    ui.selectable_value(
                        &mut draft_settings.color_space,
                        TextureColorSpace::Srgb,
                        "sRGB",
                    );
                    ui.selectable_value(
                        &mut draft_settings.color_space,
                        TextureColorSpace::Linear,
                        "Linear",
                    );
                });
            ui.end_row();

            ui.label("Mipmaps");
            egui::ComboBox::from_id_salt(("texture_mipmaps", path))
                .selected_text(match draft_settings.mipmaps {
                    TextureMipmapMode::Generate => "Generate",
                    TextureMipmapMode::PreserveSource => "Preserve Source",
                    TextureMipmapMode::None => "None",
                })
                .show_ui(ui, |ui| {
                    ui.selectable_value(
                        &mut draft_settings.mipmaps,
                        TextureMipmapMode::Generate,
                        "Generate",
                    );
                    ui.selectable_value(
                        &mut draft_settings.mipmaps,
                        TextureMipmapMode::PreserveSource,
                        "Preserve Source",
                    );
                    ui.selectable_value(
                        &mut draft_settings.mipmaps,
                        TextureMipmapMode::None,
                        "None",
                    );
                });
            ui.end_row();

            ui.label("Compression");
            egui::ComboBox::from_id_salt(("texture_compression", path))
                .selected_text(match draft_settings.compression {
                    TextureCompression::Auto => "Auto",
                    TextureCompression::Uastc => "Basis UASTC",
                    TextureCompression::Uncompressed => "Uncompressed KTX2",
                })
                .show_ui(ui, |ui| {
                    ui.selectable_value(
                        &mut draft_settings.compression,
                        TextureCompression::Auto,
                        "Auto",
                    );
                    ui.selectable_value(
                        &mut draft_settings.compression,
                        TextureCompression::Uastc,
                        "Basis UASTC",
                    );
                    ui.selectable_value(
                        &mut draft_settings.compression,
                        TextureCompression::Uncompressed,
                        "Uncompressed KTX2",
                    );
                });
            ui.end_row();

            ui.label("Maximum size");
            ui.horizontal(|ui| {
                let mut enabled = draft_settings.max_dimension.is_some();
                if ui.checkbox(&mut enabled, "").changed() {
                    draft_settings.max_dimension = enabled.then_some(2048);
                }
                if let Some(dimension) = draft_settings.max_dimension.as_mut() {
                    ui.add(egui::DragValue::new(dimension).range(1..=16_384));
                } else {
                    ui.weak("No limit");
                }
            });
            ui.end_row();
        });

    ui.collapsing("Sampling", |ui| {
        egui::Grid::new(("texture_sampling", path))
            .num_columns(2)
            .spacing([12.0, 6.0])
            .show(ui, |ui| {
                ui.label("Filtering");
                egui::ComboBox::from_id_salt(("texture_filter", path))
                    .selected_text(match draft_settings.filter {
                        TextureFilter::Nearest => "Nearest",
                        TextureFilter::Linear => "Linear",
                    })
                    .show_ui(ui, |ui| {
                        ui.selectable_value(
                            &mut draft_settings.filter,
                            TextureFilter::Nearest,
                            "Nearest",
                        );
                        ui.selectable_value(
                            &mut draft_settings.filter,
                            TextureFilter::Linear,
                            "Linear",
                        );
                    });
                ui.end_row();

                ui.label("Wrapping");
                egui::ComboBox::from_id_salt(("texture_wrap", path))
                    .selected_text(match draft_settings.wrap {
                        TextureWrap::Repeat => "Repeat",
                        TextureWrap::Clamp => "Clamp",
                        TextureWrap::Mirror => "Mirror",
                    })
                    .show_ui(ui, |ui| {
                        ui.selectable_value(
                            &mut draft_settings.wrap,
                            TextureWrap::Repeat,
                            "Repeat",
                        );
                        ui.selectable_value(&mut draft_settings.wrap, TextureWrap::Clamp, "Clamp");
                        ui.selectable_value(
                            &mut draft_settings.wrap,
                            TextureWrap::Mirror,
                            "Mirror",
                        );
                    });
                ui.end_row();

                ui.label("Anisotropy");
                ui.add(egui::Slider::new(&mut draft_settings.anisotropy, 1..=16));
                ui.end_row();
            });
    });

    if matches!(
        draft_settings.semantic,
        TextureAssetSemantic::Auto | TextureAssetSemantic::Normal
    ) {
        ui.horizontal(|ui| {
            ui.label("Normal convention");
            ui.selectable_value(
                &mut draft_settings.normal_map_convention,
                NormalMapConvention::OpenGl,
                "OpenGL (+Y)",
            );
            ui.selectable_value(
                &mut draft_settings.normal_map_convention,
                NormalMapConvention::DirectX,
                "DirectX (-Y → +Y)",
            );
        });
    }

    let mut normalized = draft_settings.clone();
    content_pipeline::normalize_texture_settings(path, &mut normalized);
    ui.small(format!(
        "Processed as {} · {} · {}",
        texture_semantic_label(normalized.semantic),
        if shared::resolves_srgb(&normalized) {
            "sRGB"
        } else {
            "Linear"
        },
        match normalized.compression {
            TextureCompression::Uastc => "Basis UASTC",
            TextureCompression::Uncompressed => "KTX2",
            TextureCompression::Auto => "Auto",
        }
    ));
    if draft_settings != original_settings {
        world
            .resource_mut::<crate::asset_documents::AuthoredAssetDocumentStore>()
            .update_texture_import(&document_key, draft_settings);
    }
}

pub(super) fn texture_semantic_label(semantic: TextureAssetSemantic) -> &'static str {
    match semantic {
        TextureAssetSemantic::Auto => "Auto",
        TextureAssetSemantic::Color => "Color",
        TextureAssetSemantic::Normal => "Normal",
        TextureAssetSemantic::MaskData => "Mask / Data",
        TextureAssetSemantic::Ui => "UI",
        TextureAssetSemantic::Hdr => "HDR",
    }
}
