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

<div data-slot="datagrid-toolbar" class="@CssClass" @attributes="AdditionalAttributes">
    <div class="@ContentWrapperClass">
        @if (ShowSearch)
        {
            <div class="relative">
                <Blazicon Svg="Lucide.Search" class="absolute left-2.5 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
                <input type="text"
                       placeholder="@L["DataGrid.SearchPlaceholder"]"
                       class="h-8 w-56 rounded-md border border-input bg-transparent pl-8 pr-3 text-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-[1.5px] focus-visible:ring-ring"
                       value="@SearchText"
                       @oninput="OnSearchInput" />
            </div>
        }

        @if (RegisteredContent?.ChildContent is not null)
        {
            @RegisteredContent.ChildContent
        }

        @if (Context is not null)
        {
            @foreach (var filter in Context.Filters)
            {
                <div class="flex items-center gap-1 rounded-full bg-muted px-2.5 py-1 text-xs">
                    <span class="font-medium">@filter.Field</span>
                    <span class="text-muted-foreground">@GetOperatorLabel(filter.Operator)</span>
                    <span>@filter.Value</span>
                    <button type="button"
                            class="ml-1 inline-flex items-center justify-center h-4 w-4 rounded-full hover:bg-muted-foreground/20 focus-visible:outline-none focus-visible:ring-[1.5px] focus-visible:ring-ring focus-visible:ring-offset-1"
                            @onclick="@(() => RemoveFilter(filter))">
                        <Blazicon Svg="Lucide.X" class="h-3 w-3" />
                    </button>
                </div>
            }
        }
    </div>

    @* When the consumer supplies a <ToolbarContent>, they take full control of the
       tools — the default right-hand stack is suppressed to avoid duplicates. Each
       tool inside ToolbarContent renders wherever the consumer places it. *@
    @if (RegisteredContent is null)
    {
        <div class="flex items-center gap-2">
            @* Expand to fullscreen *@
            @if (Expandable)
            {
                <DataGridToolbarFullscreen TItem="TItem" />
            }

            @* Copy selected rows to clipboard *@
            @if (SelectedItems is not null && SelectedItems.Count > 0 && EffectiveColumns is not null)
            {
                <DataGridToolbarCopySelected TItem="TItem" />
            }

            @* Column visibility dropdown *@
            @if (ShowColumnChooser)
            {
                <DataGridToolbarColumns TItem="TItem" />
            }

            @* Export dropdown — hidden when ShowExport=false OR ExportFormats has no flags set. *@
            @if (ShowExport && ExportFormats != DataGridExportFormat.None)
            {
                <DataGridToolbarExport TItem="TItem" />
            }

            @* Layouts dropdown *@
            @if (EnableLayoutPersistence)
            {
                <DataGridToolbarLayouts TItem="TItem" />
            }
        </div>
    }
</div>

@code {
    [CascadingParameter] private DataGridContext<TItem>? Context { get; set; }

    [Parameter] public string? SearchText { get; set; }
    [Parameter] public EventCallback<string> SearchTextChanged { get; set; }

    /// <summary>The <see cref="ToolbarContent{TItem}"/> component the consumer placed
    /// inside the DataGrid, forwarded by the parent grid. When null, the toolbar's left
    /// slot renders just the search + filter chips; when non-null, its Class styles the
    /// wrapper and its ChildContent renders alongside the chips.</summary>
    [Parameter] public ToolbarContent<TItem>? RegisteredContent { get; set; }
    [Parameter] public EventCallback OnColumnVisibilityToggle { get; set; }
    [Parameter] public EventCallback<DataGridColumn<TItem>> OnColumnToggle { get; set; }
    [Parameter] public EventCallback<ColumnReorderEventArgs> OnColumnReorder { get; set; }
    [Parameter] public EventCallback<string> OnExport { get; set; }
    [Parameter] public EventCallback<FilterDescriptor> OnRemoveFilter { get; set; }
    [Parameter] public List<TItem>? SelectedItems { get; set; }
    [Parameter] public List<TItem>? AllItems { get; set; }
    [Parameter] public IReadOnlyList<DataGridColumn<TItem>>? EffectiveColumns { get; set; }
    [Parameter] public bool EnableLayoutPersistence { get; set; }
    [Parameter] public EventCallback OnSaveLayout { get; set; }
    [Parameter] public EventCallback OnResetLayout { get; set; }
    [Parameter] public List<DataGridNamedLayout>? GlobalLayouts { get; set; }
    [Parameter] public EventCallback<DataGridNamedLayout> OnSaveNamedLayout { get; set; }
    [Parameter] public EventCallback<string> OnDeleteNamedLayout { get; set; }
    [Parameter] public EventCallback<DataGridNamedLayout> OnApplyNamedLayout { get; set; }
    [Parameter] public string? LayoutStorageKey { get; set; }
    [Parameter] public EventCallback<Exception> OnError { get; set; }
    [Parameter] public bool Expandable { get; set; }
    [Parameter] public bool IsExpanded { get; set; }
    [Parameter] public EventCallback OnToggleExpanded { get; set; }

    /// <summary>Show the global search box. Default true.</summary>
    [Parameter] public bool ShowSearch { get; set; } = true;

    /// <summary>Show the Columns (visibility/reorder) button. Default true.</summary>
    [Parameter] public bool ShowColumnChooser { get; set; } = true;

    /// <summary>Show the Export dropdown. Default true. Combined with <see cref="ExportFormats"/>.</summary>
    [Parameter] public bool ShowExport { get; set; } = true;

    /// <summary>Which export formats to include in the dropdown. Default <see cref="DataGridExportFormat.All"/>.</summary>
    [Parameter] public DataGridExportFormat ExportFormats { get; set; } = DataGridExportFormat.All;

    [Parameter] public string? Class { get; set; }
    [Parameter(CaptureUnmatchedValues = true)] public Dictionary<string, object>? AdditionalAttributes { get; set; }

    private string CssClass => $"flex items-center gap-2 px-4 py-3 border-b border-border/40 {Class}".Trim();
    private string ContentWrapperClass => $"flex items-center gap-2 flex-1 {RegisteredContent?.Class}".Trim();

    private async Task OnSearchInput(ChangeEventArgs e)
    {
        var value = e.Value?.ToString() ?? "";
        await SearchTextChanged.InvokeAsync(value);
    }

    private async Task RemoveFilter(FilterDescriptor filter)
    {
        await OnRemoveFilter.InvokeAsync(filter);
    }

    private string GetOperatorLabel(FilterOperator op) => op switch
    {
        FilterOperator.Contains => L["Filter.Contains"],
        FilterOperator.NotContains => L["Filter.DoesNotContain"],
        FilterOperator.Equals => "=",
        FilterOperator.NotEquals => "!=",
        FilterOperator.StartsWith => L["Filter.StartsWith"],
        FilterOperator.EndsWith => L["Filter.EndsWith"],
        FilterOperator.GreaterThan => ">",
        FilterOperator.GreaterThanOrEqual => ">=",
        FilterOperator.LessThan => "<",
        FilterOperator.LessThanOrEqual => "<=",
        FilterOperator.IsEmpty => L["Filter.IsEmpty"],
        FilterOperator.IsNotEmpty => L["Filter.IsNotEmpty"],
        FilterOperator.Between => L["Filter.Between"],
        _ => op.ToString()
    };
}
