use crate::app::App;
use crate::gobject_models::GCategoryID;
use crate::main_window::MainWindow;
use glib::{Object, Properties, prelude::*, subclass::*};
use gtk4::{Accessible, Buildable, CompositeTemplate, ConstraintTarget, Widget, subclass::prelude::*};
use libadwaita::{Dialog, subclass::prelude::*};
use news_flash::models::Category;
use std::cell::{Cell, RefCell};

mod imp {
    use super::*;
    #[derive(Debug, Default, CompositeTemplate, Properties)]
    #[properties(wrapper_type = super::EditCategoryDialog)]
    #[template(file = "data/resources/ui_templates/edit_dialogs/category.blp")]
    pub struct EditCategoryDialog {
        #[property(get, set, name = "category-id")]
        pub category_id: RefCell<GCategoryID>,

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

        #[property(get, set, name = "math-delimiter")]
        pub math_delimiter: RefCell<String>,

        #[property(get, set, name = "user-agent")]
        pub user_agent: RefCell<String>,

        #[property(get, set = Self::set_scrape_content, name = "scrape-content")]
        pub scrape_content: Cell<bool>,

        #[property(get, set = Self::set_mute)]
        pub mute: Cell<bool>,
    }

    #[glib::object_subclass]
    impl ObjectSubclass for EditCategoryDialog {
        const NAME: &'static str = "EditCategoryDialog";
        type Type = super::EditCategoryDialog;
        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 EditCategoryDialog {}

    impl WidgetImpl for EditCategoryDialog {}

    impl AdwDialogImpl for EditCategoryDialog {}

    #[gtk4::template_callbacks]
    impl EditCategoryDialog {
        #[template_callback]
        fn on_name_apply(&self) {
            let category_id = self.category_id.borrow().as_ref().as_str().to_string();
            let new_title = self.category_name.borrow().clone();
            MainWindow::activate_action("rename-category", Some(&(category_id, new_title).to_variant()));
        }

        #[template_callback]
        fn on_math_delimiter_apply(&self) {
            let category_id = self.category_id.borrow().clone();
            let math_delimiter = self.math_delimiter.borrow().clone();
            let mut category_settings = App::default()
                .settings()
                .get_category_settings(category_id.as_ref())
                .unwrap_or_default();

            if math_delimiter.is_empty() {
                category_settings.inline_math = None;
            } else {
                category_settings.inline_math = Some(math_delimiter);
            }

            _ = App::default()
                .settings()
                .set_category_settings(category_id.as_ref(), &category_settings);
        }

        #[template_callback]
        fn on_user_agent_apply(&self) {
            let category_id = self.category_id.borrow().clone();
            let user_agent = self.user_agent.borrow().clone();
            let mut category_settings = App::default()
                .settings()
                .get_category_settings(category_id.as_ref())
                .unwrap_or_default();

            if user_agent.is_empty() {
                category_settings.custom_user_agent = None;
            } else {
                category_settings.custom_user_agent = Some(user_agent);
            }

            _ = App::default()
                .settings()
                .set_category_settings(category_id.as_ref(), &category_settings);
        }

        fn set_scrape_content(&self, scrape_content: bool) {
            if scrape_content == self.scrape_content.get() {
                return;
            }

            let category_id = self.category_id.borrow().clone();
            let mut category_settings = App::default()
                .settings()
                .get_category_settings(category_id.as_ref())
                .unwrap_or_default();

            category_settings.scrap_content = scrape_content;

            _ = App::default()
                .settings()
                .set_category_settings(category_id.as_ref(), &category_settings);

            self.scrape_content.set(scrape_content);
        }

        fn set_mute(&self, mute: bool) {
            if mute == self.mute.get() {
                return;
            }

            let category_id = self.category_id.borrow().clone();
            let mut category_settings = App::default()
                .settings()
                .get_category_settings(category_id.as_ref())
                .unwrap_or_default();

            category_settings.mute_notifications = mute;

            _ = App::default()
                .settings()
                .set_category_settings(category_id.as_ref(), &category_settings);

            self.mute.set(mute);
        }
    }
}

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

impl EditCategoryDialog {
    pub fn new(category: Category) -> Self {
        let category_settings = App::default()
            .settings()
            .get_category_settings(&category.category_id)
            .unwrap_or_default();
        let math_delimiter = category_settings.inline_math.as_deref().unwrap_or("");
        let user_agent = category_settings.custom_user_agent.as_deref().unwrap_or("");

        let category_id: GCategoryID = category.category_id.into();

        Object::builder()
            .property("category-id", category_id)
            .property("category-name", &category.label)
            .property("math-delimiter", math_delimiter)
            .property("user-agent", user_agent)
            .property("scrape-content", category_settings.scrap_content)
            .property("mute", category_settings.mute_notifications)
            .build()
    }
}
