//! Windows-only window branding for the SDL session window.
//!
//! SDL registers its window class with a generic icon, so without help the taskbar and
//! Alt-Tab show the SDL default even when the exe embeds ours. [`stamp_window_icon`]
//! stamps the exe's icon resource (ordinal 1, when embedded — see the session binary's
//! `build.rs`) onto the window via `WM_SETICON`, at the native small/big metrics so
//! nothing is scaled at draw time — the same treatment the WinUI shell gives its window.
//!
//! [`set_app_user_model_id`] gives unpackaged (dev/CLI) runs the same explicit
//! AppUserModelID as the shell, so the two windows group as ONE taskbar app across the
//! shell⇄session visibility handoff. MSIX runs already share the package identity, and
//! overriding it would detach the window from the Start-menu pin — so packaged processes
//! are left alone.

use windows_sys::core::w;
use windows_sys::Win32::Foundation::{APPMODEL_ERROR_NO_PACKAGE, HWND, LPARAM, WPARAM};
use windows_sys::Win32::Storage::Packaging::Appx::GetCurrentPackageFullName;
use windows_sys::Win32::System::LibraryLoader::GetModuleHandleW;
use windows_sys::Win32::UI::Shell::SetCurrentProcessExplicitAppUserModelID;
use windows_sys::Win32::UI::WindowsAndMessaging::{
    GetSystemMetrics, LoadImageW, SendMessageW, ICON_BIG, ICON_SMALL, IMAGE_ICON, LR_DEFAULTCOLOR,
    SM_CXICON, SM_CXSMICON, WM_SETICON,
};

/// The shared taskbar identity — must stay in sync with the WinUI shell's
/// (`clients/windows/src/main.rs`), or the two windows stop grouping.
const APP_USER_MODEL_ID: *const u16 = w!("unom.punktfunk.client");

/// Tag this process with the shared AppUserModelID — unpackaged runs only (a packaged
/// process already carries the MSIX identity, which must win). Call before any window
/// exists; later calls don't re-tag existing windows.
pub(crate) fn set_app_user_model_id() {
    // SAFETY: `GetCurrentPackageFullName` is called with `len = 0` and a NULL buffer, which is the
    // documented identity PROBE — it writes nothing and only reports whether the process is
    // packaged. `SetCurrentProcessExplicitAppUserModelID` takes a static wide literal.
    unsafe {
        let mut len: u32 = 0;
        // No buffer: just probe whether the process has package identity.
        if GetCurrentPackageFullName(&mut len, std::ptr::null_mut()) != APPMODEL_ERROR_NO_PACKAGE {
            return; // packaged (or indeterminate) — leave the identity alone
        }
        let _ = SetCurrentProcessExplicitAppUserModelID(APP_USER_MODEL_ID);
    }
}

/// Stamp the exe-embedded icon (resource ordinal 1) onto the SDL window's title bar,
/// taskbar and Alt-Tab. A quiet no-op when the exe embeds no icon.
pub(crate) fn stamp_window_icon(window: &sdl3::video::Window) {
    // SAFETY: the SDL property lookups return the `HWND` SDL itself owns for this live `window`
    // borrow; the icon calls only pass that handle and a resource ordinal back to Win32, and every
    // result is checked before use.
    unsafe {
        // The HWND behind the SDL window, via SDL3's window properties (the same route
        // the sdl3 crate's raw-window-handle integration takes).
        let hwnd: HWND = sdl3::sys::properties::SDL_GetPointerProperty(
            sdl3::sys::video::SDL_GetWindowProperties(window.raw()),
            sdl3::sys::video::SDL_PROP_WINDOW_WIN32_HWND_POINTER,
            std::ptr::null_mut(),
        ) as HWND;
        if hwnd.is_null() {
            return;
        }
        let module = GetModuleHandleW(std::ptr::null());
        for (which, metric) in [(ICON_SMALL, SM_CXSMICON), (ICON_BIG, SM_CXICON)] {
            let px = GetSystemMetrics(metric);
            // MAKEINTRESOURCE(1): an integer resource ordinal smuggled through the name
            // pointer, never dereferenced — `without_provenance` says exactly that (and
            // `1 as *const u16` reads as a dangling pointer to clippy 1.96).
            let icon = LoadImageW(
                module,
                std::ptr::without_provenance(1),
                IMAGE_ICON,
                px,
                px,
                LR_DEFAULTCOLOR,
            );
            if !icon.is_null() {
                SendMessageW(hwnd, WM_SETICON, which as WPARAM, icon as LPARAM);
            }
        }
    }
}
