#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]

use std::sync::Mutex;
use tauri::Manager;
use tutorialvault_lib::{commands, ffmpeg, fonts, library, prefs, video_protocol, AppPaths};

fn main() {
    // 1. Resolve exe directory for portability.
    let exe_dir = std::env::current_exe()
        .expect("cannot resolve exe path")
        .parent()
        .expect("exe has no parent")
        .to_path_buf();

    let state_dir = exe_dir.join("state");

    // 2. Create all subdirectories.
    let paths = AppPaths {
        exe_dir: exe_dir.clone(),
        state_dir: state_dir.clone(),
        fonts_dir: state_dir.join("fonts"),
        fa_dir: state_dir.join("fontawesome"),
        subs_dir: state_dir.join("subtitles"),
    };
    std::fs::create_dir_all(&paths.fonts_dir).ok();
    std::fs::create_dir_all(&paths.fa_dir.join("webfonts")).ok();
    std::fs::create_dir_all(&paths.subs_dir).ok();

    // 3. Set WebView2 user data folder for portability (no AppData usage).
    let webview_profile = state_dir.join("webview_profile");
    std::fs::create_dir_all(&webview_profile).ok();
    unsafe {
        std::env::set_var("WEBVIEW2_USER_DATA_FOLDER", &webview_profile);
    }

    // 4. Load preferences.
    let prefs_data = prefs::Prefs::load(&state_dir);

    // 5. Initialize library (empty — loaded from last folder or frontend action).
    let mut lib = library::Library::new();

    // Discover ffmpeg/ffprobe.
    let ff_paths = ffmpeg::discover(&paths.exe_dir, &paths.state_dir);
    let needs_ffmpeg_download = ff_paths.ffprobe.is_none() || ff_paths.ffmpeg.is_none();
    lib.ffprobe = ff_paths.ffprobe;
    lib.ffmpeg = ff_paths.ffmpeg;

    // Restore last folder if it exists.
    if let Some(ref last_path) = prefs_data.last_folder_path {
        if std::path::Path::new(last_path).is_dir() {
            let _ = lib.set_root(last_path, &state_dir);
        }
    }

    // 6. Build Tauri app.
    let builder = tauri::Builder::default()
        .plugin(tauri_plugin_dialog::init())
        .manage(Mutex::new(lib))
        .manage(Mutex::new(prefs_data))
        .manage(paths)
        .invoke_handler(tauri::generate_handler![
            commands::select_folder,
            commands::open_folder_path,
            commands::get_recents,
            commands::remove_recent,
            commands::get_library,
            commands::set_current,
            commands::tick_progress,
            commands::set_folder_volume,
            commands::set_folder_autoplay,
            commands::set_folder_rate,
            commands::set_order,
            commands::start_duration_scan,
            commands::get_prefs,
            commands::set_prefs,
            commands::set_always_on_top,
            commands::save_window_state,
            commands::get_note,
            commands::set_note,
            commands::get_current_video_meta,
            commands::get_current_subtitle,
            commands::get_embedded_subtitles,
            commands::extract_embedded_subtitle,
            commands::get_available_subtitles,
            commands::load_sidecar_subtitle,
            commands::choose_subtitle_file,
            commands::reset_watch_progress,
        ]);

    // Register custom protocol for video/subtitle/font serving.
    let builder = video_protocol::register_protocol(builder);

    // Configure window from saved prefs and launch.
    builder
        .setup(move |app| {
            let prefs_state = app.state::<Mutex<prefs::Prefs>>();
            let p = prefs_state.lock().unwrap();
            let win = app.get_webview_window("main").unwrap();

            // Only restore position/size if values are sane (not minimized/offscreen).
            let w = p.window.width.max(640) as u32;
            let h = p.window.height.max(480) as u32;
            if let (Some(x), Some(y)) = (p.window.x, p.window.y) {
                if x > -10000 && y > -10000 && x < 10000 && y < 10000 {
                    let _ = win.set_position(tauri::Position::Physical(
                        tauri::PhysicalPosition::new(x, y),
                    ));
                }
            }
            let _ = win.set_size(tauri::Size::Physical(tauri::PhysicalSize::new(w, h)));
            let _ = win.set_always_on_top(p.always_on_top);
            drop(p);

            // Spawn async font caching (silent, non-blocking).
            let app_paths = app.state::<AppPaths>();
            let fonts_dir = app_paths.fonts_dir.clone();
            let fa_dir = app_paths.fa_dir.clone();
            tauri::async_runtime::spawn(async move {
                let _ = fonts::ensure_google_fonts_local(&fonts_dir).await;
                let _ = fonts::ensure_fontawesome_local(&fa_dir).await;
            });

            // Auto-download ffmpeg/ffprobe if not found locally.
            if needs_ffmpeg_download {
                let handle = app.handle().clone();
                tauri::async_runtime::spawn(async move {
                    let sd = handle.state::<AppPaths>().state_dir.clone();
                    let (tx, _rx) = tokio::sync::mpsc::channel(16);
                    match ffmpeg::download_ffmpeg(&sd, tx).await {
                        Ok(paths) => {
                            let lib_state = handle.state::<Mutex<library::Library>>();
                            if let Ok(mut lib) = lib_state.lock() {
                                if lib.ffprobe.is_none() {
                                    lib.ffprobe = paths.ffprobe;
                                }
                                if lib.ffmpeg.is_none() {
                                    lib.ffmpeg = paths.ffmpeg;
                                }
                            }
                            eprintln!("[ffmpeg] Auto-download complete");
                        }
                        Err(e) => {
                            eprintln!("[ffmpeg] Auto-download failed: {}", e);
                        }
                    }
                });
            }

            Ok(())
        })
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}
