using DeepDrftModels.DTOs;
using DeepDrftPublic.Client.Helpers;
using DeepDrftPublic.Client.Services;
using Microsoft.AspNetCore.Components;
using MudBlazor;

namespace DeepDrftPublic.Client.Controls;

/// <summary>
/// Renders the play/pause transport glyph for either a specific track or global playback,
/// reading live state off the cascaded <see cref="IStreamingPlayerService"/>. The icon is
/// always resolved through <see cref="PlaybackIcons.Resolve"/>.
/// </summary>
public partial class PlayStateIcon : ComponentBase, IDisposable
{
    [CascadingParameter] public IStreamingPlayerService? PlayerService { get; set; }

    /// <summary>
    /// When non-null, the icon reflects this track's playback state (active only when it is the
    /// current track). When null, it reflects global playback state.
    /// </summary>
    [Parameter] public TrackDto? Track { get; set; }

    [Parameter] public Size Size { get; set; } = Size.Medium;
    [Parameter] public Color Color { get; set; } = Color.Primary;
    [Parameter] public bool Disabled { get; set; } = false;
    [Parameter] public EventCallback OnToggle { get; set; }

    private IStreamingPlayerService? _subscribedService;

    private bool IsActive => Track is null || PlayerService?.CurrentTrack?.Id == Track.Id;
    private bool IsPlaying => IsActive && (PlayerService?.IsPlaying ?? false);
    private bool IsPaused => IsActive && (PlayerService?.IsPaused ?? false);

    private string Icon => PlaybackIcons.Resolve(IsPlaying, IsPaused);

    protected override void OnParametersSet()
    {
        // The cascade is IsFixed, so the provider's re-render never reaches us; subscribe to the
        // multicast side-channel to re-render on every player state change. Reference-guarded so
        // re-parametering is idempotent. Mirrors AudioPlayerBar.
        if (PlayerService != null && !ReferenceEquals(PlayerService, _subscribedService))
        {
            if (_subscribedService != null)
                _subscribedService.StateChanged -= OnPlayerStateChanged;

            PlayerService.StateChanged += OnPlayerStateChanged;
            _subscribedService = PlayerService;
        }
    }

    private void OnPlayerStateChanged() => InvokeAsync(StateHasChanged);

    public void Dispose()
    {
        if (_subscribedService != null)
        {
            _subscribedService.StateChanged -= OnPlayerStateChanged;
            _subscribedService = null;
        }
    }
}
