use crate::prelude::*;

use ftypes::AccountId;

use super::Manager;

gtk::glib::wrapper! {
    /// A contact represents a user of Signal.
    pub struct Contact(ObjectSubclass<imp::Contact>);
}

impl Contact {
    pub(super) fn from_ftypes(inner: ftypes::Contact, manager: &Manager) -> Self {
        let s: Self = Object::builder::<Self>()
            .property("manager", manager)
            .build();
        s.imp().inner.borrow_mut().replace(inner);
        s
    }

    pub(super) fn set_ftypes(&self, inner: ftypes::Contact) {
        self.imp().inner.borrow_mut().replace(inner);

        for prop in self.list_properties() {
            self.notify(prop.name());
        }
    }

    pub fn inner(&self) -> ftypes::Contact {
        self.imp()
            .inner
            .borrow()
            .clone()
            .expect("Inner contact to be set")
    }

    pub fn is_blocked(&self) -> bool {
        // TODO: The blocked field got removed in https://github.com/whisperfish/libsignal-service-rs/pull/303
        false
    }

    pub fn account_id(&self) -> AccountId {
        self.inner().id.account_id
    }

    pub fn expire_timer(&self) -> u32 {
        match self.inner().disappearing_messages_timer {
            ftypes::Timer::Off => 0,
            ftypes::Timer::On(time_delta) => time_delta.num_seconds() as u32,
        }
    }

    pub fn phone_number(&self) -> Option<String> {
        self.inner().phone_number.map(|p| p.to_string())
    }
}

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

    use std::marker::PhantomData;

    use gdk::Paintable;

    use crate::backend::{Channel, Manager};

    #[derive(Default, glib::Properties)]
    #[properties(wrapper_type = super::Contact)]
    pub struct Contact {
        #[property(name = "title", type = String, get = |s: &Self| s.inner.borrow().as_ref().expect("Contact inner to be set").title().unwrap_or_else(|| gettextrs::gettext("Unknown Contact")))]
        #[property(name = "label", type = String, get = |s: &Self| s.inner.borrow().as_ref().expect("Contact inner to be set").group_member_data.as_ref().map(|m| m.label.to_string()).unwrap_or_default())]
        #[property(name = "has-label", type = bool, get = |s: &Self| !s.inner.borrow().as_ref().expect("Contact inner to be set").group_member_data.as_ref().map(|m| m.label.to_string()).unwrap_or_default().is_empty())]
        pub(super) inner: RefCell<Option<ftypes::Contact>>,

        #[property(get, set)]
        pub(crate) avatar: RefCell<Option<Paintable>>,

        #[property(get, set, construct_only, type = Manager)]
        manager: RefCell<Option<Manager>>,
        #[property(get, set, nullable)]
        channel: RefCell<Option<Channel>>,

        #[property(get = Self::is_self)]
        is_self: PhantomData<bool>,
    }

    impl Contact {
        fn is_self(&self) -> bool {
            self.obj().account_id() == self.manager.borrow().as_ref().unwrap().account_id()
        }
    }

    #[glib::object_subclass]
    impl ObjectSubclass for Contact {
        const NAME: &'static str = "FlContact";
        type Type = super::Contact;
    }

    #[glib::derived_properties]
    impl ObjectImpl for Contact {}
}
