using System.Text.Json;
using System.Text.Json.Serialization;
using DeepDrftModels.DTOs;
using DeepDrftModels.Enums;
using Microsoft.AspNetCore.Components;

namespace DeepDrftPublic.Client.Services;

/// <summary>
/// Production <see cref="IPlayEventSink"/> (Phase 16 §2.2): serializes the play classification and fires
/// it via <c>navigator.sendBeacon</c> to the proxied <c>api/event/play</c> route. Fire-and-forget by
/// design — <see cref="IPlayEventSink.EmitPlay"/> is synchronous (it is called from the player's close
/// path and the unload handler, neither of which can await), so the beacon is dispatched without
/// awaiting and its failure is irrelevant. The current <c>anonId</c> (wave 16.3) is read synchronously
/// from the warmed <see cref="IAnonIdProvider"/> cache and omitted when null (storage unavailable / not
/// yet warmed) — an anonId-less play still counts, it just doesn't contribute to the listener tally.
/// </summary>
public sealed class BeaconPlayEventSink : IPlayEventSink
{
    // Omit a null anonId from the wire payload (§2.2 — "omitted entirely" when absent) rather than
    // sending "anonId":null. The API treats absent and null identically, so this is cosmetic minimalism;
    // it does not change the integer enum encoding the 16.1 contract already relies on.
    private static readonly JsonSerializerOptions BeaconJson =
        new() { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull };

    private readonly BeaconInterop _beacon;
    private readonly IAnonIdProvider _anonId;
    private readonly string _playUrl;

    public BeaconPlayEventSink(BeaconInterop beacon, IAnonIdProvider anonId, NavigationManager navigation)
    {
        _beacon = beacon;
        _anonId = anonId;
        // The WASM client posts to its own host, which proxies to DeepDrftAPI. BaseUri carries a
        // trailing slash; the route does not lead with one.
        _playUrl = $"{navigation.BaseUri}api/event/play";
    }

    public void EmitPlay(string trackEntryKey, PlayBucket bucket)
    {
        var json = JsonSerializer.Serialize(new PlayEventDto
        {
            TrackEntryKey = trackEntryKey,
            Bucket = bucket,
            AnonId = _anonId.Current,
        }, BeaconJson);

        // Fire-and-forget: do not await. The beacon survives unload; the C# task may not, and we do not
        // act on the result either way.
        _ = _beacon.SendAsync(_playUrl, json);
    }
}
