use glib::clone;
use gtk::prelude::WidgetExt;
use gtk::prelude::*;
use relm4::{
    binding::{Binding, U8Binding},
    factory::{DynamicIndex, FactoryComponent, FactorySender, FactoryVecDeque},
    prelude::*,
    typed_list_view::{RelmListItem, TypedListView},
    RelmObjectExt,
};

use crate::{
    chart::Chart,
    data::Npz,
    render::{predefined::color_mapper::BoundaryNorm, Layer},
};

use super::bottom_bar::BottomBarModel;
pub struct SideBarModel {
    counter: u8,
    list_view_wrapper: TypedListView<LayerItem, gtk::SingleSelection>,
    bottom_bar_vec: FactoryVecDeque<BottomBarModel>,
}

#[derive(Debug)]
pub enum Msg {
    RefreshList(Vec<Layer>),
    None
}

#[derive(Debug)]
pub enum SideBarOutputMsg {
    NewLayer(Layer),
}

#[relm4::component(pub)]
impl SimpleComponent for SideBarModel {
    type Init = ();
    type Output = SideBarOutputMsg;
    type Input = Msg;

    view! {
        gtk::Box {
        set_orientation: gtk::Orientation::Vertical,
            set_spacing: 5,
            set_margin_all: 5,

            gtk::Paned{
                set_orientation: gtk::Orientation::Vertical,
                set_position: 300,
                #[wrap(Some)]
                set_start_child = &gtk::Box{
                    set_orientation: gtk::Orientation::Vertical,
                    set_spacing: 5,
                    gtk::Frame{
                        add_css_class: "rb",
                        #[local]
                        top_panel -> gtk::Notebook{}
                    },
                    gtk::Button {
                        set_label: "Add Layers",
                        connect_clicked[sender] => move |_| {
                        },
                    },
                    gtk::Button {
                        set_label: "Add Layer",
                        connect_clicked[sender] => move |_| {
                            sender.output(
                                SideBarOutputMsg::NewLayer(
                                    Layer::grid_render_layer_with_path(
                                        std::path::Path::new("./test2.npz"),
                                        "DBZ".to_string(),
                                        Npz,
                                        BoundaryNorm::default(),
                                    )
                                )
                            ).unwrap()
                        },
                    },
                },

                #[wrap(Some)]
                set_end_child=&gtk::Box{
                    set_orientation: gtk::Orientation::Vertical,
                    set_vexpand: true,
                    set_hexpand: true,
                    #[local]
                    bottom_panel -> gtk::Notebook{
                        set_margin_top: 10,
                        set_margin_bottom: 5,
                    },
                    #[local_ref]
                    counter_box -> gtk::Box{
                        set_spacing: 5,
                    }
                }
            },


        }
    }

    fn init(
        init: Self::Init,
        root: &Self::Root,
        sender: ComponentSender<Self>,
    ) -> ComponentParts<Self> {
        // Initialize the ListView wrapper
        let mut list_view_wrapper: TypedListView<LayerItem, gtk::SingleSelection> =
            TypedListView::with_sorting();

        let mut bottom_bar_vec = FactoryVecDeque::new(gtk::Box::default(), sender.input_sender());


        {
            let mut bottom_bar_vec_guard = bottom_bar_vec.guard();
            bottom_bar_vec_guard.push_back(BottomBarModel::new("add-filled".to_string()));
            bottom_bar_vec_guard.push_back(BottomBarModel::new("delete-filled".to_string()));
            bottom_bar_vec_guard.push_back(BottomBarModel::new("chevron-up-filled".to_string()));
            bottom_bar_vec_guard.push_back(BottomBarModel::new("chevron-down-filled".to_string()));
        }

        let model = SideBarModel {
            counter: 0,
            list_view_wrapper,
            bottom_bar_vec,
        };

        let my_view = &model.list_view_wrapper.view;
        let top_panel = gtk::Notebook::builder().vexpand(true).hexpand(true).build();
        top_panel.append_page(&Chart::new(), Some(&gtk::Label::new(Some("Chart"))));

        let bottom_panel = gtk::Notebook::builder().vexpand(true).build();
        let layer_page = gtk::ScrolledWindow::builder()
            .vexpand(true)
            .hexpand(true)
            .build();

        let counter_box = model.bottom_bar_vec.widget();

        layer_page.set_child(Some(my_view));
        layer_page.set_margin_horizontal(5);
        layer_page.set_margin_vertical(3);
        bottom_panel.append_page(&layer_page, Some(&gtk::Label::new(Some("Layers"))));

        let widgets = view_output!();
        ComponentParts { model, widgets }
    }

    fn update(&mut self, message: Self::Input, sender: ComponentSender<Self>) {
        match message {
            Msg::RefreshList(layers) => {
                for layer in layers {
                    self.list_view_wrapper
                        .append(LayerItem::new(layer.name, true));
                }
            }

            _ => {}
        }
    }
}

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
struct LayerItem {
    layer_name: String,
    visiable: bool,
}

impl LayerItem {
    fn new(name: String, visiable: bool) -> Self {
        Self {
            layer_name: name,
            visiable,
        }
    }
}

struct Widgets {
    label: gtk::Label,
    button: gtk::CheckButton,
}

impl Drop for Widgets {
    fn drop(&mut self) {
        dbg!(self.label.label());
    }
}

impl RelmListItem for LayerItem {
    type Root = gtk::Box;
    type Widgets = Widgets;

    fn setup(_item: &gtk::ListItem) -> (gtk::Box, Widgets) {
        relm4::view! {
            my_box = gtk::Box {
                #[name = "label"]
                gtk::Label{
                    set_halign: gtk::Align::Start,
                },
                gtk::Label{
                    set_hexpand: true,
                },
                #[name = "button"]
                gtk::CheckButton{
                    set_halign: gtk::Align::End,
                },
            }
        }

        let widgets = Widgets { label, button };

        (my_box, widgets)
    }

    fn bind(&mut self, widgets: &mut Self::Widgets, _root: &mut Self::Root) {
        let Widgets { label, button } = widgets;

        label.set_label(&format!("Layer: {} ", &self.layer_name));
        button.set_active(self.visiable);
    }
}
