@namespace Lumeo
@implements IAsyncDisposable
@inject Lumeo.Services.ComponentInteropService Interop
@inject Lumeo.Services.Localization.ILumeoLocalizer L

@if (_visible && !Disabled)
{
    <button type="button"
            class="@CssClass"
            @onclick="ScrollToTop"
            aria-label="@L["Common.BackToTop"]"
            @attributes="AdditionalAttributes">
        @if (ChildContent is not null)
        {
            @ChildContent
        }
        else
        {
            <Blazicon Svg="Lucide.ArrowUp" class="h-5 w-5" />
        }
    </button>
}

@code {
    [Parameter] public int VisibilityThreshold { get; set; } = 300;
    [Parameter] public bool Disabled { get; set; }
    [Parameter] public RenderFragment? ChildContent { get; set; }
    [Parameter] public string? Class { get; set; }
    [Parameter(CaptureUnmatchedValues = true)] public Dictionary<string, object>? AdditionalAttributes { get; set; }

    private bool _visible;
    private readonly string _id = $"backtotop-{Guid.NewGuid():N}";

    private string CssClass => $"fixed bottom-6 right-6 z-50 flex h-10 w-10 items-center justify-center rounded-full bg-primary text-primary-foreground shadow-lg transition-all hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-[1.5px] focus-visible:ring-ring focus-visible:ring-offset-2 {Class}".Trim();

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (!firstRender) return;
        try
        {
            await Interop.RegisterBackToTop(_id, VisibilityThreshold, async (visible) =>
            {
                if (_visible != visible)
                {
                    _visible = visible;
                    await InvokeAsync(StateHasChanged);
                }
            });
        }
        catch (JSDisconnectedException) { }
        catch (ObjectDisposedException) { }
    }

    private async Task ScrollToTop()
    {
        await Interop.ScrollToTop();
    }

    public async ValueTask DisposeAsync()
    {
        try
        {
            await Interop.UnregisterBackToTop(_id);
        }
        catch (JSDisconnectedException)
        {
            // Circuit disconnected, safe to ignore
        }
    }
}
