use std::sync::{Arc, Mutex};

use assets::Assets;
use gpui::{
    App, AppContext, Bounds, KeyBinding, Menu, MenuItem, SharedString, TitlebarOptions,
    WindowBackgroundAppearance, WindowBounds, WindowDecorations, WindowKind, WindowOptions,
    actions, point, px, size,
};
use gpui_platform::application;
use state::{APP_ID, CLIENT_NAME};
use ui::Root;

mod dialogs;
mod panels;
mod sidebar;
mod workspace;

actions!(coop, [Quit]);

fn main() {
    // Initialize logging
    tracing_subscriber::fmt::init();

    // Run application
    application()
        .with_assets(Assets)
        .with_http_client(Arc::new(reqwest_client::ReqwestClient::new()))
        .run(move |cx| {
            // Load embedded fonts in assets/fonts
            load_embedded_fonts(cx);

            // Register the `quit` function
            cx.on_action(quit);

            // Register the `quit` function with CMD+Q (macOS)
            #[cfg(target_os = "macos")]
            cx.bind_keys([KeyBinding::new("cmd-q", Quit, None)]);

            // Register the `quit` function with Super+Q (others)
            #[cfg(not(target_os = "macos"))]
            cx.bind_keys([KeyBinding::new("super-q", Quit, None)]);

            // Set menu items
            cx.set_menus(vec![Menu {
                name: "Coop".into(),
                items: vec![MenuItem::action("Quit", Quit)],
                disabled: false,
            }]);

            // Set up the window bounds
            let bounds = Bounds::centered(None, size(px(920.0), px(700.0)), cx);

            // Set up the window options
            let opts = WindowOptions {
                window_background: WindowBackgroundAppearance::Opaque,
                window_decorations: Some(WindowDecorations::Client),
                window_bounds: Some(WindowBounds::Windowed(bounds)),
                kind: WindowKind::Normal,
                app_id: Some(APP_ID.to_owned()),
                titlebar: Some(TitlebarOptions {
                    title: Some(SharedString::new_static(CLIENT_NAME)),
                    traffic_light_position: Some(point(px(9.0), px(9.0))),
                    appears_transparent: true,
                }),
                ..Default::default()
            };

            // Open a window with default options
            cx.open_window(opts, |window, cx| {
                // Bring the app to the foreground
                cx.activate(true);

                cx.new(|cx| {
                    // Initialize the tokio runtime
                    gpui_tokio::init(cx);

                    // Initialize components
                    ui::init(cx);

                    // Initialize theme registry
                    theme::init(cx);

                    // Initialize settings
                    settings::init(window, cx);

                    // Initialize the nostr client
                    state::init(window, cx);

                    // Initialize person registry
                    person::init(window, cx);

                    // Initialize relay auth registry
                    relay_auth::init(window, cx);

                    // Initialize device signer
                    //
                    // NIP-4e: https://github.com/nostr-protocol/nips/blob/per-device-keys/4e.md
                    device::init(window, cx);

                    // Initialize app registry
                    chat::init(window, cx);

                    // Initialize auto update
                    auto_update::init(window, cx);

                    // Root Entity
                    Root::new(workspace::init(window, cx).into(), window, cx)
                })
            })
            .expect("Failed to open window. Please restart the application.");
        });
}

fn load_embedded_fonts(cx: &App) {
    let asset_source = cx.asset_source();
    let font_paths = asset_source.list("fonts").unwrap();
    let embedded_fonts = Mutex::new(vec![]);
    let executor = cx.background_executor();

    cx.foreground_executor().block_on(executor.scoped(|scope| {
        for font_path in &font_paths {
            if !font_path.ends_with(".ttf") {
                continue;
            }

            scope.spawn(async {
                let font_bytes = asset_source.load(font_path.as_str()).unwrap().unwrap();
                embedded_fonts.lock().unwrap().push(font_bytes);
            });
        }
    }));

    cx.text_system()
        .add_fonts(embedded_fonts.into_inner().unwrap())
        .unwrap();
}

fn quit(_ev: &Quit, cx: &mut App) {
    log::info!("Gracefully quitting the application . . .");
    cx.quit();
}
