@page "/components/combobox"

<PageTitle>Combobox — Lumeo</PageTitle>

<PageHeader Title="Combobox" Description="An autocomplete input with a filterable dropdown list." />

<Stack Gap="8">
    <ComponentDemo Title="Default" Code="@_defaultCode">
        <Container MaxWidth="xs" Center="false" Padding="">
            <Combobox @bind-Value="_selectedFramework" @bind-Open="_isOpen1">
                <ComboboxInput Placeholder="Search frameworks..." />
                <ComboboxContent>
                    @foreach (var fw in _frameworks.Where(f => string.IsNullOrEmpty(_searchText1) || f.Label.Contains(_searchText1, StringComparison.OrdinalIgnoreCase)))
                    {
                        <ComboboxItem Value="@fw.Value">@fw.Label</ComboboxItem>
                    }
                    <ComboboxEmpty>No framework found.</ComboboxEmpty>
                </ComboboxContent>
            </Combobox>
            @if (!string.IsNullOrEmpty(_selectedFramework))
            {
                <Lumeo.Text Size="sm" Color="muted" Class="mt-2">Selected: @_selectedFramework</Lumeo.Text>
            }
        </Container>
    </ComponentDemo>

    <ComponentDemo Title="Country Selector" Code="@_countryCode">
        <Stack Gap="2" Class="w-full max-w-xs">
            <Label>Country</Label>
            <Combobox @bind-Value="_selectedCountry" @bind-Open="_isOpen3">
                <ComboboxInput Placeholder="Search countries..." />
                <ComboboxContent>
                    @foreach (var country in _countries)
                    {
                        <ComboboxItem Value="@country">@country</ComboboxItem>
                    }
                    <ComboboxEmpty>No country found.</ComboboxEmpty>
                </ComboboxContent>
            </Combobox>
            @if (!string.IsNullOrEmpty(_selectedCountry))
            {
                <Lumeo.Text Size="sm" Color="muted">Selected: @_selectedCountry</Lumeo.Text>
            }
        </Stack>
    </ComponentDemo>

    <ComponentDemo Title="With Label" Code="@_labelCode">
        <Stack Gap="2" Class="w-full max-w-xs">
            <Label>Language</Label>
            <Combobox @bind-Value="_selectedLanguage" @bind-Open="_isOpen2">
                <ComboboxInput Placeholder="Search languages..." />
                <ComboboxContent>
                    @foreach (var lang in _languages)
                    {
                        <ComboboxItem Value="@lang">@lang</ComboboxItem>
                    }
                    <ComboboxEmpty>No language found.</ComboboxEmpty>
                </ComboboxContent>
            </Combobox>
        </Stack>
    </ComponentDemo>

    <ComponentDemo Title="Multiple Selection" Code="@_multipleCode">
        <Stack Gap="2" Class="w-full max-w-sm">
            <Combobox Multiple="true" @bind-Values="_selectedFrameworks" @bind-Open="_isOpenMulti">
                <ComboboxInput Placeholder="Select frameworks..." />
                <ComboboxContent>
                    <ComboboxItem Value="react">React</ComboboxItem>
                    <ComboboxItem Value="vue">Vue</ComboboxItem>
                    <ComboboxItem Value="angular">Angular</ComboboxItem>
                    <ComboboxItem Value="svelte">Svelte</ComboboxItem>
                    <ComboboxItem Value="blazor">Blazor</ComboboxItem>
                </ComboboxContent>
            </Combobox>
            <Lumeo.Text Size="sm" Color="muted">Selected: @(_selectedFrameworks.Count == 0 ? "none" : string.Join(", ", _selectedFrameworks))</Lumeo.Text>
        </Stack>
    </ComponentDemo>

    <ComponentDemo Title="Async Search" Code="@_asyncCode">
        <Container MaxWidth="sm" Center="false" Padding="">
            <Combobox @bind-Open="_isOpenAsync" OnSearchAsync="@HandleSearchAsync" IsSearchLoading="@_isSearching">
                <ComboboxInput Placeholder="Search users..." />
                <ComboboxContent>
                    @foreach (var user in _searchResults)
                    {
                        <ComboboxItem Value="@user">@user</ComboboxItem>
                    }
                    <ComboboxEmpty>Type to search users.</ComboboxEmpty>
                </ComboboxContent>
            </Combobox>
        </Container>
    </ComponentDemo>
</Stack>

