use crate::add_dialog::g_parsed_url::GParsedUrl;
use crate::add_dialog::{
    add_error_widget::AddErrorWidget, add_feed_widget::AddFeedWidget, parse_feed_widget::ParseFeedWidget,
    select_feed_widget::SelectFeedWidget,
};
use crate::gobject_models::GFeed;
use glib::{Object, subclass::*};
use gtk4::{Accessible, Buildable, CompositeTemplate, ConstraintTarget, Widget, subclass::prelude::*};
use libadwaita::{Dialog, NavigationView, prelude::*, subclass::prelude::*};
use news_flash::ParsedUrl;

mod imp {
    use super::*;

    #[derive(Debug, Default, CompositeTemplate)]
    #[template(file = "data/resources/ui_templates/add_dialog/feed.blp")]
    pub struct AddFeedDialog {
        #[template_child]
        pub navigation_view: TemplateChild<NavigationView>,

        #[template_child]
        pub parse_feed_widget: TemplateChild<ParseFeedWidget>,
        #[template_child]
        pub select_feed_widget: TemplateChild<SelectFeedWidget>,
        #[template_child]
        pub add_feed_widget: TemplateChild<AddFeedWidget>,
        #[template_child]
        pub error_widget: TemplateChild<AddErrorWidget>,
    }

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

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

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

    impl ObjectImpl for AddFeedDialog {
        fn constructed(&self) {
            self.navigation_view.replace_with_tags(&["feed_parse_page"]);
            self.parent_constructed();
        }
    }

    impl WidgetImpl for AddFeedDialog {}

    impl AdwDialogImpl for AddFeedDialog {}

    #[gtk4::template_callbacks]
    impl AddFeedDialog {
        #[template_callback]
        fn on_feed_parsed(&self, parsed_url: GParsedUrl) {
            let parsed_url: ParsedUrl = parsed_url.into();

            match parsed_url {
                ParsedUrl::SingleFeed(feed) => {
                    self.add_feed_widget.set_feed(GFeed::from(*feed));
                    self.navigation_view.push_by_tag("feed_add_page");
                }
                ParsedUrl::MultipleFeeds(feed_vec) => {
                    self.select_feed_widget.fill(feed_vec);
                    self.navigation_view.push_by_tag("feed_selection_page");
                }
            }
        }

        #[template_callback]
        fn on_feed_selected(&self, feed: GFeed) {
            self.add_feed_widget.reset();
            self.add_feed_widget.set_feed(feed);
            self.navigation_view.push_by_tag("feed_add_page");
        }

        #[template_callback]
        fn on_feed_added(&self) {
            self.obj().close();
        }

        #[template_callback]
        fn on_error(&self, error_msg: String) {
            self.error_widget.set_error(error_msg);
            self.navigation_view.push_by_tag("error_page");
        }

        #[template_callback]
        fn on_try_again(&self) {
            self.navigation_view.pop_to_tag("feed_parse_page");
        }
    }
}

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

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

impl AddFeedDialog {
    pub async fn parse_url_str(&self, url: &str) {
        self.imp().parse_feed_widget.parse_url_str(url).await;
    }
}
