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

@if (Context is not null && Context.IsLoading)
{
    <tbody data-slot="datagrid-body" class="@CssClass" @attributes="AdditionalAttributes">
        @{
            // Context.VisibleColumns is already filtered + cached at the grid level.
            var visibleColumns = Context.VisibleColumns;
            var fallbackCellCount = visibleColumns.Count > 0 ? visibleColumns.Count : (SkeletonRowCount > 0 ? 4 : 4);
        }
        @for (var i = 0; i < SkeletonRowCount; i++)
        {
            <tr class="border-b border-border/40">
                @if (Context.SelectionMode != DataGridSelectionMode.None)
                {
                    <td class="px-3 py-2 w-10">
                        <Skeleton Class="h-4 w-4 rounded" />
                    </td>
                }
                @if (HasDetailTemplate)
                {
                    <td class="px-1 py-2 w-8">
                        <Skeleton Class="h-4 w-4 rounded" />
                    </td>
                }
                @if (visibleColumns.Count > 0)
                {
                    @foreach (var column in visibleColumns)
                    {
                        <td class="px-3 py-2">
                            <Skeleton Class="h-4 w-full rounded" />
                        </td>
                    }
                }
                else
                {
                    @for (var j = 0; j < fallbackCellCount; j++)
                    {
                        <td class="px-3 py-2">
                            <Skeleton Class="h-4 w-full rounded" />
                        </td>
                    }
                }
            </tr>
        }
    </tbody>
}
else if (Context is not null && Context.IsTreeGrid)
{
    <tbody data-slot="datagrid-body" class="@CssClass" @attributes="AdditionalAttributes">
        @if (Context.DisplayedItems.Count == 0)
        {
            <tr>
                <td colspan="@ColSpan" class="px-3 py-8 text-center text-muted-foreground">
                    @if (EmptyContent is not null) { @EmptyContent }
                    else
                    {
                        <div class="flex flex-col items-center gap-2">
                            <Blazicon Svg="Lucide.Inbox" class="h-8 w-8 text-muted-foreground/50" />
                            <span class="text-sm">@L["DataGrid.NoData"]</span>
                        </div>
                    }
                </td>
            </tr>
        }
        else
        {
            var ti = 0;
            foreach (var item in Context.DisplayedItems)
            {
                <DataGridRow @key="item" TItem="TItem"
                             Item="item"
                             RowIndex="ti"
                             DetailTemplate="DetailTemplate"
                             OnContextMenu="OnContextMenu" />
                ti++;
            }
        }
    </tbody>
}
else if (Context is not null && Context.GroupTree is not null && Context.GroupTree.Count > 0)
{
    // Multi-level grouping: render a nested forest of group rows.
    RenderFragment<DataGridGroupNode<TItem>>? renderNode = null;
    renderNode = node => __builder =>
    {
        var expanded = Context.IsGroupPathExpanded(node.Path);
        <DataGridGroupRow @key="@("g:" + node.Path)" TItem="TItem"
                          GroupKey="@node.Key"
                          Count="@node.TotalCount"
                          Level="@node.Level"
                          IsExpanded="@expanded"
                          Aggregates="@node.Aggregates"
                          ColSpan="@ColSpan"
                          OnToggle="@(() => Context.ToggleGroupPath(node.Path))" />
        if (expanded)
        {
            if (node.Children.Count > 0)
            {
                foreach (var child in node.Children)
                {
                    @renderNode!(child)
                }
            }
            else
            {
                var li = 0;
                foreach (var item in node.Items)
                {
                    <DataGridRow @key="item" TItem="TItem"
                                 Item="item"
                                 RowIndex="li"
                                 DetailTemplate="DetailTemplate"
                                 OnContextMenu="OnContextMenu" />
                    li++;
                }
            }
        }
    };
    <tbody data-slot="datagrid-body" class="@CssClass" @attributes="AdditionalAttributes">
        @foreach (var root in Context.GroupTree)
        {
            @renderNode(root)
        }
    </tbody>
}
else if (Context is not null && Context.IsGrouped && Context.GroupedSections is not null && Context.GroupedSections.Count > 0)
{
    <tbody data-slot="datagrid-body" class="@CssClass" @attributes="AdditionalAttributes">
        @foreach (var grp in Context.GroupedSections)
        {
            var groupKey = grp.Key;
            var expanded = Context.IsGroupExpanded(groupKey);
            <DataGridGroupRow @key="groupKey" TItem="TItem"
                              GroupKey="@groupKey"
                              Count="@grp.TotalCount"
                              IsExpanded="@expanded"
                              Aggregates="@grp.Aggregates"
                              ColSpan="@ColSpan"
                              OnToggle="@(() => Context.ToggleGroupExpand(groupKey))" />
            if (expanded)
            {
                var grpIndex = 0;
                foreach (var item in grp.Items)
                {
                    <DataGridRow @key="item" TItem="TItem"
                                 Item="item"
                                 RowIndex="grpIndex"
                                 DetailTemplate="DetailTemplate"
                                 OnContextMenu="OnContextMenu" />
                    grpIndex++;
                }
            }
        }
    </tbody>
}
else if (Context is not null && Context.DisplayedItems.Count == 0)
{
    <tbody data-slot="datagrid-body" class="@CssClass" @attributes="AdditionalAttributes">
        <tr>
            <td colspan="@ColSpan" class="px-3 py-8 text-center text-muted-foreground">
                @if (EmptyContent is not null)
                {
                    @EmptyContent
                }
                else
                {
                    <div class="flex flex-col items-center gap-2">
                        <Blazicon Svg="Lucide.Inbox" class="h-8 w-8 text-muted-foreground/50" />
                        <span class="text-sm">@L["DataGrid.NoData"]</span>
                    </div>
                }
            </td>
        </tr>
    </tbody>
}
else if (Context is not null && ServerVirtualizationProvider is not null)
{
    @* Virtualised server mode: rows are fetched in scroll-driven windows
       via ItemsProvider, so the in-memory list is empty until the user
       scrolls. SpacerElement="tr" is non-negotiable inside <tbody>. *@
    <tbody data-slot="datagrid-body" class="@CssClass" @attributes="AdditionalAttributes">
        <Virtualize @ref="_virtualize" TItem="IndexedItem"
                    ItemsProvider="ServerVirtualizationProvider"
                    Context="entry"
                    SpacerElement="tr"
                    ItemSize="@VirtualItemSize"
                    OverscanCount="@VirtualOverscanCount">
            <ItemContent>
                <DataGridRow TItem="TItem"
                             Item="entry.Item"
                             RowIndex="entry.Index"
                             DetailTemplate="DetailTemplate"
                             OnContextMenu="OnContextMenu" />
            </ItemContent>
            <Placeholder>
                <tr class="border-b border-border/40">
                    <td colspan="@ColSpan" class="px-3 py-2">
                        <Skeleton Class="h-4 w-full rounded" />
                    </td>
                </tr>
            </Placeholder>
        </Virtualize>
    </tbody>
}
else if (Context is not null && UseVirtualization)
{
    <tbody data-slot="datagrid-body" class="@CssClass" @attributes="AdditionalAttributes">
        @* SpacerElement="tr" is required: <Virtualize> defaults to <div>
           spacers, but <div> is invalid as a direct child of <tbody> and the
           browser hoists it out of the table, breaking layout. *@
        <Virtualize Items="@_indexedItems" Context="entry"
                    SpacerElement="tr"
                    ItemSize="@VirtualItemSize"
                    OverscanCount="@VirtualOverscanCount">
            <DataGridRow TItem="TItem"
                         Item="entry.Item"
                         RowIndex="entry.Index"
                         DetailTemplate="DetailTemplate"
                         OnContextMenu="OnContextMenu" />
        </Virtualize>
    </tbody>
}
else if (Context is not null)
{
    <tbody data-slot="datagrid-body" class="@CssClass" @attributes="AdditionalAttributes">
        @if (Context.IsGrouped && Context.GroupedSections is not null)
        {
            @foreach (var grp in Context.GroupedSections)
            {
                var groupKey = grp.Key;
                var expanded = Context.IsGroupExpanded(groupKey);
                <DataGridGroupRow @key="groupKey" TItem="TItem"
                                  GroupKey="@groupKey"
                                  Count="@grp.TotalCount"
                                  IsExpanded="@expanded"
                                  ColSpan="@ColSpan"
                                  OnToggle="@(() => Context.ToggleGroupExpand(groupKey))" />
                if (expanded)
                {
                    var grpIndex = 0;
                    foreach (var item in grp.Items)
                    {
                        <DataGridRow @key="item" TItem="TItem"
                                     Item="item"
                                     RowIndex="grpIndex"
                                     DetailTemplate="DetailTemplate"
                                     OnContextMenu="OnContextMenu" />
                        grpIndex++;
                    }
                }
            }
        }
        else
        {
            var idx = 0;
            foreach (var item in Context.DisplayedItems)
            {
                <DataGridRow @key="item" TItem="TItem"
                             Item="item"
                             RowIndex="idx"
                             DetailTemplate="DetailTemplate"
                             OnContextMenu="OnContextMenu" />
                idx++;
            }
        }
    </tbody>
}

