@namespace Lumeo

<button type="button"
        id="@_itemId"
        role="radio"
        aria-checked="@IsSelected.ToString().ToLower()"
        tabindex="@Tabindex"
        class="@CssClass"
        @onclick="Select"
        @onkeydown="HandleKeyDown"
        @onkeydown:preventDefault="@_preventKey"
        @attributes="AdditionalAttributes">
    @ChildContent
</button>

@inject ComponentInteropService Interop

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

    private readonly string _itemId = $"radio-card-{Guid.NewGuid():N}";
    private bool IsSelected => Context.Value == Value;
    private bool _preventKey;

    private int Tabindex
    {
        get
        {
            if (Context.Value == Value) return 0;
            if (string.IsNullOrEmpty(Context.Value) && Context.ItemValues.FirstOrDefault() == Value) return 0;
            return -1;
        }
    }

    private string CssClass => string.Join(" ", new[] { "flex cursor-pointer rounded-lg border-2 p-4 text-left transition-colors hover:bg-accent focus-visible:outline-none focus-visible:ring-[1.5px] focus-visible:ring-ring focus-visible:ring-offset-2", IsSelected ? "border-primary bg-primary/5" : "border-border", Class }.Where(s => !string.IsNullOrWhiteSpace(s)));

    protected override void OnInitialized()
    {
        if (!Context.ItemValues.Contains(Value))
            Context.ItemValues.Add(Value);
        Context.ItemIds[Value] = _itemId;
    }

    private async Task Select() => await Context.OnSelect.InvokeAsync(Value);

    private async Task HandleKeyDown(KeyboardEventArgs e)
    {
        var items = Context.ItemValues;
        var idx = items.IndexOf(Value);

        string? nextValue = e.Key switch
        {
            "ArrowDown" or "ArrowRight" => idx < items.Count - 1 ? items[idx + 1] : items[0],
            "ArrowUp"   or "ArrowLeft"  => idx > 0 ? items[idx - 1] : items[^1],
            _ => null
        };

        _preventKey = e.Key is "ArrowDown" or "ArrowRight" or "ArrowUp" or "ArrowLeft";

        if (nextValue is not null)
        {
            await Context.OnSelect.InvokeAsync(nextValue);
            if (Context.ItemIds.TryGetValue(nextValue, out var nextId))
            {
                await Interop.FocusElement(nextId);
            }
        }
        else if (e.Key == " ")
        {
            await Select();
        }
    }
}
