use super::{ComponentInspector, EditorContext};
use nightshade::ecs::generational_registry::{registry_entry_by_name, registry_entry_by_name_mut};
use nightshade::prelude::*;

#[derive(Default)]
pub struct MaterialInspector {
    editing: bool,
}

impl ComponentInspector for MaterialInspector {
    fn name(&self) -> &str {
        "Material"
    }

    fn has_component(&self, world: &World, entity: Entity) -> bool {
        world.get_material_ref(entity).is_some()
    }

    fn add_component(&self, world: &mut World, entity: Entity) {
        if let Some(&index) = world
            .resources
            .material_registry
            .registry
            .name_to_index
            .get("Default")
        {
            world
                .resources
                .material_registry
                .registry
                .add_reference(index);
        }
        world.set_material_ref(entity, MaterialRef::new("Default".to_string()));
    }

    fn remove_component(&self, world: &mut World, entity: Entity) {
        let material_name = world.get_material_ref(entity).map(|r| r.name.clone());
        if let Some(name) = material_name
            && let Some(&index) = world
                .resources
                .material_registry
                .registry
                .name_to_index
                .get(&name)
        {
            world
                .resources
                .material_registry
                .registry
                .remove_reference(index);
        }
        world.remove_material_ref(entity);
    }

    fn ui(
        &mut self,
        world: &mut World,
        entity: Entity,
        ui: &mut egui::Ui,
        editor: &mut EditorContext,
    ) {
        ui.label("Material");

        let material_name = if let Some(material_ref) = world.get_material_ref(entity) {
            material_ref.name.clone()
        } else {
            return;
        };

        let available_materials: Vec<String> = world
            .resources
            .material_registry
            .registry
            .index_to_name
            .iter()
            .filter_map(|opt| opt.clone())
            .collect();

        let mut selected_name = material_name.clone();
        ui.horizontal(|ui| {
            ui.label("Material:");
            egui::ComboBox::from_id_salt("material_selector")
                .selected_text(&selected_name)
                .show_ui(ui, |ui| {
                    for name in &available_materials {
                        ui.selectable_value(&mut selected_name, name.clone(), name);
                    }
                });
        });

        if selected_name != material_name {
            if let Some(&index) = world
                .resources
                .material_registry
                .registry
                .name_to_index
                .get(&material_name)
            {
                world
                    .resources
                    .material_registry
                    .registry
                    .remove_reference(index);
            }
            if let Some(&index) = world
                .resources
                .material_registry
                .registry
                .name_to_index
                .get(&selected_name)
            {
                world
                    .resources
                    .material_registry
                    .registry
                    .add_reference(index);
            }
            world.set_material_ref(entity, MaterialRef::new(selected_name.clone()));
            self.editing = false;
            return;
        }

        ui.separator();

        if self.editing {
            if let Some(material) = registry_entry_by_name_mut(
                &mut world.resources.material_registry.registry,
                &material_name,
            ) {
                let mut changed = false;

                ui.horizontal(|ui| {
                    ui.label("Base Color:");
                    if ui
                        .color_edit_button_rgba_unmultiplied(&mut material.base_color)
                        .changed()
                    {
                        changed = true;
                    }
                });

                ui.horizontal(|ui| {
                    ui.label("R:");
                    if ui
                        .add(
                            egui::Slider::new(&mut material.base_color[0], 0.0..=1.0)
                                .fixed_decimals(2),
                        )
                        .changed()
                    {
                        changed = true;
                    }
                });

                ui.horizontal(|ui| {
                    ui.label("G:");
                    if ui
                        .add(
                            egui::Slider::new(&mut material.base_color[1], 0.0..=1.0)
                                .fixed_decimals(2),
                        )
                        .changed()
                    {
                        changed = true;
                    }
                });

                ui.horizontal(|ui| {
                    ui.label("B:");
                    if ui
                        .add(
                            egui::Slider::new(&mut material.base_color[2], 0.0..=1.0)
                                .fixed_decimals(2),
                        )
                        .changed()
                    {
                        changed = true;
                    }
                });

                ui.horizontal(|ui| {
                    ui.label("A:");
                    if ui
                        .add(
                            egui::Slider::new(&mut material.base_color[3], 0.0..=1.0)
                                .fixed_decimals(2),
                        )
                        .changed()
                    {
                        changed = true;
                    }
                });

                ui.separator();

                ui.horizontal(|ui| {
                    ui.label("Alpha Mode:");
                    egui::ComboBox::from_id_salt("inspector_alpha_mode")
                        .selected_text(match material.alpha_mode {
                            AlphaMode::Opaque => "Opaque",
                            AlphaMode::Mask => "Mask",
                            AlphaMode::Blend => "Blend",
                        })
                        .show_ui(ui, |ui| {
                            if ui
                                .selectable_value(
                                    &mut material.alpha_mode,
                                    AlphaMode::Opaque,
                                    "Opaque",
                                )
                                .changed()
                            {
                                changed = true;
                            }
                            if ui
                                .selectable_value(&mut material.alpha_mode, AlphaMode::Mask, "Mask")
                                .changed()
                            {
                                changed = true;
                            }
                            if ui
                                .selectable_value(
                                    &mut material.alpha_mode,
                                    AlphaMode::Blend,
                                    "Blend",
                                )
                                .changed()
                            {
                                changed = true;
                            }
                        });
                });

                if material.alpha_mode == AlphaMode::Mask {
                    ui.horizontal(|ui| {
                        ui.label("Alpha Cutoff:");
                        if ui
                            .add(
                                egui::Slider::new(&mut material.alpha_cutoff, 0.0..=1.0)
                                    .fixed_decimals(2),
                            )
                            .changed()
                        {
                            changed = true;
                        }
                    });
                }

                ui.separator();

                ui.horizontal(|ui| {
                    ui.label("Roughness:");
                    if ui
                        .add(
                            egui::Slider::new(&mut material.roughness, 0.0..=1.0).fixed_decimals(2),
                        )
                        .changed()
                    {
                        changed = true;
                    }
                });

                ui.horizontal(|ui| {
                    ui.label("Metallic:");
                    if ui
                        .add(egui::Slider::new(&mut material.metallic, 0.0..=1.0).fixed_decimals(2))
                        .changed()
                    {
                        changed = true;
                    }
                });

                ui.horizontal(|ui| {
                    ui.label("Unlit:");
                    if ui.checkbox(&mut material.unlit, "").changed() {
                        changed = true;
                    }
                });

                ui.separator();

                ui.label("Emissive Factor:");

                ui.horizontal(|ui| {
                    ui.label("R:");
                    if ui
                        .add(
                            egui::Slider::new(&mut material.emissive_factor[0], 0.0..=1.0)
                                .fixed_decimals(2),
                        )
                        .changed()
                    {
                        changed = true;
                    }
                });

                ui.horizontal(|ui| {
                    ui.label("G:");
                    if ui
                        .add(
                            egui::Slider::new(&mut material.emissive_factor[1], 0.0..=1.0)
                                .fixed_decimals(2),
                        )
                        .changed()
                    {
                        changed = true;
                    }
                });

                ui.horizontal(|ui| {
                    ui.label("B:");
                    if ui
                        .add(
                            egui::Slider::new(&mut material.emissive_factor[2], 0.0..=1.0)
                                .fixed_decimals(2),
                        )
                        .changed()
                    {
                        changed = true;
                    }
                });

                if changed {
                    editor.pending_info_toast =
                        Some(format!("Material '{}' modified", material_name));
                }

                ui.separator();

                if ui.button("Done Editing").clicked() {
                    self.editing = false;
                }
            }
        } else if let Some(material) =
            registry_entry_by_name(&world.resources.material_registry.registry, &material_name)
        {
            ui.horizontal(|ui| {
                ui.label("Base Color:");
                let color = egui::Color32::from_rgba_unmultiplied(
                    (material.base_color[0] * 255.0) as u8,
                    (material.base_color[1] * 255.0) as u8,
                    (material.base_color[2] * 255.0) as u8,
                    (material.base_color[3] * 255.0) as u8,
                );
                let (rect, _) =
                    ui.allocate_exact_size(egui::vec2(48.0, 18.0), egui::Sense::hover());
                ui.painter().rect_filled(rect, 2.0, color);
                ui.painter().rect_stroke(
                    rect,
                    2.0,
                    egui::Stroke::new(1.0, egui::Color32::GRAY),
                    egui::StrokeKind::Inside,
                );
            });

            ui.horizontal(|ui| {
                ui.label("Alpha Mode:");
                ui.label(match material.alpha_mode {
                    AlphaMode::Opaque => "Opaque",
                    AlphaMode::Mask => "Mask",
                    AlphaMode::Blend => "Blend",
                });
            });

            if material.alpha_mode == AlphaMode::Mask {
                ui.horizontal(|ui| {
                    ui.label("Alpha Cutoff:");
                    ui.label(format!("{:.2}", material.alpha_cutoff));
                });
            }

            ui.horizontal(|ui| {
                ui.label("Roughness:");
                ui.label(format!("{:.2}", material.roughness));
                ui.label("Metallic:");
                ui.label(format!("{:.2}", material.metallic));
            });

            if material.unlit {
                ui.label("Unlit: Yes");
            }

            if material.emissive_factor[0] > 0.0
                || material.emissive_factor[1] > 0.0
                || material.emissive_factor[2] > 0.0
            {
                ui.horizontal(|ui| {
                    ui.label("Emissive:");
                    let color = egui::Color32::from_rgb(
                        (material.emissive_factor[0] * 255.0) as u8,
                        (material.emissive_factor[1] * 255.0) as u8,
                        (material.emissive_factor[2] * 255.0) as u8,
                    );
                    let (rect, _) =
                        ui.allocate_exact_size(egui::vec2(48.0, 18.0), egui::Sense::hover());
                    ui.painter().rect_filled(rect, 2.0, color);
                    ui.painter().rect_stroke(
                        rect,
                        2.0,
                        egui::Stroke::new(1.0, egui::Color32::GRAY),
                        egui::StrokeKind::Inside,
                    );
                });
            }

            if let Some(texture) = &material.base_texture {
                ui.horizontal(|ui| {
                    ui.label("Base Texture:");
                    ui.label(texture);
                });
            }

            if let Some(texture) = &material.emissive_texture {
                ui.horizontal(|ui| {
                    ui.label("Emissive Texture:");
                    ui.label(texture);
                });
            }

            ui.separator();

            let ref_count = world
                .resources
                .material_registry
                .registry
                .name_to_index
                .get(&material_name)
                .map(|&index| {
                    world.resources.material_registry.registry.reference_counts[index as usize]
                })
                .unwrap_or(0);
            ui.small(format!("Used by {} entities", ref_count));

            ui.horizontal(|ui| {
                if ui.button("Lookup Material").clicked() {
                    editor.pending_material_edit = Some(material_name.clone());
                }
                if ui.button("Edit Material").clicked() {
                    self.editing = true;
                }
            });
        }
    }
}