@code {
    [CascadingParameter] private DataGridContext<TItem>? Context { get; set; }
    [Parameter] public RenderFragment<TItem>? DetailTemplate { get; set; }
    [Parameter] public RenderFragment? EmptyContent { get; set; }
    [Parameter] public bool UseVirtualization { get; set; }
    [Parameter] public float VirtualItemSize { get; set; } = 41f;
    [Parameter] public int VirtualOverscanCount { get; set; } = 3;
    /// <summary>When set, switches the body to ItemsProvider-mode
    /// virtualisation (window-fetched server scrolling). Null disables.</summary>
    [Parameter] public Microsoft.AspNetCore.Components.Web.Virtualization.ItemsProviderDelegate<IndexedItem>? ServerVirtualizationProvider { get; set; }
    [Parameter] public bool HasDetailTemplate { get; set; }
    [Parameter] public int SkeletonRowCount { get; set; } = 5;
    [Parameter] public EventCallback<(TItem, double, double)> OnContextMenu { get; set; }
    [Parameter] public string? Class { get; set; }
    [Parameter(CaptureUnmatchedValues = true)] public Dictionary<string, object>? AdditionalAttributes { get; set; }

    private string CssClass => $"{Class}".Trim();

    private List<IndexedItem> _indexedItems = new();
    private Microsoft.AspNetCore.Components.Web.Virtualization.Virtualize<IndexedItem>? _virtualize;

    /// <summary>Tells the inner <c>Virtualize</c> component to discard its
    /// window cache and refetch via <see cref="ServerVirtualizationProvider"/>.
    /// No-op when not in ItemsProvider mode (no virtualizer in tree).</summary>
    public Task RefreshVirtualizeAsync() =>
        _virtualize is not null ? _virtualize.RefreshDataAsync() : Task.CompletedTask;

    protected override void OnParametersSet()
    {
        if (UseVirtualization && Context is not null)
        {
            _indexedItems = Context.DisplayedItems
                .Select((item, idx) => new IndexedItem(item, idx))
                .ToList();
        }
    }

    private int ColSpan
    {
        get
        {
            var count = Context?.VisibleColumns.Count ?? 1;
            if (Context?.SelectionMode != DataGridSelectionMode.None) count++;
            if (HasDetailTemplate) count++;
            return count;
        }
    }

    public record IndexedItem(TItem Item, int Index);
}
