@namespace OpenArchival.Blazor.AdminPages
@using Microsoft.AspNetCore.Components.Web
@using MudBlazor
@using MudExtensions
@using OpenArchival.Blazor.ArchiveDisplay
@using OpenArchival.DataAccess
@using OpenArchival.Blazor.AdminPages.Shared;
@using OpenArchival.Blazor.AdminPages;
@using OpenArchival.Blazor;

<ArchiveSearchBar @ref=_searchBar SearchTermsChanged="OnSearchTermsChanged"></ArchiveSearchBar>
<MudDataGrid 
    T="ArtifactGroupingRowElement" 
    MultiSelection=true 
    Filterable=false
    SelectOnRowClick=true
    ServerData="new Func<GridState<ArtifactGroupingRowElement>, Task<GridData<ArtifactGroupingRowElement>>>(ServerReload)"
    @ref=@DataGrid
    @bind-SelectedItems="_selectedGroupings"
    Comparer="_comparer">

    <ToolBarContent>
        
        <MudSpacer /> 

        <MudButton Variant="Variant.Filled"
                   StartIcon="@Icons.Material.Filled.Delete"
                   Color="Color.Error"
                   OnClick="OnDeleteClicked">Delete</MudButton>
    </ToolBarContent>
    
    <Columns>
        <SelectColumn T="ArtifactGroupingRowElement"/>
                
        <PropertyColumn 
            Title="Id"
            Property="x=>x.ArtifactGroupingIdentifier"
            Filterable="false"/>

        <PropertyColumn 
            Title="Category"
            Property="x=>x.CategoryName"
            Filterable="false"/>

        <PropertyColumn 
            Title="Title"
            Property="x=>x.Title"
            Filterable="false"/>

        <PropertyColumn 
            Title="Publically Visible"
            Property="x=>x.IsPublicallyVisible"
            Filterable="false"/>

        <TemplateColumn Title="Edit"> 
            <CellTemplate>
                <MudIconButton 
                    Color="Color.Primary"
                    Icon="@Icons.Material.Filled.Edit" 
                    Variant="Variant.Filled"
                    OnClick="() => OnRowEditClick(context.Item)">Edit</MudIconButton>
            </CellTemplate>
        </TemplateColumn>

    </Columns>

    <PagerContent>
        <MudDataGridPager T="ArtifactGroupingRowElement"/>
    </PagerContent>
</MudDataGrid>


