use crate::prelude::*;

glib::wrapper! {
    /// Message indicators, currently including the message timestamp.
    pub struct MessageIndicators(ObjectSubclass<imp::MessageIndicators>)
        @extends gtk::Widget,
        @implements gtk::Accessible, gtk::Buildable, gtk::ConstraintTarget;
}

impl MessageIndicators {
    pub fn new(timestamp: String) -> Self {
        log::trace!("Initializing `MessageIndicators`");
        Object::builder::<Self>()
            .property("timestamp", timestamp)
            .build()
    }
}

mod imp {
    use crate::prelude::*;
    use gtk::CompositeTemplate;

    #[derive(Default, CompositeTemplate, glib::Properties)]
    #[properties(wrapper_type = super::MessageIndicators)]
    #[template(resource = "/ui/components/indicators.ui")]
    pub struct MessageIndicators {
        #[template_child]
        sending_state_icon: TemplateChild<gtk::Button>,
        #[property(get, set)]
        pub(super) timestamp: RefCell<String>,
        #[property(get, set)]
        pub(super) edited: Cell<bool>,
        #[property(get, set)]
        pub(super) has_delivery_receipt: Cell<bool>,
        #[property(get, set)]
        pub(super) has_read_receipt: Cell<bool>,
        #[property(get, set)]
        pub(super) pending: Cell<bool>,
        #[property(get, set)]
        pub(super) error: Cell<bool>,
        #[property(get, set)]
        pub(super) show_sending_state: Cell<bool>,
    }

    #[gtk::template_callbacks]
    impl MessageIndicators {
        #[template_callback]
        pub fn handle_edited_clicked(&self) {
            let obj = self.obj();
            obj.emit_by_name::<()>("edited-clicked", &[]);
        }

        #[template_callback]
        pub fn handle_sending_state_clicked(&self) {
            let obj = self.obj();
            obj.emit_by_name::<()>("sending-state-clicked", &[]);
        }

        fn recompute_send_icon(&self) {
            let obj = self.obj();
            let (icon, color, tooltip) = if obj.error() {
                (
                    "dialog-error-symbolic",
                    false,
                    gettextrs::gettext("Error sending message"),
                )
            } else if obj.pending() {
                (
                    "message-pending-symbolic",
                    false,
                    gettextrs::gettext("Message pending"),
                )
            } else if obj.has_read_receipt() {
                (
                    "message-delivered-symbolic",
                    true,
                    gettextrs::gettext("Message read"),
                )
            } else if obj.has_delivery_receipt() {
                (
                    "message-delivered-symbolic",
                    false,
                    gettextrs::gettext("Message delivered"),
                )
            } else {
                (
                    "message-sent-symbolic",
                    false,
                    gettextrs::gettext("Message sent"),
                )
            };

            self.sending_state_icon.set_icon_name(icon);
            self.sending_state_icon.set_tooltip_text(Some(&tooltip));
            if color {
                self.sending_state_icon
                    .add_css_class("message-indicator-read");
            } else {
                self.sending_state_icon
                    .remove_css_class("message-indicator-read");
            }
        }
    }

    #[glib::object_subclass]
    impl ObjectSubclass for MessageIndicators {
        const NAME: &'static str = "FlMessageIndicators";
        type Type = super::MessageIndicators;
        type ParentType = gtk::Widget;

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

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

    #[glib::derived_properties]
    impl ObjectImpl for MessageIndicators {
        fn constructed(&self) {
            self.parent_constructed();

            self.obj().connect_notify_local(None, move |s, _| {
                s.imp().recompute_send_icon();
            });
            self.recompute_send_icon();
        }

        fn signals() -> &'static [Signal] {
            static SIGNALS: Lazy<Vec<Signal>> = Lazy::new(|| -> Vec<Signal> {
                vec![
                    Signal::builder("edited-clicked").build(),
                    Signal::builder("sending-state-clicked").build(),
                ]
            });
            SIGNALS.as_ref()
        }

        fn dispose(&self) {
            let mut child = self.obj().first_child();
            while let Some(child_) = child {
                child = child_.next_sibling();
                child_.unparent();
            }
        }
    }

    impl WidgetImpl for MessageIndicators {}
}
