@namespace Lumeo
@inject Lumeo.Services.Localization.ILumeoLocalizer L

<div class="relative">
    <Blazicon Svg="Lucide.Search" class="absolute start-2.5 top-2.5 h-4 w-4 text-muted-foreground" />
    <input type="text"
           role="combobox"
           aria-haspopup="listbox"
           aria-expanded="@Context.IsOpen.ToString().ToLower()"
           aria-controls="@Context.ContentId"
           aria-autocomplete="list"
           aria-activedescendant="@(Context.IsOpen ? Context.FocusedItemId : null)"
           class="@CssClass"
           placeholder="@(Placeholder ?? L["Combobox.SearchPlaceholder"])"
           value="@Context.SearchText"
           @oninput="HandleInput"
           @onfocus="Open"
           @onkeydown="HandleKeyDown"
           @attributes="AdditionalAttributes" />
</div>

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

    private string CssClass => $"flex h-9 w-full rounded-md border {(Context.Invalid ? "border-destructive" : "border-input")} bg-transparent py-2 ps-8 pe-3 text-sm placeholder:text-muted-foreground focus-visible:outline-none {(Context.Invalid ? "focus-visible:ring-[1.5px] focus-visible:ring-destructive/20" : "")} {Class}".Trim();

    private async Task HandleInput(ChangeEventArgs e)
    {
        var text = e.Value?.ToString() ?? "";
        await Context.OnSearch.InvokeAsync(text);
        if (!Context.IsOpen)
        {
            await Context.SetOpen.InvokeAsync(true);
        }
    }

    private async Task Open()
    {
        if (!Context.IsOpen)
        {
            await Context.SetOpen.InvokeAsync(true);
        }
    }

    private async Task HandleKeyDown(KeyboardEventArgs e)
    {
        switch (e.Key)
        {
            case "ArrowDown":
                if (!Context.IsOpen)
                    await Context.SetOpen.InvokeAsync(true);
                else
                    await Context.SetFocusedIndex.InvokeAsync(Context.FocusedIndex + 1);
                break;
            case "ArrowUp":
                if (Context.IsOpen)
                    await Context.SetFocusedIndex.InvokeAsync(Context.FocusedIndex > 0 ? Context.FocusedIndex - 1 : 0);
                break;
            case "Home":
                if (Context.IsOpen)
                    await Context.SetFocusedIndex.InvokeAsync(0);
                break;
            case "End":
                if (Context.IsOpen)
                    await Context.SetFocusedIndex.InvokeAsync(int.MaxValue);
                break;
            case "Enter":
                if (Context.IsOpen && Context.FocusedItemValue is not null)
                    await Context.OnSelect.InvokeAsync(Context.FocusedItemValue);
                break;
            case "Escape":
                await Context.SetOpen.InvokeAsync(false);
                break;
        }
    }
}
