//! Synor Desktop Wallet - Tauri Backend
//!
//! Provides native functionality for the desktop wallet:
//! - Secure key storage using OS keychain
//! - Direct RPC communication with Synor nodes
//! - Transaction signing with Dilithium3 post-quantum signatures
//! - File system access for wallet backups
//! - System tray for background operation
//! - Auto-updates for seamless upgrades

mod commands;
mod crypto;
mod error;
mod wallet;

use tauri::{
    menu::{Menu, MenuItem},
    tray::{MouseButton, MouseButtonState, TrayIconBuilder, TrayIconEvent},
    Emitter, Manager, Runtime,
};

pub use error::{Error, Result};

/// Build the system tray menu
fn build_tray_menu<R: Runtime>(app: &tauri::AppHandle<R>) -> tauri::Result<Menu<R>> {
    let show = MenuItem::with_id(app, "show", "Show Wallet", true, None::<&str>)?;
    let hide = MenuItem::with_id(app, "hide", "Hide to Tray", true, None::<&str>)?;
    let separator1 = MenuItem::with_id(app, "sep1", "─────────────", false, None::<&str>)?;
    let lock = MenuItem::with_id(app, "lock", "Lock Wallet", true, None::<&str>)?;
    let separator2 = MenuItem::with_id(app, "sep2", "─────────────", false, None::<&str>)?;
    let check_updates = MenuItem::with_id(app, "check_updates", "Check for Updates", true, None::<&str>)?;
    let separator3 = MenuItem::with_id(app, "sep3", "─────────────", false, None::<&str>)?;
    let quit = MenuItem::with_id(app, "quit", "Quit", true, None::<&str>)?;

    Menu::with_items(
        app,
        &[
            &show,
            &hide,
            &separator1,
            &lock,
            &separator2,
            &check_updates,
            &separator3,
            &quit,
        ],
    )
}

/// Handle system tray menu events
fn handle_tray_event<R: Runtime>(app: &tauri::AppHandle<R>, event: TrayIconEvent) {
    match event {
        TrayIconEvent::Click {
            button: MouseButton::Left,
            button_state: MouseButtonState::Up,
            ..
        } => {
            // Left click: show and focus the window
            if let Some(window) = app.get_webview_window("main") {
                let _ = window.show();
                let _ = window.set_focus();
            }
        }
        _ => {}
    }
}

/// Handle tray menu item clicks
fn handle_menu_event<R: Runtime>(app: &tauri::AppHandle<R>, event: tauri::menu::MenuEvent) {
    match event.id().as_ref() {
        "show" => {
            if let Some(window) = app.get_webview_window("main") {
                let _ = window.show();
                let _ = window.set_focus();
            }
        }
        "hide" => {
            if let Some(window) = app.get_webview_window("main") {
                let _ = window.hide();
            }
        }
        "lock" => {
            // Emit lock event to frontend
            let _ = app.emit("wallet-lock", ());
        }
        "check_updates" => {
            // Emit update check event to frontend
            let _ = app.emit("check-updates", ());
        }
        "quit" => {
            // Emit quit event to allow cleanup
            let _ = app.emit("app-quit", ());
            std::process::exit(0);
        }
        _ => {}
    }
}

