use crate::gobject_models::GPluginID;
use crate::main_window::MainWindow;
use glib::{Object, Properties, prelude::*, subclass::*};
use gtk4::{Accessible, Box, Buildable, CompositeTemplate, ConstraintTarget, Widget, subclass::prelude::*};
use news_flash::NewsFlash;
use news_flash::models::{ApiSecret, PluginID, Url};
use std::cell::{Cell, RefCell};

mod imp {
    use super::*;

    #[derive(Debug, Default, CompositeTemplate, Properties)]
    #[properties(wrapper_type = super::CustomApiSecret)]
    #[template(file = "data/resources/ui_templates/login/custom_api_secret.blp")]
    pub struct CustomApiSecret {
        #[property(get, set, name = "info-text")]
        pub info_text: RefCell<String>,

        #[property(get, set, name = "client-id")]
        pub client_id: RefCell<String>,

        #[property(get, set, name = "client-secret")]
        pub client_secret: RefCell<String>,

        #[property(get, set, name = "plugin-id")]
        pub plugin_id: RefCell<GPluginID>,

        #[property(get, set, name = "can-submit")]
        pub can_submit: Cell<bool>,
    }

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

        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 CustomApiSecret {
        fn constructed(&self) {
            let obj = self.obj();

            obj.connect_client_id_notify(super::CustomApiSecret::update_can_submit);
            obj.connect_client_secret_notify(super::CustomApiSecret::update_can_submit);

            self.parent_constructed();
        }
    }

    impl WidgetImpl for CustomApiSecret {}

    impl BoxImpl for CustomApiSecret {}

    #[gtk4::template_callbacks]
    impl CustomApiSecret {
        #[template_callback]
        fn on_submit(&self) {
            let plugin_id = self.plugin_id.borrow().clone();
            let Some(plugin_info) = NewsFlash::list_backends().remove(plugin_id.as_ref()) else {
                return;
            };
            let secret = if self.client_id.borrow().is_empty() || self.client_secret.borrow().is_empty() {
                None
            } else {
                Some(ApiSecret {
                    client_id: self.client_id.borrow().clone(),
                    client_secret: self.client_secret.borrow().clone(),
                })
            };
            MainWindow::instance().show_web_login_page(plugin_info, secret.as_ref());
        }

        #[template_callback]
        fn on_ignore(&self) {
            let plugin_id = self.plugin_id.borrow().clone();
            let Some(plugin_info) = NewsFlash::list_backends().remove(plugin_id.as_ref()) else {
                return;
            };
            MainWindow::instance().show_web_login_page(plugin_info, None);
        }
    }
}

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

impl Default for CustomApiSecret {
    fn default() -> Self {
        Object::new::<Self>()
    }
}

impl CustomApiSecret {
    pub fn fill(&self, secret: ApiSecret) {
        self.set_client_id(secret.client_id);
        self.set_client_secret(secret.client_secret);
    }

    pub fn set_service(&self, plugin_id: PluginID, create_secret_url: Option<Url>) {
        let plugin_id: GPluginID = plugin_id.into();
        self.set_plugin_id(plugin_id);

        if let Some(url) = create_secret_url {
            self.set_info_text(format!(
                r#"This service uses API secrets to limit the amount of actions per day for every user of the app. You can generate your own secrets <a href="{}">here</a>. This way you don't have to share the limited amount of actions with other users of Newsflash."#,
                url.as_str()
            ));
        }
    }

    pub fn reset(&self) {
        self.set_client_id("");
        self.set_client_secret("");
    }

    fn update_can_submit(&self) {
        let have_client_id = !self.client_id().is_empty();
        let have_client_secret = !self.client_secret().is_empty();

        self.set_can_submit(have_client_id && have_client_secret);
    }
}
