use adw::prelude::*;
use kifu_core::{CoreApp, CoreRequest, CoreResponse};
use kifu_gtk::{
    perftrace,
    ui::{AppWindow, ConfigurationPage, Home, PlayingField},
    CoreApi,
};
use std::sync::{Arc, RwLock};

fn handle_response(api: CoreApi, app_window: &AppWindow, message: CoreResponse) {
    let playing_field = Arc::new(RwLock::new(None));
    match message {
        CoreResponse::ConfigurationView(view) => perftrace("ConfigurationView", || {
            let config_page = ConfigurationPage::new(api, view);

            let window = adw::PreferencesWindow::new();
            window.add(&config_page);
            window.set_visible_page(&config_page);
            window.present();
        }),
        CoreResponse::HomeView(view) => perftrace("HomeView", || {
            let api = api.clone();

            let home = Home::new(api, view);
            app_window.set_content(&home);
        }),
        CoreResponse::PlayingFieldView(view) => perftrace("PlayingFieldView", || {
            let api = api.clone();

            let mut playing_field = playing_field.write().unwrap();
            if playing_field.is_none() {
                perftrace("creating a new playing field", || {
                    let field = PlayingField::new(api, view);
                    app_window.set_content(&field);
                    *playing_field = Some(field);
                })
            } else if let Some(field) = playing_field.as_ref() {
                field.update_view(view)
            }
        }),
        CoreResponse::UpdatedConfigurationView(view) => perftrace("UpdatedConfiguration", || {
            println!("updated configuration: {:?}", view);
        }),
    }
}

fn main() {
    gio::resources_register_include!("com.luminescent-dreams.kifu-gtk.gresource")
        .expect("Failed to register resources");

    let runtime = Arc::new(
        tokio::runtime::Builder::new_multi_thread()
            .enable_all()
            .build()
            .unwrap(),
    );

    let config_path = std::env::var("CONFIG")
        .map(std::path::PathBuf::from)
        .or({
            std::env::var("HOME").map(|base| {
                let mut config_path = std::path::PathBuf::from(base);
                config_path.push(".config");
                config_path.push("kifu");
                config_path
            })
        })
        .expect("no config path could be found");

    let core = CoreApp::new(config_path);

    let core_handle = runtime.spawn({
        let core = core.clone();
        async move {
            core.run().await;
        }
    });

    let app = adw::Application::builder()
        .application_id("com.luminescent-dreams.kifu-gtk")
        .resource_base_path("/com/luminescent-dreams/kifu-gtk")
        .build();

    app.connect_activate({
        let runtime = runtime.clone();
        move |app| {
            let (gtk_tx, gtk_rx) =
                gtk::glib::MainContext::channel::<CoreResponse>(gtk::glib::Priority::DEFAULT);

            let app_window = AppWindow::new(app);

            let api = CoreApi {
                gtk_tx,
                rt: runtime.clone(),
                core: core.clone(),
            };

            let action_config = gio::SimpleAction::new("show-config", None);
            action_config.connect_activate({
                let api = api.clone();
                move |_, _| {
                    api.dispatch(CoreRequest::OpenConfiguration);
                }
            });
            app.add_action(&action_config);

            app_window.window.present();

            gtk_rx.attach(None, {
                let api = api.clone();
                move |message| {
                    perftrace("handle_response", || {
                        handle_response(api.clone(), &app_window, message)
                    });
                    glib::ControlFlow::Continue
                }
            });

            api.dispatch(CoreRequest::Home);
        }
    });

    println!("running the gtk loop");
    app.run();

    let _ = runtime.block_on(core_handle);
}
