@namespace Lumeo

@if (!string.IsNullOrEmpty(Description))
{
    <div class="flex items-start gap-2">
        <button type="button"
                id="@_itemId"
                role="radio"
                aria-checked="@IsSelected.ToString().ToLower()"
                tabindex="@Tabindex"
                class="@CssClass"
                @onclick="Select"
                @onkeydown="HandleKeyDown"
                @onkeydown:preventDefault="@_preventKey"
                disabled="@Disabled"
                @attributes="AdditionalAttributes">
            @if (IsSelected)
            {
                <span class="flex h-2 w-2 rounded-full bg-current"></span>
            }
        </button>
        <div class="grid gap-0.5 leading-none">
            @if (ChildContent is not null)
            {
                @ChildContent
            }
            <p class="text-xs text-muted-foreground mt-0.5">@Description</p>
        </div>
    </div>
}
else
{
    <button type="button"
            id="@_itemId"
            role="radio"
            aria-checked="@IsSelected.ToString().ToLower()"
            tabindex="@Tabindex"
            class="@CssClass"
            @onclick="Select"
            @onkeydown="HandleKeyDown"
            @onkeydown:preventDefault="@_preventKey"
            disabled="@Disabled"
            @attributes="AdditionalAttributes">
        @if (IsSelected)
        {
            <span class="flex h-2 w-2 rounded-full bg-current"></span>
        }
    </button>
}

@inject ComponentInteropService Interop

@code {
    [CascadingParameter] public RadioGroup.RadioGroupContext Context { get; set; } = default!;
    [Parameter, EditorRequired] public string Value { get; set; } = "";
    [Parameter] public bool Disabled { get; set; }
    [Parameter] public string? Description { 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 readonly string _itemId = $"radio-{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 => $"aspect-square h-4 w-4 shrink-0 cursor-pointer rounded-full border border-primary text-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 flex items-center justify-center {Class}".Trim();

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

    private async Task Select()
    {
        if (!Disabled)
        {
            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 && !Disabled)
        {
            await Context.OnSelect.InvokeAsync(nextValue);
            if (Context.ItemIds.TryGetValue(nextValue, out var nextId))
            {
                await Interop.FocusElement(nextId);
            }
        }
        else if (e.Key == " ")
        {
            await Select();
        }
    }
}
