mod service_row;

use self::service_row::ServiceRow;
use crate::app::App;
use crate::main_window::MainWindow;
use glib::{Object, prelude::*, subclass::*};
use gtk4::{
    Accessible, Buildable, CompositeTemplate, ConstraintTarget, ListBox, ListBoxRow, Widget, subclass::prelude::*,
};
use libadwaita::{Bin, subclass::prelude::*};
use news_flash::NewsFlash;
use news_flash::models::{LoginData, LoginGUI, ServiceType};

mod imp {
    use super::*;

    #[derive(Debug, Default, CompositeTemplate)]
    #[template(file = "data/resources/ui_templates/login/welcome.blp")]
    pub struct WelcomePage {
        #[template_child]
        pub local_list: TemplateChild<ListBox>,
        #[template_child]
        pub service_list: TemplateChild<ListBox>,
    }

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

        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 WelcomePage {
        fn constructed(&self) {
            let services = NewsFlash::list_backends();

            for (_id, plugin_info) in services.into_iter() {
                let service_type = plugin_info.service_type.clone();
                let row = ServiceRow::new(plugin_info);

                if service_type == ServiceType::Local {
                    self.local_list.append(&row);
                } else {
                    self.service_list.append(&row);
                }
            }

            self.parent_constructed();
        }
    }

    impl WidgetImpl for WelcomePage {}

    impl BinImpl for WelcomePage {}

    #[gtk4::template_callbacks]
    impl WelcomePage {
        #[template_callback]
        async fn on_row_activated(&self, row: &ListBoxRow) {
            let Some(service_row) = row.downcast_ref::<ServiceRow>() else {
                return;
            };

            let plugin_id = service_row.plugin_id();
            let services = NewsFlash::list_backends();
            let Some(plugin_info) = services.get(plugin_id.as_ref()) else {
                return;
            };

            match plugin_info.login_gui {
                LoginGUI::OAuth(_) | LoginGUI::Direct(_) => {
                    MainWindow::instance().show_login_page(plugin_id.as_ref(), None)
                }
                LoginGUI::None => {
                    App::login(LoginData::None(plugin_id.into())).await;
                }
            }
        }
    }
}

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

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