/// Initialize the Tauri application with all plugins and commands
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
    tauri::Builder::default()
        // Core plugins
        .plugin(tauri_plugin_fs::init())
        .plugin(tauri_plugin_store::Builder::default().build())
        .plugin(tauri_plugin_shell::init())
        .plugin(tauri_plugin_dialog::init())
        .plugin(tauri_plugin_clipboard_manager::init())
        // New plugins for desktop features
        .plugin(tauri_plugin_updater::Builder::new().build())
        .plugin(tauri_plugin_notification::init())
        .plugin(tauri_plugin_process::init())
        .setup(|app| {
            // Initialize wallet state
            let wallet_state = wallet::WalletState::new();
            app.manage(wallet_state);

            // Build and set up system tray
            let menu = build_tray_menu(app.handle())?;
            let _tray = TrayIconBuilder::new()
                .icon(app.default_window_icon().unwrap().clone())
                .menu(&menu)
                .show_menu_on_left_click(false)
                .on_tray_icon_event(|tray, event| {
                    handle_tray_event(tray.app_handle(), event);
                })
                .on_menu_event(|app, event| {
                    handle_menu_event(app, event);
                })
                .tooltip("Synor Wallet")
                .build(app)?;

            // Check for updates on startup (non-blocking)
            let handle = app.handle().clone();
            tauri::async_runtime::spawn(async move {
                check_for_updates(handle).await;
            });

            #[cfg(debug_assertions)]
            {
                // Open devtools in development
                if let Some(window) = app.get_webview_window("main") {
                    window.open_devtools();
                }
            }

            Ok(())
        })
        .invoke_handler(tauri::generate_handler![
            // Wallet management
            commands::create_wallet,
            commands::import_wallet,
            commands::unlock_wallet,
            commands::lock_wallet,
            commands::get_wallet_info,
            commands::export_mnemonic,
            // Addresses & UTXOs
            commands::get_addresses,
            commands::generate_address,
            commands::get_balance,
            commands::get_utxos,
            // Transactions
            commands::create_transaction,
            commands::sign_transaction,
            commands::broadcast_transaction,
            commands::get_transaction_history,
            // Network
            commands::connect_node,
            commands::disconnect_node,
            commands::get_network_status,
            // Updates
            check_update,
            install_update,
        ])
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}

/// Check for updates on startup
async fn check_for_updates<R: Runtime>(app: tauri::AppHandle<R>) {
    use tauri_plugin_updater::UpdaterExt;

    // Wait a few seconds before checking for updates
    tokio::time::sleep(std::time::Duration::from_secs(5)).await;

    let updater = match app.updater() {
        Ok(u) => u,
        Err(e) => {
            eprintln!("Updater not available: {}", e);
            return;
        }
    };

    match updater.check().await {
        Ok(Some(update)) => {
            // Notify frontend about available update
            let _ = app.emit("update-available", serde_json::json!({
                "version": update.version,
                "body": update.body,
                "date": update.date
            }));
        }
        Ok(None) => {
            // No update available
        }
        Err(e) => {
            eprintln!("Failed to check for updates: {}", e);
        }
    }
}

/// Tauri command: Check for updates
#[tauri::command]
async fn check_update<R: Runtime>(app: tauri::AppHandle<R>) -> std::result::Result<Option<serde_json::Value>, String> {
    use tauri_plugin_updater::UpdaterExt;

    let updater = app.updater().map_err(|e| format!("Updater not configured: {}", e))?;

    match updater.check().await {
        Ok(Some(update)) => {
            Ok(Some(serde_json::json!({
                "version": update.version,
                "body": update.body,
                "date": update.date
            })))
        }
        Ok(None) => Ok(None),
        Err(e) => Err(format!("Update check failed: {}", e)),
    }
}

/// Tauri command: Install update
#[tauri::command]
async fn install_update<R: Runtime>(app: tauri::AppHandle<R>) -> std::result::Result<(), String> {
    use tauri_plugin_updater::UpdaterExt;

    let updater = app.updater().map_err(|e| format!("Updater not configured: {}", e))?;

    match updater.check().await {
        Ok(Some(update)) => {
            // Download and install with progress callbacks
            let downloaded: u64 = 0;
            let total_size: u64 = 0;

            update.download_and_install(
                move |chunk_len, content_len| {
                    // Progress callback - could emit progress events here
                    let _ = (chunk_len, content_len, downloaded, total_size);
                },
                || {
                    // Ready to install callback
                },
            ).await.map_err(|e| format!("Update installation failed: {}", e))?;

            // Notify user to restart
            let _ = app.emit("update-installed", ());

            Ok(())
        }
        Ok(None) => Err("No update available".to_string()),
        Err(e) => Err(format!("Update check failed: {}", e)),
    }
}
