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

<button type="button" id="@_triggerId"
        role="combobox"
        aria-haspopup="listbox"
        aria-expanded="@Context.IsOpen.ToString().ToLower()"
        aria-controls="@Context.ContentId"
        aria-activedescendant="@(Context.IsOpen ? Context.FocusedItemId : null)"
        class="@CssClass"
        disabled="@Context.Disabled"
        @onclick="Toggle"
        @onkeydown="HandleKeyDown"
        @attributes="AdditionalAttributes">
    @if (Context.Multiple && Context.Values != null && Context.Values.Count > 0)
    {
        <div class="flex flex-wrap gap-1 items-center flex-1 min-w-0">
            @{
                var displayed = Context.Values.Take(Context.MaxDisplayTags).ToList();
                var remaining = Context.Values.Count - Context.MaxDisplayTags;
            }
            @foreach (var val in displayed)
            {
                <span class="inline-flex items-center gap-1 rounded-md border border-border/40 bg-secondary px-1.5 py-0.5 text-xs font-medium text-secondary-foreground">
                    @val
                    <button type="button" class="cursor-pointer rounded-full hover:bg-foreground/20 focus-visible:outline-none focus-visible:ring-[1.5px] focus-visible:ring-ring focus-visible:ring-offset-1" aria-label="@($"Remove {val}")" @onclick="() => RemoveValue(val)" @onclick:stopPropagation="true">
                        <Blazicon Svg="Lucide.X" class="h-3 w-3" />
                    </button>
                </span>
            }
            @if (remaining > 0)
            {
                <span class="text-xs text-muted-foreground">+@remaining more</span>
            }
        </div>
    }
    else if (HasValue)
    {
        @ChildContent
    }
    else
    {
        <span class="text-muted-foreground">@(Placeholder ?? L["Select.Placeholder"])</span>
    }

    <div class="flex items-center gap-1 ms-auto shrink-0">
        @if (Context.Clearable && HasValue)
        {
            <button type="button" class="cursor-pointer hover:text-foreground focus-visible:outline-none focus-visible:ring-[1.5px] focus-visible:ring-ring focus-visible:ring-offset-1 rounded" aria-label="@L["Select.ClearSelection"]" @onclick="HandleClear" @onclick:stopPropagation="true">
                <Blazicon Svg="Lucide.X" class="h-3.5 w-3.5 opacity-50 hover:opacity-100" />
            </button>
        }
        <Blazicon Svg="Lucide.ChevronDown" class="@($"h-4 w-4 shrink-0 opacity-50 transition-transform duration-200 {(Context.IsOpen ? "rotate-180" : "")}")" />
    </div>
</button>

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

    private readonly string _triggerId = $"select-trigger-{Guid.NewGuid():N}";

    private bool HasValue => Context.Multiple
        ? Context.Values != null && Context.Values.Count > 0
        : !string.IsNullOrEmpty(Context.Value);

    private string CssClass => $"flex h-9 w-full cursor-pointer items-center justify-between whitespace-nowrap rounded-md border {(Context.Invalid ? "border-destructive" : "border-input")} bg-transparent px-3 py-2 text-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 {(Context.Invalid ? "focus-visible:ring-destructive/20" : "focus-visible:ring-ring")} focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 {Class}".Trim();

    private async Task Toggle() => await Context.SetOpen.InvokeAsync(!Context.IsOpen);

    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.SetOpen.InvokeAsync(true);
                else
                    await Context.SetFocusedIndex.InvokeAsync(Context.FocusedIndex > 0 ? Context.FocusedIndex - 1 : 0);
                break;
            case "Enter":
            case " ":
                if (!Context.IsOpen)
                    await Context.SetOpen.InvokeAsync(true);
                else if (Context.FocusedItemValue is not null)
                    await Context.OnSelect.InvokeAsync(Context.FocusedItemValue);
                break;
            case "Escape":
                await Context.SetOpen.InvokeAsync(false);
                break;
            case "Home":
                if (Context.IsOpen)
                    await Context.SetFocusedIndex.InvokeAsync(0);
                break;
            case "End":
                if (Context.IsOpen)
                    await Context.SetFocusedIndex.InvokeAsync(int.MaxValue);
                break;
        }
    }

    private async Task RemoveValue(string value)
    {
        await Context.OnSelect.InvokeAsync(value);
    }

    private async Task HandleClear()
    {
        await Context.OnClear.InvokeAsync();
    }
}
