use crate::color::ColorRGBA;
use crate::gobject_models::GTagID;
use crate::main_window::MainWindow;
use crate::util::constants;
use gdk4::RGBA;
use glib::{Binding, Object, Properties, prelude::*, subclass::*};
use gtk4::{
    Accessible, Buildable, ColorDialogButton, CompositeTemplate, ConstraintTarget, Widget, subclass::prelude::*,
};
use libadwaita::{Dialog, subclass::prelude::*};
use news_flash::models::Tag;
use std::cell::RefCell;

mod imp {
    use super::*;

    #[derive(Debug, Default, CompositeTemplate, Properties)]
    #[properties(wrapper_type = super::EditTagDialog)]
    #[template(file = "data/resources/ui_templates/edit_dialogs/tag.blp")]
    pub struct EditTagDialog {
        #[template_child]
        pub color_button: TemplateChild<ColorDialogButton>,

        #[property(get, set, name = "tag-id")]
        pub tag_id: RefCell<GTagID>,

        #[property(get, set, name = "tag-name")]
        pub tag_name: RefCell<String>,

        #[property(get, set, name = "color-string")]
        pub color_string: RefCell<String>,
    }

    #[glib::object_subclass]
    impl ObjectSubclass for EditTagDialog {
        const NAME: &'static str = "EditTagDialog";
        type Type = super::EditTagDialog;
        type ParentType = Dialog;

        fn class_init(klass: &mut Self::Class) {
            klass.bind_template();
            klass.bind_template_callbacks();
        }

        fn instance_init(obj: &InitializingObject<Self>) {
            obj.init_template();
        }
    }

    #[glib::derived_properties]
    impl ObjectImpl for EditTagDialog {
        fn constructed(&self) {
            self.color_button
                .bind_property("rgba", &*self.obj(), "color-string")
                .transform_to(Self::rgba_to_string)
                .transform_from(Self::string_to_rgba)
                .sync_create()
                .bidirectional()
                .build();

            self.obj().connect_color_string_notify(move |dialog| {
                let tag_id = dialog.tag_id().as_ref().as_str().to_string();
                let new_title = dialog.tag_name();
                let color = dialog.color_string();
                MainWindow::activate_action("edit-tag", Some(&(tag_id, new_title, color).to_variant()));
            });

            self.parent_constructed();
        }
    }

    impl WidgetImpl for EditTagDialog {}

    impl AdwDialogImpl for EditTagDialog {}

    #[gtk4::template_callbacks]
    impl EditTagDialog {
        #[template_callback]
        fn on_name_apply(&self) {
            let tag_id = self.tag_id.borrow().as_ref().as_str().to_string();
            let new_title = self.tag_name.borrow().clone();
            let color = self.color_string.borrow().clone();

            MainWindow::activate_action("edit-tag", Some(&(tag_id, new_title, color).to_variant()));
        }

        fn rgba_to_string(_binding: &Binding, rgba: RGBA) -> Option<String> {
            let color = ColorRGBA::from_normalized(
                rgba.red() as f64,
                rgba.green() as f64,
                rgba.blue() as f64,
                rgba.alpha() as f64,
            );
            Some(color.as_string_no_alpha())
        }

        fn string_to_rgba(_binding: &Binding, color: String) -> Option<RGBA> {
            ColorRGBA::parse_string(&color).ok().map(|rgba| {
                RGBA::new(
                    rgba.red_normalized() as f32,
                    rgba.green_normalized() as f32,
                    rgba.blue_normalized() as f32,
                    rgba.alpha_normalized() as f32,
                )
            })
        }
    }
}

glib::wrapper! {
    pub struct EditTagDialog(ObjectSubclass<imp::EditTagDialog>)
        @extends Widget, Dialog,
        @implements Accessible, Buildable, ConstraintTarget;
}

impl EditTagDialog {
    pub fn new(tag: Tag) -> Self {
        let color_str = tag.color.as_deref().unwrap_or(constants::TAG_DEFAULT_COLOR);
        let tag_id: GTagID = tag.tag_id.into();

        Object::builder()
            .property("color-string", color_str.to_string())
            .property("tag-name", tag.label)
            .property("tag-id", tag_id)
            .build()
    }
}
