use crate::Editor;
use crate::app_context::{SceneBrowserContext, SceneInfo};
use crate::mosaic::Mosaic;
use crate::widgets::{EditorWidget, MaterialsWidget};
use nightshade::prelude::*;

#[derive(Clone)]
pub enum SceneAction {
    SwitchTo(String),
    #[cfg(not(target_arch = "wasm32"))]
    Import(std::path::PathBuf),
    #[cfg(not(target_arch = "wasm32"))]
    Export(std::path::PathBuf),
    Delete(String),
}

#[derive(Clone)]
pub enum EditorMessage {
    SceneAction(SceneAction),
}

impl Editor {
    pub fn render_mosaic_and_scene_browser(
        &mut self,
        world: &mut World,
        ui_context: &egui::Context,
    ) {
        #[cfg(not(target_arch = "wasm32"))]
        self.context.ui.web_widget_rects.clear();

        Mosaic::<EditorWidget, crate::app_context::AppContext, EditorMessage>::clear_required_cameras(world);

        if self.scene_browser_dirty {
            self.scene_browser_dirty = false;
            self.context.scene_browser = self
                .project
                .as_ref()
                .map(|project| {
                    let data = project.data.as_ref();
                    let active_name = data.and_then(|d| d.active_scene_name.as_deref());
                    let scenes_map = data.map(|d| &d.scenes);
                    let mut scenes: Vec<_> = scenes_map
                        .into_iter()
                        .flat_map(|s| s.iter())
                        .map(|(name, scene)| SceneInfo {
                            name: name.clone(),
                            entity_count: scene.entities.len(),
                            is_active: active_name == Some(name.as_str()),
                        })
                        .collect();
                    scenes.sort_by(|a, b| a.name.cmp(&b.name));
                    SceneBrowserContext {
                        scenes,
                        has_project: true,
                    }
                })
                .unwrap_or_default();
        }

        egui::CentralPanel::default()
            .frame(egui::Frame::NONE)
            .show(ui_context, |ui| {
                self.mosaic.show_inside(world, ui, &mut self.context);
            });
    }

    pub fn process_mosaic_messages(&mut self, world: &mut World) {
        for action in self.context.assets.inspector_actions.drain(..) {
            match action {
                crate::engine_editor::InspectorAction::LookupMaterial(material_name) => {
                    let found = self
                        .mosaic
                        .find_widget(|widget| matches!(widget, EditorWidget::Materials(_)));

                    if let Some(tile_id) = found {
                        if let Some(EditorWidget::Materials(materials_widget)) =
                            self.mosaic.get_widget_mut(tile_id)
                        {
                            materials_widget.selected_material = Some(material_name);
                        }
                    } else {
                        self.mosaic
                            .insert_pane(EditorWidget::Materials(MaterialsWidget {
                                selected_material: Some(material_name),
                                ..Default::default()
                            }));
                    }
                }
            }
        }

        for message in self.mosaic.drain_messages() {
            match message {
                EditorMessage::SceneAction(action) => match action {
                    SceneAction::SwitchTo(name) => {
                        self.switch_to_map(world, &name);
                    }
                    #[cfg(not(target_arch = "wasm32"))]
                    SceneAction::Import(path) => {
                        self.load_scene_from_path(world, &path);
                    }
                    #[cfg(not(target_arch = "wasm32"))]
                    SceneAction::Export(path) => {
                        self.export_scene_to_path(world, &path);
                    }
                    SceneAction::Delete(name) => {
                        if let Some(ref mut project) = self.project
                            && let Some(data) = project.data.as_mut()
                            && data.scenes.len() > 1
                            && data.active_scene_name.as_deref() != Some(&name)
                        {
                            data.remove_scene(&name);
                            self.project_state.mark_modified();
                            self.scene_browser_dirty = true;
                            #[cfg(not(target_arch = "wasm32"))]
                            self.toasts.push(
                                crate::mosaic::ToastKind::Success,
                                format!("Deleted scene: {}", name),
                                3.0,
                            );
                        }
                    }
                },
            }
        }

        if self.mosaic.take_layout_modified() {
            self.project_state.mark_modified();
        }
    }
}
