@using Ljbc1994.Blazor.IntersectionObserver.API
@using Ljbc1994.Blazor.IntersectionObserver.Components
<IntersectionObserve OnChange="entry => OnChange(entry)">
    <div @ref="context.Ref.Current" class="@Class @(Hide ? "hidden" : "")" style="@Style">
        @if (_state is State.Loading or State.Init)
        {
            <LoadingSpinner />
        }
        else
        {
            <button class="button" @onclick="Manual">Load more</button>
        }
    </div>
</IntersectionObserve>

@code {
    [Parameter] [EditorRequired] public EventCallback IntersectionChange { get; set; }
    [Parameter] [EditorRequired] public EventCallback ManualLoad         { get; set; }
    [Parameter]                  public string?       Class              { get; set; }
    [Parameter]                  public bool          RequireReset       { get; init; }
    [Parameter]                  public string?       Style              { get; set; }
    [Parameter]                  public bool          Hide               { get; set; } = false;
    public                              bool          Visible            { get; private set; }
    private                             State         _state;

    private async Task OnChange(IntersectionObserverEntry entry)
    {
        if (entry.IsIntersecting)
        {
            Visible = true;
            switch (_state)
            {
                case State.Loading:
                    return;
                case State.Waiting or State.Init:
                    _state = State.Loading;
                    await IntersectionChange.InvokeAsync();
                    break;
            }

            if (!RequireReset)
            {
                _state = State.Waiting;
            }
        } else if (entry.IsIntersecting == false)
        {
            Visible = false;
        }
    }

    private async Task Manual()
    {
        await ManualLoad.InvokeAsync();
    }

    private enum State
    {
        Init,
        Loading,
        Waiting
    }

    public void Reset()
    {
        _state = State.Waiting;
    }
}