pub mod commands;
pub mod db;
pub mod downloader;
pub mod feed;
pub mod models;
pub mod net;
pub mod playlist_server;
pub mod resolve;
pub mod subscriptions;
pub mod takeout;
pub mod thumbs;
pub mod tray;

use tauri::menu::{AboutMetadata, Menu, PredefinedMenuItem, Submenu};
use tauri::Manager;

/// The macOS menu bar, minus Edit and Help.
///
/// Tauri's default adds both; neither has anything to offer here. Edit is kept
/// as a hidden-in-spirit necessity though — its Cut/Copy/Paste items are what
/// make those shortcuts work in the search field, so they live under the app
/// menu instead of their own top-level entry.
fn build_menu(app: &tauri::AppHandle) -> tauri::Result<Menu<tauri::Wry>> {
    let app_menu = Submenu::with_items(
        app,
        "FlightTube",
        true,
        &[
            &PredefinedMenuItem::about(app, None, Some(AboutMetadata::default()))?,
            &PredefinedMenuItem::separator(app)?,
            &PredefinedMenuItem::hide(app, None)?,
            &PredefinedMenuItem::hide_others(app, None)?,
            &PredefinedMenuItem::show_all(app, None)?,
            &PredefinedMenuItem::separator(app)?,
            // Keeps ⌘X/⌘C/⌘V working in text fields without an Edit menu.
            &PredefinedMenuItem::cut(app, None)?,
            &PredefinedMenuItem::copy(app, None)?,
            &PredefinedMenuItem::paste(app, None)?,
            &PredefinedMenuItem::select_all(app, None)?,
            &PredefinedMenuItem::separator(app)?,
            &PredefinedMenuItem::quit(app, None)?,
        ],
    )?;

    let window_menu = Submenu::with_items(
        app,
        "Window",
        true,
        &[
            &PredefinedMenuItem::minimize(app, None)?,
            &PredefinedMenuItem::maximize(app, None)?,
            &PredefinedMenuItem::separator(app)?,
            &PredefinedMenuItem::close_window(app, None)?,
        ],
    )?;

    Menu::with_items(app, &[&app_menu, &window_menu])
}

/// Turns on WKWebView's element fullscreen.
///
/// It is off by default in a Tauri window, which is why the native player has
/// no full-screen button and why `requestFullscreen()` — and the right-click
/// "Enter Full Screen" item — silently do nothing. Flipping this one preference
/// puts the button back in the video's own transport bar, where it belongs.
#[cfg(target_os = "macos")]
fn enable_element_fullscreen(window: &tauri::WebviewWindow) {
    use objc2_web_kit::WKWebView;
    let _ = window.with_webview(|platform| unsafe {
        let ptr = platform.inner() as *const WKWebView;
        if ptr.is_null() {
            return;
        }
        let webview: &WKWebView = &*ptr;
        webview
            .configuration()
            .preferences()
            .setElementFullscreenEnabled(true);
    });
}

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
    tauri::Builder::default()
        .menu(build_menu)
        .plugin(tauri_plugin_opener::init())
        .plugin(tauri_plugin_dialog::init())
        .plugin(tauri_plugin_notification::init())
        .setup(|app| {
            let state = commands::build_state(&app.handle().clone())?;
            app.manage(state);

            #[cfg(target_os = "macos")]
            if let Some(window) = app.get_webview_window("main") {
                enable_element_fullscreen(&window);
            }

            // The menu bar item, so a video playing in a browser can be saved
            // without coming back to the window.
            tray::build(&app.handle().clone())?;

            // The bundled yt-dlp takes seconds to start, so pay that once in
            // the background rather than the first time Settings is opened.
            let handle = app.handle().clone();
            tauri::async_runtime::spawn(async move {
                let state = handle.state::<commands::AppState>();
                let _ = commands::check_prereqs(state).await;
            });

            Ok(())
        })
        .invoke_handler(tauri::generate_handler![
            commands::check_prereqs,
            commands::import_takeout_csv,
            commands::preview_takeout_import,
            commands::list_channels,
            commands::list_feed,
            commands::resolve_stream,
            commands::save_playback,
            commands::refresh_feeds,
            commands::download_video,
            commands::cancel_download,
            commands::cancel_all_downloads,
            commands::interrupted_downloads,
            commands::delete_download,
            commands::delete_all_downloads,
            commands::list_subtitles,
            commands::fetch_subtitles,
            commands::embedded_subtitles,
            commands::fetch_durations,
            commands::list_browsers,
            commands::set_cookie_source,
            commands::test_youtube,
            commands::check_yt_dlp_update,
            commands::update_yt_dlp,
            commands::get_connectivity,
            commands::set_library_path,
            commands::open_external,
            commands::add_channel,
            commands::scrape_subscriptions,
            tray::tray_save_video,
            tray::show_main_window,
            tray::hide_panel,
            tray::quit_app,
            commands::preview_scraped_import,
            commands::import_scraped,
            commands::preview_remove_all_subscriptions,
            commands::remove_all_subscriptions,
            commands::delete_channel,
            commands::preview_delete_channel,
            commands::set_download_defaults,
        ])
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}
