//! The downloads notice on the phone.
//!
//! The Transfers screen only exists inside the app: the desktop says what a
//! Save is doing with its title-bar ring, the phone with a badge on the nav,
//! and neither is visible once the app is in the background — which is
//! exactly when a Save is left to run on its own. So a running Save says so
//! where the phone says things, in the shade: how many files are left, the
//! one it is on, a progress bar, Stop all and Open.
//!
//! Its own channel, low importance, so it can be silenced without silencing
//! the player's card. Its own foreground service (`TransferService`,
//! `dataSync`) rather than the media one, because a download is not
//! playback: `MediaService` stops itself the moment the bar empties, and a
//! `mediaPlayback` service with no session is a policy violation. That
//! service is also what keeps the process alive for a Save with nothing
//! playing — the way the first real Save died, four tracks in.
//!
//! Two commands, both fed by the phone UI (src/mobile/xfernote.svelte.js):
//! `update` with what is still in flight, `clear` when the queue empties.
//! The notice's buttons arrive as the plugin event `action`
//! (`addPluginListener("transfer-notice", "action", …)`): `cancel` stops
//! everything still going, `open` brings the app forward on Transfers.
//!
//! On the desktop the plugin is registered too, so the permission set
//! resolves on every platform, but its commands answer "not here".

use serde::{Deserialize, Serialize};
use tauri::{
    plugin::{Builder, TauriPlugin},
    Runtime,
};

/// What the notice says: how many files are still in flight, the one it is
/// on, and how far the burst has come. `indeterminate` is a queue whose
/// sizes no peer has stated yet — a bar with no end to walk towards.
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[serde(rename_all = "camelCase")]
pub struct TransferNotice {
    #[serde(default)]
    pub count: u32,
    pub title: Option<String>,
    pub line: Option<String>,
    #[serde(default)]
    pub percent: i32,
    #[serde(default)]
    pub indeterminate: bool,
}

#[cfg(mobile)]
pub struct TransferNoticePlugin<R: Runtime>(tauri::plugin::PluginHandle<R>);

#[tauri::command]
fn update<R: Runtime>(app: tauri::AppHandle<R>, state: TransferNotice) -> Result<(), String> {
    #[cfg(mobile)]
    {
        use tauri::Manager;
        let notice = app.state::<TransferNoticePlugin<R>>();
        notice
            .0
            .run_mobile_plugin::<serde_json::Value>("update", state)
            .map(|_| ())
            .map_err(|e| e.to_string())
    }
    #[cfg(not(mobile))]
    {
        let _ = (app, state);
        Err("the downloads notice is a phone feature".into())
    }
}

#[tauri::command]
fn clear<R: Runtime>(app: tauri::AppHandle<R>) -> Result<(), String> {
    #[cfg(mobile)]
    {
        use tauri::Manager;
        let notice = app.state::<TransferNoticePlugin<R>>();
        notice
            .0
            .run_mobile_plugin::<serde_json::Value>("clear", ())
            .map(|_| ())
            .map_err(|e| e.to_string())
    }
    #[cfg(not(mobile))]
    {
        let _ = app;
        Err("the downloads notice is a phone feature".into())
    }
}

pub fn init<R: Runtime>() -> TauriPlugin<R> {
    Builder::new("transfer-notice")
        .invoke_handler(tauri::generate_handler![update, clear])
        .setup(|app, api| {
            #[cfg(target_os = "android")]
            {
                use tauri::Manager;
                let handle = api.register_android_plugin(
                    "com.soulstream.transfernotice",
                    "TransferNoticePlugin",
                )?;
                app.manage(TransferNoticePlugin(handle));
            }
            #[cfg(not(target_os = "android"))]
            {
                let _ = (app, api);
            }
            Ok(())
        })
        .build()
}
