//! P5-43 — System Media Transport Controls (SMTC) call surface (Windows).
//!
//! Surfaces the active voice/video call to the Windows media overlay (the
//! volume flyout / SMTC card) so the user can mute or hang up from the OS
//! media controls. We create the SMTC via the WinRT interop factory
//! (`ISystemMediaTransportControlsInterop::GetForWindow`), keep the object in
//! managed state, and let the web client drive its state through
//! `set_smtc_call_state` as the call-embed atom / mic state changes.
//!
//! Button mapping: **Play/Pause → mute toggle**, **Stop → end call**. Presses
//! are forwarded to the web client as a `smtc-action` DOM CustomEvent (see
//! `super::emit_to_web`) with `action` in `"mute" | "end"`; the web hook
//! (`useTauriSmtc`) translates them into `CallControl.toggleMicrophone()` /
//! `CallEmbed.hangup()`.
//!
//! RUNTIME NOTE: SMTC is designed for real media apps. For a non-media app the
//! card may not actually appear unless the process owns an active audio session
//! recognised by the system. This module prioritises a clean compile and
//! correct WinRT API usage; visibility of the overlay at runtime is uncertain
//! and may depend on the embedded Element Call iframe holding an audio session.
//!
//! Other platforms are a no-op (SMTC is Windows-only); the command keeps an
//! identical cross-platform signature so the web side stays unconditional.

use tauri::AppHandle;

/// Payload for the `smtc-action` DOM event forwarded to the web client.
#[cfg(target_os = "windows")]
#[derive(serde::Serialize)]
struct Ev {
    action: String,
}

/// Holds the SMTC object (and its `ButtonPressed` registration token) in Tauri
/// managed state so `set_smtc_call_state` can update it at runtime. Mirrors the
/// `TrayUnreadState` managed-state pattern in lib.rs.
#[cfg(target_os = "windows")]
struct SmtcState {
    controls: std::sync::Mutex<Option<windows::Media::SystemMediaTransportControls>>,
    // Kept alive so the ButtonPressed handler stays registered for the app's
    // lifetime; never unregistered. (windows 0.61 event registrations return a
    // plain i64 token — the EventRegistrationToken newtype is gone.)
    _token: i64,
}

/// Called once from `native::setup()`. Creates and configures the SMTC on
/// Windows; no-op elsewhere. SMTC init failures are logged and swallowed so a
/// missing/unsupported overlay never blocks app startup.
pub fn setup(app: &AppHandle) -> tauri::Result<()> {
    #[cfg(target_os = "windows")]
    {
        if let Err(err) = init_smtc(app) {
            eprintln!("smtc: failed to initialize System Media Transport Controls: {err:?}");
        }
    }

    #[cfg(not(target_os = "windows"))]
    {
        let _ = app;
    }

    Ok(())
}

#[cfg(target_os = "windows")]
fn init_smtc(app: &AppHandle) -> Result<(), Box<dyn std::error::Error>> {
    use tauri::Manager;
    use windows::core::{factory, HSTRING};
    use windows::Foundation::TypedEventHandler;
    use windows::Media::{
        MediaPlaybackStatus, MediaPlaybackType, SystemMediaTransportControls,
        SystemMediaTransportControlsButton, SystemMediaTransportControlsButtonPressedEventArgs,
    };
    use windows::Win32::Foundation::HWND;
    use windows::Win32::System::WinRT::ISystemMediaTransportControlsInterop;

    let window = app
        .get_webview_window("main")
        .ok_or("smtc: main window not found")?;
    // Match the HWND conversion used by set_badge_count in lib.rs.
    let hwnd = HWND(window.hwnd()?.0 as _);

    // SMTC has no WinRT constructor; it's obtained per-window via the interop
    // factory. `factory::<C, I>()` fetches the activation factory for the
    // runtime class `C` cast to the classic COM interop interface `I`.
    let interop =
        factory::<SystemMediaTransportControls, ISystemMediaTransportControlsInterop>()?;
    let controls: SystemMediaTransportControls = unsafe { interop.GetForWindow(hwnd)? };

    controls.SetIsEnabled(true)?;
    controls.SetIsPlayEnabled(true)?;
    controls.SetIsPauseEnabled(true)?;
    controls.SetIsStopEnabled(true)?;

    // Configure the card metadata once ("In call"); the web side only toggles
    // playback status afterwards.
    let updater = controls.DisplayUpdater()?;
    updater.SetType(MediaPlaybackType::Music)?;
    let music = updater.MusicProperties()?;
    music.SetTitle(&HSTRING::from("In call"))?;
    updater.Update()?;

    // Idle until a call becomes active (set_smtc_call_state flips this).
    controls.SetPlaybackStatus(MediaPlaybackStatus::Closed)?;

    // ButtonPressed → forward a normalized action to the web client.
    let app_for_handler = app.clone();
    let handler = TypedEventHandler::<
        SystemMediaTransportControls,
        SystemMediaTransportControlsButtonPressedEventArgs,
    >::new(move |_sender, args| {
        if let Some(args) = args.as_ref() {
            let button = args.Button()?;
            let action = if button == SystemMediaTransportControlsButton::Play
                || button == SystemMediaTransportControlsButton::Pause
            {
                Some("mute")
            } else if button == SystemMediaTransportControlsButton::Stop {
                Some("end")
            } else {
                None
            };
            if let Some(action) = action {
                let payload = serde_json::to_string(&Ev {
                    action: action.to_string(),
                })
                .unwrap_or_default();
                super::emit_to_web(&app_for_handler, "smtc-action", &payload);
            }
        }
        Ok(())
    });
    let token = controls.ButtonPressed(&handler)?;

    app.manage(SmtcState {
        controls: std::sync::Mutex::new(Some(controls)),
        _token: token,
    });

    Ok(())
}

/// Reflect the call state onto the SMTC. When `active`, enable the controls and
/// set playback status to Playing (unmuted) / Paused (muted); when inactive,
/// mark the card Closed and disable it. Windows-only; no-op elsewhere.
#[tauri::command]
pub fn set_smtc_call_state(app: AppHandle, active: bool, muted: bool) {
    #[cfg(target_os = "windows")]
    {
        use tauri::Manager;
        if let Some(state) = app.try_state::<SmtcState>() {
            if let Ok(guard) = state.controls.lock() {
                if let Some(controls) = guard.as_ref() {
                    let _ = apply_call_state(controls, active, muted);
                }
            }
        }
    }

    #[cfg(not(target_os = "windows"))]
    {
        // No-op off Windows; bind args so the signature is identical everywhere
        // and no unused warnings fire.
        let _ = (&app, active, muted);
    }
}

#[cfg(target_os = "windows")]
fn apply_call_state(
    controls: &windows::Media::SystemMediaTransportControls,
    active: bool,
    muted: bool,
) -> windows::core::Result<()> {
    use windows::Media::MediaPlaybackStatus;

    if active {
        controls.SetIsEnabled(true)?;
        let status = if muted {
            MediaPlaybackStatus::Paused
        } else {
            MediaPlaybackStatus::Playing
        };
        controls.SetPlaybackStatus(status)?;
    } else {
        controls.SetPlaybackStatus(MediaPlaybackStatus::Closed)?;
        controls.SetIsEnabled(false)?;
    }

    Ok(())
}
