@namespace Lumeo
@implements IAsyncDisposable

@if (Context.IsOpen)
{
    <div id="@_contentId" class="@CssClass" style="@PositionStyle" @onkeydown="HandleKeyDown" tabindex="-1" @attributes="AdditionalAttributes">
        @ChildContent
    </div>
}

@inject ComponentInteropService Interop

@code {
    [CascadingParameter] public ContextMenu.ContextMenuContext Context { get; set; } = default!;
    [Parameter] public RenderFragment? ChildContent { get; set; }
    [Parameter] public string? Class { get; set; }
    [Parameter(CaptureUnmatchedValues = true)] public Dictionary<string, object>? AdditionalAttributes { get; set; }

    private readonly string _contentId = $"context-menu-content-{Guid.NewGuid():N}";
    private bool _registered;
    private int _focusedIndex = -1;

    private string CssClass => $"fixed z-50 min-w-[8rem] overflow-hidden rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-lg animate-fade-in {Class}".Trim();

    private string PositionStyle => string.Create(System.Globalization.CultureInfo.InvariantCulture, $"position: fixed; left: {Context.X}px; top: {Context.Y}px");

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (Context.IsOpen && !_registered)
        {
            await Interop.RegisterClickOutside(_contentId, null, async () =>
            {
                await Context.SetOpen.InvokeAsync(false);
                await InvokeAsync(StateHasChanged);
            });
            _registered = true;
            _focusedIndex = -1;
        }
        else if (!Context.IsOpen && _registered)
        {
            await Cleanup();
        }
    }

    private async Task HandleKeyDown(KeyboardEventArgs e)
    {
        switch (e.Key)
        {
            case "Escape":
                await Context.SetOpen.InvokeAsync(false);
                break;
            case "ArrowDown":
                {
                    var count = await Interop.GetMenuItemCount(_contentId);
                    if (count > 0)
                    {
                        _focusedIndex = (_focusedIndex + 1) % count;
                        await Interop.FocusMenuItemByIndex(_contentId, _focusedIndex);
                    }
                    break;
                }
            case "ArrowUp":
                {
                    var count = await Interop.GetMenuItemCount(_contentId);
                    if (count > 0)
                    {
                        _focusedIndex = _focusedIndex <= 0 ? count - 1 : _focusedIndex - 1;
                        await Interop.FocusMenuItemByIndex(_contentId, _focusedIndex);
                    }
                    break;
                }
            case "Home":
                {
                    var count = await Interop.GetMenuItemCount(_contentId);
                    if (count > 0)
                    {
                        _focusedIndex = 0;
                        await Interop.FocusMenuItemByIndex(_contentId, _focusedIndex);
                    }
                    break;
                }
            case "End":
                {
                    var count = await Interop.GetMenuItemCount(_contentId);
                    if (count > 0)
                    {
                        _focusedIndex = count - 1;
                        await Interop.FocusMenuItemByIndex(_contentId, _focusedIndex);
                    }
                    break;
                }
        }
    }

    private async Task Cleanup()
    {
        try
        {
            await Interop.UnregisterClickOutside(_contentId);
        }
        catch (JSDisconnectedException) { }
        _registered = false;
    }

    public async ValueTask DisposeAsync()
    {
        if (_registered) await Cleanup();
    }
}
