using Microsoft.JSInterop;

namespace DeepDrftPublic.Client.Services;

/// <summary>
/// Thin C# wrapper over the <c>window.DeepDrftBeacon</c> TS interop (Phase 16 §2.2). Wraps the
/// <c>navigator.sendBeacon</c> POST and the page-unload registration so the rest of the client never
/// touches <see cref="IJSRuntime"/> string identifiers directly. All calls are best-effort: a JS
/// failure (module not yet loaded, interop unavailable during prerender) is swallowed — telemetry must
/// never throw into the UI or the playback path.
/// </summary>
public sealed class BeaconInterop
{
    private readonly IJSRuntime _js;

    public BeaconInterop(IJSRuntime js)
    {
        _js = js;
    }

    /// <summary>Queue a fire-and-forget POST of a JSON body to the given absolute URL.</summary>
    public async Task SendAsync(string url, string json)
    {
        try
        {
            await _js.InvokeAsync<bool>("DeepDrftBeacon.send", url, json);
        }
        catch
        {
            // Module not loaded / not interactive yet — drop the event silently.
        }
    }

    /// <summary>Register a .NET unload callback (fires on pagehide / visibility→hidden) under a key.</summary>
    public async Task RegisterUnloadAsync<T>(string key, DotNetObjectReference<T> dotNetRef, string methodName)
        where T : class
    {
        try
        {
            await _js.InvokeVoidAsync("DeepDrftBeacon.registerUnload", key, dotNetRef, methodName);
        }
        catch
        {
            // Best-effort — without the unload handler, mid-play tab-close simply isn't recorded.
        }
    }

    /// <summary>Detach a previously-registered unload callback.</summary>
    public async Task UnregisterUnloadAsync(string key)
    {
        try
        {
            await _js.InvokeVoidAsync("DeepDrftBeacon.unregisterUnload", key);
        }
        catch
        {
            // Disposal best-effort.
        }
    }
}