@code {
    private string? _selectedFramework;
    private string? _selectedLanguage;
    private string? _selectedCountry;
    private bool _isOpen1;
    private bool _isOpen2;
    private bool _isOpen3;
    private bool _isOpenMulti;
    private bool _isOpenAsync;
    private string _searchText1 = "";
    private HashSet<string> _selectedFrameworks = new();
    private bool _isSearching;
    private List<string> _searchResults = new();

    private readonly string[] _countries = ["Australia", "Canada", "France", "Germany", "India", "Japan", "Netherlands", "United Kingdom", "United States"];

    private record FrameworkOption(string Value, string Label);

    private readonly FrameworkOption[] _frameworks =
    [
        new("blazor", "Blazor"),
        new("react", "React"),
        new("vue", "Vue.js"),
        new("angular", "Angular"),
        new("svelte", "Svelte"),
    ];

    private readonly string[] _languages = ["C#", "TypeScript", "Python", "Rust", "Go"];

    private string _defaultCode = @"<Combobox @bind-Value=""_selected"" @bind-Open=""_isOpen"">
    <ComboboxInput Placeholder=""Search frameworks..."" />
    <ComboboxContent>
        <ComboboxItem Value=""blazor"">Blazor</ComboboxItem>
        <ComboboxItem Value=""react"">React</ComboboxItem>
        <ComboboxItem Value=""vue"">Vue.js</ComboboxItem>
        <ComboboxEmpty>No framework found.</ComboboxEmpty>
    </ComboboxContent>
</Combobox>";

    private string _countryCode = @"<Label>Country</Label>
<Combobox @bind-Value=""_selected"" @bind-Open=""_isOpen"">
    <ComboboxInput Placeholder=""Search countries..."" />
    <ComboboxContent>
        <ComboboxItem Value=""Australia"">Australia</ComboboxItem>
        <ComboboxItem Value=""Canada"">Canada</ComboboxItem>
        <ComboboxItem Value=""France"">France</ComboboxItem>
        <ComboboxItem Value=""United Kingdom"">United Kingdom</ComboboxItem>
        <ComboboxItem Value=""United States"">United States</ComboboxItem>
        <ComboboxEmpty>No country found.</ComboboxEmpty>
    </ComboboxContent>
</Combobox>";

    private string _labelCode = @"<Label>Language</Label>
<Combobox @bind-Value=""_selected"" @bind-Open=""_isOpen"">
    <ComboboxInput Placeholder=""Search languages..."" />
    <ComboboxContent>
        <ComboboxItem Value=""C#"">C#</ComboboxItem>
        <ComboboxItem Value=""TypeScript"">TypeScript</ComboboxItem>
        <ComboboxEmpty>No language found.</ComboboxEmpty>
    </ComboboxContent>
</Combobox>";

    private async Task HandleSearchAsync(string query)
    {
        _isSearching = true;
        await Task.Delay(500);
        var allUsers = new[] { "alice@example.com", "bob@example.com", "carol@example.com", "dave@example.com", "eve@example.com" };
        _searchResults = allUsers.Where(u => u.Contains(query, StringComparison.OrdinalIgnoreCase)).ToList();
        _isSearching = false;
    }

    private string _multipleCode = @"<Combobox Multiple=""true"" @bind-Values=""_selectedFrameworks"" @bind-Open=""_isOpen"">
    <ComboboxInput Placeholder=""Select frameworks..."" />
    <ComboboxContent>
        <ComboboxItem Value=""react"">React</ComboboxItem>
        <ComboboxItem Value=""vue"">Vue</ComboboxItem>
        <ComboboxItem Value=""angular"">Angular</ComboboxItem>
        <ComboboxItem Value=""svelte"">Svelte</ComboboxItem>
        <ComboboxItem Value=""blazor"">Blazor</ComboboxItem>
    </ComboboxContent>
</Combobox>

@code {
    private HashSet<string> _selectedFrameworks = new();
    private bool _isOpen;
}";

    private string _asyncCode = @"<Combobox @bind-Open=""_isOpen"" OnSearchAsync=""@HandleSearchAsync"" IsSearchLoading=""@_isSearching"">
    <ComboboxInput Placeholder=""Search users..."" />
    <ComboboxContent>
        @foreach (var user in _searchResults)
        {
            <ComboboxItem Value=""@user"">@user</ComboboxItem>
        }
        <ComboboxEmpty>Type to search users.</ComboboxEmpty>
    </ComboboxContent>
</Combobox>

@code {
    private bool _isOpen;
    private bool _isSearching;
    private List<string> _searchResults = new();

    private async Task HandleSearchAsync(string query)
    {
        _isSearching = true;
        await Task.Delay(500); // simulate API call
        _searchResults = /* filter results */;
        _isSearching = false;
    }
}";
}