@inject IArtifactGroupingProvider GroupingProvider;
@inject IDialogService DialogService;
@inject IArtifactGroupingProvider GroupingProvider;
@inject ArtifactEntrySharedHelpers Helpers;
@inject ArtifactGroupingSearch SearchProvider;
@code 
{
    public class ArtifactGroupingRowElementComparer : IEqualityComparer<ArtifactGroupingRowElement>
    {
        public bool Equals(ArtifactGroupingRowElement? x, ArtifactGroupingRowElement? y)
        {
            if (ReferenceEquals(x, y)) return true;
            if (x is null || y is null) return false;
            return x.Id == y.Id;
        }

        public int GetHashCode(ArtifactGroupingRowElement obj)
        {
            return obj.Id.GetHashCode();
        }
    }
    public List<ArtifactGroupingRowElement> ArtifactGroupingRows { get; set; } = new();

    public MudDataGrid<ArtifactGroupingRowElement> DataGrid { get; set; } = default!;

    private ArtifactGroupingRowElementComparer _comparer = new();

    private string _searchString { get; set; } = "";

    private ArchiveSearchBar _searchBar { get; set; } = default!;

    private HashSet<ArtifactGroupingRowElement> _selectedGroupings { get; set; } = [];

    protected override async Task OnInitializedAsync()
    {
        // Load inital data
        List<ArtifactGrouping> groupings = await GroupingProvider.GetGroupingsPaged(1, 25);
        SetGroupingRows(groupings);

        await base.OnInitializedAsync();
        StateHasChanged();
    }

    private void SetGroupingRows(IEnumerable<ArtifactGrouping> groupings)
    {
        ArtifactGroupingRows.Clear();

        foreach (var grouping in groupings)
        {
            ArtifactGroupingRows.Add(new ArtifactGroupingRowElement()
                {
                    ArtifactGroupingIdentifier=grouping.ArtifactGroupingIdentifier ?? throw new ArgumentNullException(nameof(grouping), "Got a null grouping identifier"), 
                    CategoryName=grouping.Category.Name,
                    Title=grouping.Title,
                    IsPublicallyVisible=grouping.IsPublicallyVisible,
                    Id=grouping.Id
                }
            );        
        }
    }

    private async Task OnRowEditClick(ArtifactGroupingRowElement row)
    {
        var parameters = new DialogParameters();

        var model = await GroupingProvider.GetGroupingAsync(row.Id); 

        parameters.Add("Model", ArtifactGroupingValidationModel.ToValidationModel(model));

        var options = new DialogOptions()
        {
            MaxWidth = MaxWidth.ExtraExtraLarge,
            FullWidth = true
        };

        var dialog = await DialogService.ShowAsync<AddGroupingDialog>("Edit Grouping", parameters, options);

        var result = await dialog.Result;

        if (result is not null && !result.Canceled)
        {
            var validationModel = (ArtifactGroupingValidationModel)result.Data!;

            await Helpers.OnGroupingPublished(validationModel);            

            await DataGrid.ReloadServerData(); 
        }
    }

    private async Task OnDeleteClicked(MouseEventArgs args)
    {
        HashSet<ArtifactGroupingRowElement> selected = DataGrid.SelectedItems;

        bool? confirmed = await DialogService.ShowMessageBox
        (
            new MessageBoxOptions(){
            Message=$"Are you sure you want to delete {selected.Count} groupings?", 
            Title="Delete Groupings", 
            CancelText="Cancel", 
            YesText="Delete"
        });

        if (confirmed is not null && (confirmed ?? throw new ArgumentNullException("confirmed was null")))
        {
            foreach (var grouping in selected)
            {
                await GroupingProvider.DeleteGroupingAsync(grouping.Id);
            }
        }

        await DataGrid.ReloadServerData();
        StateHasChanged();
    }

    private async Task<GridData<ArtifactGroupingRowElement>> ServerReload(GridState<ArtifactGroupingRowElement> state)
    {
        int totalItems = await GroupingProvider.GetTotalCount();

        SearchProvider.PageSize = state.PageSize;
        IEnumerable<ArtifactGrouping> groupings;

        if (string.IsNullOrEmpty(_searchString))
        {
            groupings = await GroupingProvider.GetGroupingsPaged(state.Page + 1, state.PageSize);
            totalItems = await GroupingProvider.GetTotalCount(); 

        } else
        {
            await SearchProvider.Search(_searchString, _searchBar.SelectedFilter, state.Page + 1);
            groupings = SearchProvider.SearchResults;
        }

        var pagedItems = groupings.Select(grouping => new ArtifactGroupingRowElement()
        {
            Id = grouping.Id,
            Title = grouping.Title,
            ArtifactGroupingIdentifier = grouping.ArtifactGroupingIdentifier ?? throw new ArgumentNullException(nameof(grouping), "Got a null ArtifactGroupingIdentifier"),
            CategoryName = grouping.Category.Name,
            IsPublicallyVisible = grouping.IsPublicallyVisible,
        });

        StateHasChanged();

        return new GridData<ArtifactGroupingRowElement>()
            {
                TotalItems = totalItems,
                Items = pagedItems
            };
    }

    private async Task OnSearchTermsChanged(string args)
    {
        _searchString = args;
        await DataGrid.ReloadServerData(); 
    }

    public async Task<List<ArtifactGrouping>> SelectedItems()
    {
        List<ArtifactGrouping> selectedGroupings = [];
        foreach (ArtifactGroupingRowElement row in DataGrid.SelectedItems)
        {
            selectedGroupings.Add(await GroupingProvider.GetGroupingAsync(row.Id));
        }

        return selectedGroupings;
    }

    public void ClearSelected()
    {
        // OLD: _selectedGroupings = new HashSet<ArtifactGroupingRowElement>();
        // NEW: Initialize with the comparer
        _selectedGroupings = new HashSet<ArtifactGroupingRowElement>(_comparer);
    }

    // 6. ADD THIS NEW PUBLIC METHOD
    public Task SetSelectedItemsAsync(IEnumerable<ArtifactGrouping> groupingsToSelect)
    {
        // Convert from the full ArtifactGrouping entity to the RowElement.
        // We only *really* need the Id for the comparer, but populating
        // the other fields is good practice.
        var rowElementsToSelect = groupingsToSelect.Select(grouping => new ArtifactGroupingRowElement
        {
            Id = grouping.Id,
            Title = grouping.Title,
            ArtifactGroupingIdentifier = grouping.ArtifactGroupingIdentifier ?? string.Empty,
            CategoryName = grouping.Category?.Name ?? string.Empty,
            IsPublicallyVisible = grouping.IsPublicallyVisible
        });

        // Create a new HashSet from the list, using the comparer.
        // Assigning this to the bound variable will update the grid's UI.
        _selectedGroupings = new HashSet<ArtifactGroupingRowElement>(rowElementsToSelect, _comparer);

        StateHasChanged();
        return Task.CompletedTask;
    }

}