use glib::clone;
use gtk::prelude::*;
use relm4::{
    binding::{Binding, U8Binding},
    prelude::*,
    typed_list_view::{RelmListItem, TypedListView},
    RelmObjectExt,
};

use crate::{chart::Chart, render::{Layer, predefined::color_mapper::BoundaryNorm}, data::Npz};
pub struct SideBarModel {
    counter: u8,
    list_view_wrapper: TypedListView<MyListItem, gtk::SingleSelection>,
}

#[derive(Debug)]
pub enum Msg {
    Append,
    Remove,
    OnlyShowEven(bool),
}

#[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::Notebook {
                        set_vexpand: true,
                        append_page:(&page_1, Some(&label)),
                    },
                    gtk::Button {
                        set_label: "Add Layer",
                        connect_clicked[sender] => move |_| {
                            sender.output(
                                SideBarOutputMsg::NewLayer(
                                    Layer::grid_render_layer_with_path(
                                        "/users/tsuki/projects/radar-g/test2.npz",
                                        Npz,
                                        BoundaryNorm::default(),
                                    )
                                )
                            ).unwrap()
                        },
                    },
                    gtk::ScrolledWindow {
                            set_vexpand: true,
                            #[local_ref]
                            my_view -> gtk::ListView {}
                    }
                }
            }

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

        // Add a filter and disable it
        list_view_wrapper.add_filter(|item| item.value % 2 == 0);
        list_view_wrapper.set_filter_status(0, false);

        let model = SideBarModel {
            counter: 0,
            list_view_wrapper,
        };
        let my_view = &model.list_view_wrapper.view;

        let page_1 = gtk::Box::builder()
            .orientation(gtk::Orientation::Vertical)
            .vexpand(true)
            .hexpand(true)
            .build();

        let chart = Chart::new();

        chart.connect_resize(clone!(@weak chart as my_view => move |_, w,h|{
            my_view.set_height_request((w as f32 / 16.0 * 3.0) as i32);
        }));

        page_1.append(&chart);
        let label = gtk::Label::new(Some("Page 1"));

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

    fn update(&mut self, message: Self::Input, sender: ComponentSender<Self>) {
        match message {
            Msg::Append => {
                // Add 10 items
                for _ in 0..10 {
                    self.counter = self.counter.wrapping_add(1);
                    self.list_view_wrapper.append(MyListItem::new(self.counter));
                }

                // Count up the first item
                let first_item = self.list_view_wrapper.get(0).unwrap();
                let first_binding = &mut first_item.borrow_mut().binding;
                let mut guard = first_binding.guard();
                *guard += 1;
            }
            Msg::Remove => {
                // Remove the second item
                self.list_view_wrapper.remove(1);
            }
            Msg::OnlyShowEven(show_only_even) => {
                // Disable or enable the first filter
                self.list_view_wrapper.set_filter_status(0, show_only_even);
            }
        }
    }
}

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
struct MyListItem {
    value: u8,
    binding: U8Binding,
}

impl MyListItem {
    fn new(value: u8) -> Self {
        Self {
            value,
            binding: U8Binding::new(0),
        }
    }
}

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

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

impl RelmListItem for MyListItem {
    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,

                #[name = "label2"]
                gtk::Label,

                #[name = "button"]
                gtk::CheckButton,
            }
        }

        let widgets = Widgets {
            label,
            label2,
            button,
        };

        (my_box, widgets)
    }

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

        label.set_label(&format!("Value: {} ", self.value));
        label2.add_write_only_binding(&self.binding, "label");
        button.set_active(self.value % 2 == 0);
    }
}