<!-- API Reference -->
<Stack Gap="6" Class="mt-12">
    <Heading Level="2">API Reference</Heading>

    <Stack Gap="8">
        <Stack Gap="3">
            <Heading Level="3">Combobox</Heading>
            <Stack Class="rounded-lg border border-border/40 overflow-x-auto">
                <table class="w-full min-w-[600px] text-sm">
                    <thead>
                        <tr class="border-b border-border/40 bg-muted/40">
                            <th class="text-left p-3 font-medium text-foreground">Property</th>
                            <th class="text-left p-3 font-medium text-foreground">Type</th>
                            <th class="text-left p-3 font-medium text-foreground">Default</th>
                            <th class="text-left p-3 font-medium text-foreground">Description</th>
                        </tr>
                    </thead>
                    <tbody class="divide-y divide-border/40">
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">Value</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">string?</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">null</td>
                            <td class="p-3 text-muted-foreground">The currently selected value. Use with @@bind-Value for two-way binding.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">ValueChanged</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">EventCallback&lt;string&gt;</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">—</td>
                            <td class="p-3 text-muted-foreground">Callback invoked when the selected value changes.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">Open</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">bool</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">false</td>
                            <td class="p-3 text-muted-foreground">Controls whether the dropdown is open. Use with @@bind-Open for two-way binding.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">OpenChanged</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">EventCallback&lt;bool&gt;</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">—</td>
                            <td class="p-3 text-muted-foreground">Callback invoked when the open state changes.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">Required</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">bool</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">false</td>
                            <td class="p-3 text-muted-foreground">Marks the field as required. Syncs with a parent FormField.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">Invalid</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">bool</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">false</td>
                            <td class="p-3 text-muted-foreground">Applies error styling. Syncs with a parent FormField.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">ErrorText</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">string?</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">null</td>
                            <td class="p-3 text-muted-foreground">Error message displayed below the field when Invalid is true.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">HelperText</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">string?</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">null</td>
                            <td class="p-3 text-muted-foreground">Helper text shown below the field when not invalid.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">Label</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">string?</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">null</td>
                            <td class="p-3 text-muted-foreground">Label rendered above the field (standalone, without FormField).</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">Name</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">string?</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">null</td>
                            <td class="p-3 text-muted-foreground">HTML name attribute for form submission.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">FormField</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">FormField.FormFieldContext?</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">null</td>
                            <td class="p-3 text-muted-foreground">Cascaded context from a parent FormField; wires label, validation, and required state automatically.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">IsOpen</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">bool</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">false</td>
                            <td class="p-3 text-muted-foreground">Obsolete alias for <code class="rounded bg-muted px-1 py-0.5 text-xs font-mono">Open</code>; forwards to and from it.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">IsOpenChanged</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">EventCallback&lt;bool&gt;</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">—</td>
                            <td class="p-3 text-muted-foreground">Obsolete alias for <code class="rounded bg-muted px-1 py-0.5 text-xs font-mono">OpenChanged</code>; forwards to and from it.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">Items</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">IEnumerable&lt;object&gt;?</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">null</td>
                            <td class="p-3 text-muted-foreground">Optional data source. When set, ComboboxContent renders options from this list instead of ChildContent.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">ItemTemplate</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">RenderFragment&lt;object&gt;?</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">null</td>
                            <td class="p-3 text-muted-foreground">Optional custom render fragment for an item's content. Receives the raw item object.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">Virtualize</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">bool</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">false</td>
                            <td class="p-3 text-muted-foreground">When true and Items is set, uses Blazor's Virtualize component for the option list.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">ItemSize</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">float</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">36f</td>
                            <td class="p-3 text-muted-foreground">Estimated pixel height of each option row used by the Virtualize component.</td>
                        </tr>
                    </tbody>
                </table>
            </Stack>
        </Stack>

        <Stack Gap="3">
            <Heading Level="3">ComboboxInput</Heading>
            <Stack Class="rounded-lg border border-border/40 overflow-x-auto">
                <table class="w-full min-w-[600px] text-sm">
                    <thead>
                        <tr class="border-b border-border/40 bg-muted/40">
                            <th class="text-left p-3 font-medium text-foreground">Property</th>
                            <th class="text-left p-3 font-medium text-foreground">Type</th>
                            <th class="text-left p-3 font-medium text-foreground">Default</th>
                            <th class="text-left p-3 font-medium text-foreground">Description</th>
                        </tr>
                    </thead>
                    <tbody class="divide-y divide-border/40">
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">Placeholder</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">string</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">"Search..."</td>
                            <td class="p-3 text-muted-foreground">Placeholder text shown in the search input when empty.</td>
                        </tr>
                    </tbody>
                </table>
            </Stack>
        </Stack>

        <Stack Gap="3">
            <Heading Level="3">ComboboxItem</Heading>
            <Stack Class="rounded-lg border border-border/40 overflow-x-auto">
                <table class="w-full min-w-[600px] text-sm">
                    <thead>
                        <tr class="border-b border-border/40 bg-muted/40">
                            <th class="text-left p-3 font-medium text-foreground">Property</th>
                            <th class="text-left p-3 font-medium text-foreground">Type</th>
                            <th class="text-left p-3 font-medium text-foreground">Default</th>
                            <th class="text-left p-3 font-medium text-foreground">Description</th>
                        </tr>
                    </thead>
                    <tbody class="divide-y divide-border/40">
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">Value</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">string</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">""</td>
                            <td class="p-3 text-muted-foreground">The value this item represents when selected. Required. Also used for filtering against the search text.</td>
                        </tr>
                    </tbody>
                </table>
            </Stack>
        </Stack>

        <Stack Gap="3">
            <Heading Level="3">Combobox — Additional Props</Heading>
            <Stack Class="rounded-lg border border-border/40 overflow-x-auto">
                <table class="w-full min-w-[600px] text-sm">
                    <thead>
                        <tr class="border-b border-border/40 bg-muted/40">
                            <th class="text-left p-3 font-medium text-foreground">Property</th>
                            <th class="text-left p-3 font-medium text-foreground">Type</th>
                            <th class="text-left p-3 font-medium text-foreground">Default</th>
                            <th class="text-left p-3 font-medium text-foreground">Description</th>
                        </tr>
                    </thead>
                    <tbody class="divide-y divide-border/40">
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">Multiple</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">bool</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">false</td>
                            <td class="p-3 text-muted-foreground">When true, allows selecting multiple values at once.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">Values</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">HashSet&lt;string&gt;</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">new()</td>
                            <td class="p-3 text-muted-foreground">The set of selected values when Multiple is true. Use with @@bind-Values.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">OnSearchAsync</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">EventCallback&lt;string&gt;</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">—</td>
                            <td class="p-3 text-muted-foreground">Callback invoked (debounced) when the search query changes, enabling server-side filtering.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">DebounceMs</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">int</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">300</td>
                            <td class="p-3 text-muted-foreground">Milliseconds to debounce the OnSearchAsync callback.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">IsSearchLoading</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">bool</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">false</td>
                            <td class="p-3 text-muted-foreground">When true, shows a loading indicator inside the dropdown.</td>
                        </tr>
                        <tr><td class="p-3 font-mono text-xs text-primary">ValuesChanged</td><td class="p-3 font-mono text-xs text-muted-foreground">EventCallback&lt;HashSet&lt;string&gt;&gt;</td><td class="p-3 font-mono text-xs text-muted-foreground">—</td><td class="p-3 text-muted-foreground">Two-way binding callback for the multi-select values set.</td></tr>
                        <tr><td class="p-3 font-mono text-xs text-primary">Creatable</td><td class="p-3 font-mono text-xs text-muted-foreground">bool</td><td class="p-3 font-mono text-xs text-muted-foreground">false</td><td class="p-3 text-muted-foreground">When true, users can create new values that are not in the list.</td></tr>
                        <tr><td class="p-3 font-mono text-xs text-primary">OnCreate</td><td class="p-3 font-mono text-xs text-muted-foreground">EventCallback&lt;string&gt;</td><td class="p-3 font-mono text-xs text-muted-foreground">—</td><td class="p-3 text-muted-foreground">Invoked when the user creates a new value via the create affordance.</td></tr>
                        <tr><td class="p-3 font-mono text-xs text-primary">EmptyText</td><td class="p-3 font-mono text-xs text-muted-foreground">string?</td><td class="p-3 font-mono text-xs text-muted-foreground">null</td><td class="p-3 text-muted-foreground">ComboboxContent — text shown when no items match. Defaults to "No results".</td></tr>
                        <tr><td class="p-3 font-mono text-xs text-primary">ShowCreate</td><td class="p-3 font-mono text-xs text-muted-foreground">bool</td><td class="p-3 font-mono text-xs text-muted-foreground">false</td><td class="p-3 text-muted-foreground">ComboboxCreate — toggles the "create new" item visibility.</td></tr>
                    </tbody>
                </table>
            </Stack>
        </Stack>
    </Stack>
</Stack>
