//! P5-41 / P5-35 — Register an AppUserModelID (AUMID) so the WinRT rich toasts in
//! `toast.rs` actually work on Windows.
//!
//! `ToastNotificationManager::CreateToastNotifierWithId` (and the ambient
//! `CreateToastNotifier`) require the process to run under an AUMID that maps to a
//! Start-Menu shortcut carrying `System.AppUserModel.ID`. An unpackaged Win32 app
//! (our NSIS build) has none by default, so `Show()` errored and the rich toast
//! (reply box + click-to-open-room) silently fell back to the plain plugin toast.
//!
//! On startup we (1) advertise the AUMID for this process and (2) install/refresh
//! a Start-Menu `.lnk` (same name → overwrites the installer's, no duplicate)
//! carrying the AUMID. Reuses the `IShellLinkW` + `IPropertyStore` + `PROPVARIANT`
//! pattern proven in `jumplist.rs`. Best-effort: any failure is logged and
//! swallowed (the toast just keeps falling back, as before — never crash boot).
//!
//! Non-Windows: a no-op.

use tauri::AppHandle;

/// The AUMID this process advertises and that the Start-Menu shortcut carries.
/// `toast.rs` binds the toast notifier to it via `CreateToastNotifierWithId`.
pub const APP_USER_MODEL_ID: &str = "LotusGuild.LotusChat";

#[cfg(target_os = "windows")]
pub fn ensure_app_user_model_id(_app: &AppHandle) {
    use std::os::windows::ffi::OsStrExt;
    use windows::core::{Interface, GUID, HSTRING, PCWSTR};
    use windows::Win32::System::Com::{
        CoCreateInstance, CoInitializeEx, CoUninitialize, IPersistFile,
        StructuredStorage::PROPVARIANT, CLSCTX_INPROC_SERVER, COINIT_APARTMENTTHREADED,
    };
    use windows::Win32::UI::Shell::{
        PropertiesSystem::{IPropertyStore, PROPERTYKEY},
        IShellLinkW, SetCurrentProcessExplicitAppUserModelID, ShellLink,
    };

    // 1. Advertise the AUMID for this process (must happen before any toast fires).
    if let Err(e) =
        unsafe { SetCurrentProcessExplicitAppUserModelID(&HSTRING::from(APP_USER_MODEL_ID)) }
    {
        eprintln!("aumid: SetCurrentProcessExplicitAppUserModelID failed: {e}");
    }

    // 2. Install/refresh the Start-Menu shortcut carrying the AUMID so Action
    //    Center attributes toasts to "Lotus Chat". Path via %APPDATA% (avoids the
    //    SHGetKnownFolderPath free-mem dance); dir already exists for installed apps.
    let appdata = match std::env::var_os("APPDATA") {
        Some(v) => v,
        None => return,
    };
    let mut lnk = std::path::PathBuf::from(appdata);
    lnk.push(r"Microsoft\Windows\Start Menu\Programs");
    let _ = std::fs::create_dir_all(&lnk);
    lnk.push("Lotus Chat.lnk");

    let exe = match std::env::current_exe() {
        Ok(p) => p,
        Err(_) => return,
    };
    let exe_wide: Vec<u16> = exe
        .as_os_str()
        .encode_wide()
        .chain(std::iter::once(0))
        .collect();
    let lnk_wide: Vec<u16> = lnk
        .as_os_str()
        .encode_wide()
        .chain(std::iter::once(0))
        .collect();

    // PKEY_AppUserModel_ID = {9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3}, pid 5.
    // Constructed inline so we don't depend on the const's crate module path.
    const PKEY_APP_USER_MODEL_ID: PROPERTYKEY = PROPERTYKEY {
        fmtid: GUID::from_u128(0x9F4C2855_9F79_4B39_A8D0_E1D42DE1D5F3),
        pid: 5,
    };

    // STA apartment for the shell link objects, mirroring jumplist.rs. All COM
    // interfaces are dropped before CoUninitialize.
    let hr = unsafe { CoInitializeEx(None, COINIT_APARTMENTTHREADED) };
    let result = (|| -> windows::core::Result<()> {
        unsafe {
            let link: IShellLinkW = CoCreateInstance(&ShellLink, None, CLSCTX_INPROC_SERVER)?;
            link.SetPath(PCWSTR(exe_wide.as_ptr()))?;
            link.SetIconLocation(PCWSTR(exe_wide.as_ptr()), 0)?;

            // Stamp the AUMID onto the link's property store (VT_LPWSTR, exactly
            // like PKEY_Title in jumplist.rs).
            let store: IPropertyStore = link.cast()?;
            let value = PROPVARIANT::from(APP_USER_MODEL_ID);
            store.SetValue(&PKEY_APP_USER_MODEL_ID, &value)?;
            store.Commit()?;

            // Persist the .lnk to the Start-Menu Programs folder.
            let persist: IPersistFile = link.cast()?;
            // fremember is a Win32 BOOL (not bool); `.into()` uses From<bool>.
            persist.Save(PCWSTR(lnk_wide.as_ptr()), true.into())?;
            Ok(())
        }
    })();

    if hr.is_ok() {
        unsafe { CoUninitialize() };
    }
    if let Err(e) = result {
        eprintln!("aumid: failed to install Start-Menu shortcut: {e}");
    }
}

#[cfg(not(target_os = "windows"))]
pub fn ensure_app_user_model_id(_app: &AppHandle) {}
