use nightshade::prelude::*;

pub struct WidgetEntry<W> {
    pub name: String,
    pub create: fn() -> W,
}

pub struct WidgetContext<'a, C = (), M = ()> {
    pub(crate) world: &'a mut World,
    pub viewport_textures: &'a [egui::TextureId],
    pub current_tile_id: egui_tiles::TileId,
    pub selected_viewport_tile: &'a mut Option<egui_tiles::TileId>,
    pub app: &'a mut C,
    pub cached_cameras: &'a [Entity],
    pub(crate) messages: &'a mut Vec<M>,
}

impl<C, M> WidgetContext<'_, C, M> {
    pub fn world(&self) -> &World {
        self.world
    }

    pub fn world_mut(&mut self) -> &mut World {
        self.world
    }

    pub fn send(&mut self, message: M) {
        self.messages.push(message);
    }
}

pub trait Widget<C = (), M = ()>:
    Clone + serde::Serialize + serde::de::DeserializeOwned + 'static
{
    fn title(&self) -> String;
    fn ui(&mut self, ui: &mut egui::Ui, context: &mut WidgetContext<C, M>);

    fn on_add(&mut self, _context: &mut WidgetContext<C, M>) {}
    fn on_remove(&mut self, _context: &mut WidgetContext<C, M>) {}

    fn closable(&self) -> bool {
        true
    }

    fn required_camera(&self, _cached_cameras: &[Entity]) -> Option<Entity> {
        None
    }

    fn catalog() -> Vec<WidgetEntry<Self>>
    where
        Self: Sized;
}

#[derive(Clone, serde::Serialize, serde::Deserialize)]
pub struct Pane<W> {
    pub widget: W,
}

impl<W> Pane<W> {
    pub fn new(widget: W) -> Self {
        Self { widget }
    }
}
