@namespace Lumeo
@implements IAsyncDisposable
@inject ComponentInteropService Interop

<div id="@_elementId" class="@CssClass" style="@StyleString" data-motion-visible="@InitialMotionState" @attributes="AdditionalAttributes">
    @ChildContent
</div>

@code {
    [Parameter] public RenderFragment? ChildContent { get; set; }
    [Parameter] public int DelayMs { get; set; } = 0;
    [Parameter] public int DurationMs { get; set; } = 600;
    [Parameter] public int BlurPx { get; set; } = 8;
    [Parameter] public int Yoffset { get; set; } = 8;
    [Parameter] public bool Once { get; set; } = true;
    /// <summary>
    /// When true, always start in the hidden state and animate in — even if the element is already
    /// in the viewport at mount. Default (false) is prerender-friendly: above-the-fold BlurFades
    /// stay statically visible to avoid a flash of blurred content on first paint. Set to true for
    /// docs demos or controlled "Replay" scenarios where you always want the animation to play.
    /// </summary>
    [Parameter] public bool ForceHidden { get; set; }
    [Parameter] public string? Class { get; set; }
    [Parameter(CaptureUnmatchedValues = true)] public Dictionary<string, object>? AdditionalAttributes { get; set; }

    private readonly string _elementId = $"lumeo-blurfade-{Guid.NewGuid():N}";
    private bool _registered;

    private string CssClass => string.Join(" ", new[] { "lumeo-blur-fade", Class }.Where(s => !string.IsNullOrWhiteSpace(s)));

    // When ForceHidden, render the initial hidden state directly via attribute so the very first
    // paint already shows the to-be-animated state. Prevents a one-frame flash of fully-visible
    // content before the JS observer marks it hidden.
    private string? InitialMotionState => ForceHidden ? "false" : null;

    private string StyleString =>
        $"--lumeo-blur-px: {BlurPx}px; --lumeo-blur-y: {Yoffset}px; --lumeo-blur-duration: {DurationMs}ms;";

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender && !_registered)
        {
            _registered = true;
            try
            {
                await Interop.MotionBlurFade(_elementId, DelayMs, Once, ForceHidden);
            }
            catch (JSDisconnectedException) { }
        }
    }

    public async ValueTask DisposeAsync()
    {
        if (_registered)
        {
            await Interop.MotionDisposeObserver(_elementId);
        }
    }
}
