@using OpenArchival.Blazor.AdminPages.Shared;
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.EntityFrameworkCore
@using MudBlazor
@using MudExtensions
@using OpenArchival.Blazor.ArchiveSearch
@using OpenArchival.DataAccess
@using Microsoft.AspNetCore.Identity

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

    <ToolBarContent>
        
        <MudSpacer /> 

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

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

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

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

        <TemplateColumn Title="Edit"> 
            <CellTemplate>
                <MudIconButton 
                    Color="Color.Primary"
                    Icon="@Icons.Material.Filled.Edit" 
                    Variant="Variant.Filled"
                    Href="@($"/admin/blogedit/{context.Item.Id}")"
                    Target="_blank">Edit</MudIconButton>
            </CellTemplate>
        </TemplateColumn>

    </Columns>

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


@inject IArtifactGroupingProvider GroupingProvider;
@inject IDialogService DialogService;
@inject IArtifactGroupingProvider GroupingProvider;
@inject BlogPostSearch SearchProvider;
@inject IDbContextFactory<ApplicationDbContext> ContextFactory;
@inject ISnackbar Snackbar;
@inject NavigationManager NavigationManager;

@code 
{
    public class BlogPostRowElementComparer : IEqualityComparer<BlogPostRowElement>
    {
        public bool Equals(BlogPostRowElement? x, BlogPostRowElement? y)
        {
            if (ReferenceEquals(x, y)) return true;
            if (x is null || y is null) return false;
            return x.Id == y.Id;
        }

        public int GetHashCode(BlogPostRowElement obj)
        {
            return obj.Id.GetHashCode();
        }
    }

    private BlogPostRowElementComparer _comparer = new();

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

    private HashSet<BlogPostRowElement> _selectedItems = new();

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

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

    protected override async Task OnInitializedAsync()
    {
        await base.OnInitializedAsync();
        StateHasChanged();
    }

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

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

        // It was REALLY whining about null here ;-;
        if (confirmed is not null && (confirmed ?? throw new ArgumentNullException("confirmed was null")))
        {
            await using var context = await ContextFactory.CreateDbContextAsync();
            foreach (BlogPostRowElement post in selected)
            {
                await context.BlogPosts.Where(p => p.Id == post.Id).ExecuteDeleteAsync();
            }
        }

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

    private async Task<GridData<BlogPostRowElement>> ServerReload(GridState<BlogPostRowElement> state)
    {
        await using var context = await ContextFactory.CreateDbContextAsync();
        int totalItems = await context.BlogPosts.CountAsync(); 

        SearchProvider.PageSize = state.PageSize;
        IEnumerable<BlogPost> blogPosts;

        if (string.IsNullOrEmpty(_searchString))
        {
            blogPosts = await context.BlogPosts
                .Skip(state.Page * state.PageSize)
                .Take(state.PageSize)
                .ToListAsync();

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

        var pagedItems = blogPosts.Select(post => new BlogPostRowElement()
        {
            Id = post.Id,
            Title = post.Title,
            CreationTime = post.CreationTime,
            ModifiedTime = post.ModifiedTime
        });

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

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

    public async Task<List<BlogPost>> SelectedItems()
    {
        List<BlogPost> selectedGroupings = [];
        foreach (BlogPostRowElement row in DataGrid.SelectedItems)
        {
            await using var context = await ContextFactory.CreateDbContextAsync();
            var post = await context.BlogPosts.Where(p => p.Id == row.Id).FirstOrDefaultAsync();
            if (post is null)
            {
                Snackbar.Add($"Post with id {row.Id} no longer exists in the database.", Severity.Error);
                continue;
            }
            selectedGroupings.Add(post);
        }

        return selectedGroupings;
    }

    public Task SetSelectedItemsAsync(IEnumerable<BlogPost> postsToSelect)
    {
        var rowElementsToSelect = postsToSelect.Select(post => new BlogPostRowElement
        {
            Id = post.Id,
            Title = post.Title,
            CreationTime = post.CreationTime,
            ModifiedTime = post.ModifiedTime
        });

        _selectedItems = new HashSet<BlogPostRowElement>(rowElementsToSelect, _comparer);

        StateHasChanged();
        return Task.CompletedTask;
    }

    public void ClearSelected()
    {
        _selectedItems = new HashSet<BlogPostRowElement>();
    }

}