@page "/admin/homepageeditor"

@layout AdminControlPanelLayout

@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.EntityFrameworkCore
@using Microsoft.Extensions.Caching.Memory
@using Microsoft.Extensions.Options
@using Microsoft.AspNetCore.Authorization

@using MudExRichTextEditor
@using MudBlazor
@using OpenArchival.Blazor
@using OpenArchival.Blazor.AdminPages.Shared
@using OpenArchival.Blazor.Config
@using OpenArchival.DataAccess
@using OpenArchival.DataAccess.FileAccessManager
@using OpenArchival.Blazor.CustomComponents

@attribute [Authorize(Roles = UserRoles.Admin)]

<MudText Typo="Typo.h6">Home Page Editor</MudText>
<MudDivider></MudDivider>
@if (!_homePageConfigMissing)
{
    <MudFileUpload T="IBrowserFile"
                   @ref="_bannerFileUpload"
                   AppendMultipleFiles=false
                   Accept=".jpg,.png,.webp"
                   MaximumFileCount="1"
                   Files=_bannerPhotoFile
                   OnFilesChanged="OnFilesChanged"
                   Class="mt-4">
        <ActivatorContent>
            <MudButton Variant="Variant.Filled"
                       Color="Color.Primary">
                       Upload Main Photo
            </MudButton>
        </ActivatorContent>
        <SelectedTemplate>
            @if (context != null)
            {
                <MudText>@context.Name</MudText>
            }
            else if (_homePageConfiguration.HomePageBanner != null)
            {
                <MudText>@_homePageConfiguration.HomePageBanner.OriginalName</MudText>
            }
            else
            {
                <MudText>No Main Photo Selected</MudText>
            }
        </SelectedTemplate>
    </MudFileUpload>


    <MudText Typo="Typo.body2">This is the content that will be displayed on the site's home page underneath the banner image</MudText>
    <MudExRichTextEdit @ref="@_editor"
                       ReadOnly="false"
                       Height="444"
                       Class="m-2 mt-4"
                       Placeholder="Edit html"
                       ValueHtmlBehavior="MudExRichTextEditor.Types.GetHtmlBehavior.SemanticHtml"
                       Immediate="true"
                       @bind-Value="_homePageConfiguration.Content"
                       >
                       
                       </MudExRichTextEdit>

    <MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="OnSaveHomePage" Class="mt-4">Save</MudButton>

    <MudText Typo="Typo.h6" Class="mt-8">Home Page Featured Sliders</MudText>
    <MudDivider></MudDivider>
    <MudText Typo="Typo.subtitle1">Controls what artifacts are shown on the home page. This is controlled via selecting tags. The first artifact with the listed tags will be shown in the slider. Only tags belonging to valid archive entries can be used. Entries must have all of the listed tags to be included in the slider.</MudText>

    <MudTextField T="string" Placeholder="Slider Title" @bind-Text="_titleInputValue"></MudTextField>
    <MudTextField T="string" Placeholder="Slider Description" @bind-Text="_descriptionInputValue"></MudTextField>
    <MudGrid Justify="Justify.Center" Class="mt-4">
        <MudItem>
            <ChipContainer T="string" @ref="@_tagsChipContainer" @bind-Items="_selectedTagStrings" ItemRemoved="OnTagRemoved">
                <InputContent>
                    <MudAutocomplete T="string"
                                     SearchFunc="Helpers.SearchTags"
                                     OnKeyDown="@(ev => HandleChipContainerEnter<string>(ev, _tagsChipContainer, _tagsInputValue, () => _tagsInputValue = string.Empty))"
                                     CoerceValue=true
                                     Placeholder="Add Tags..."
                                     ShowProgressIndicator="true"
                                     @bind-Value=@_tagsInputValue
                                     CoerceText=true>
                    </MudAutocomplete>
                </InputContent>
            </ChipContainer>
        </MudItem>
        <MudItem>
            <MudButton Variant="Variant.Filled"
                       Color="Color.Primary"
                       OnClick="OnAddSlider">Add Slider</MudButton>
        </MudItem>
    </MudGrid>

    @if (_homePageConfiguration.SliderEntries != null)
    {
        @foreach (SearchPageSliderEntry entry in _homePageConfiguration.SliderEntries)
        {
            <MudPaper Class="pa-4 ma-2 rounded" Elevation="3">
                <MudButton StartIcon="@Icons.Material.Filled.Delete" Color="Color.Error" OnClick="() => OnDeleteSliderClicked(entry)">Delete</MudButton>
                <MudText Typo="Typo.h6">Title: @entry.Title</MudText>
                <MudText Typo="Typo.h6">Description: @entry.Description</MudText>
                <MudText Typo="Typo.h6">Tags:</MudText>
                <ChipContainer T="ArtifactEntryTag" Items="entry.FilterTags" DeleteEnabled=false></ChipContainer>
            </MudPaper>
        }
    }
} else
{
    <MudText Typo="Typo.h4" Color="Color.Error">Failed to query home page configuration from database, was your database modified outside the application?</MudText>
}

@inject ArtifactEntrySharedHelpers Helpers;
@inject ISnackbar Snackbar;
@inject IOptions<ApplicationOptions> AppOptions;
@inject IMemoryCache MemoryCache;
@inject IDbContextFactory<ApplicationDbContext> ContextFactory;
@inject IFileAccessManager FileAccessManager;

@code {
    private MudFileUpload<IBrowserFile> _bannerFileUpload = default!;

    private MudExRichTextEdit _editor = default!;

    private bool _hasLoaded = false;

    private string _editorContent = "";

    private IBrowserFile? _bannerPhotoFile { get; set; }

    // Flipped if the browser file has changed for the file picker, this lets us know to delete the old file before creating a new one
    private bool _hasFileChanged { get; set; }

    private HomePageConfiguration _homePageConfiguration { get; set; }

    private bool _homePageConfigMissing { get; set; } = true;

    // Slider management state
    private string _tagsInputValue { get; set; } = "";
    private List<string> _selectedTagStrings { get; set; } = [];
    private List<ArtifactEntryTag> _selectedTags { get; set; } = [];
    private string _titleInputValue { get; set; } = "";
    private string _descriptionInputValue { get; set; } = "";
    private ChipContainer<string> _tagsChipContainer { get; set; } = default!;

    protected override async Task OnInitializedAsync()
    {
        await using var context = await ContextFactory.CreateDbContextAsync();
        var tempConfig = await context.HomePageConfiguration
            .Include(config => config.HomePageBanner)
            .Include(config => config.SliderEntries)
                .ThenInclude(se => se.FilterTags)
            .FirstOrDefaultAsync();

        if (tempConfig == null)
        {
            Snackbar.Add("Database invalid, no HomePageConfiguration", Severity.Error);
            _homePageConfigMissing = true;
        }
        else
        {
            _homePageConfigMissing = false;
            _homePageConfiguration = tempConfig;
            if (_homePageConfiguration.SliderEntries == null)
            {
                _homePageConfiguration.SliderEntries = new List<SearchPageSliderEntry>();
            }
        }
    }

    private async Task OnSaveHomePage(Microsoft.AspNetCore.Components.Web.MouseEventArgs args)
    {
        await using var context = await ContextFactory.CreateDbContextAsync();
        if (_bannerPhotoFile != null)
        {
            // In this case we know to delete the current FilePathListing and make a new one
            // as the file has changed
            if (_hasFileChanged)
            {
                FilePathListing? bannerListing = _homePageConfiguration.HomePageBanner;
                if (bannerListing != null)
                {
                    await FileAccessManager.DeleteFileAsync(bannerListing.Id);
                }

                FilePathListing? newBannerFileListing = null;
                newBannerFileListing = await FileAccessManager.UploadFileAsync(_bannerPhotoFile);
                newBannerFileListing.HomePageConfiguration = _homePageConfiguration;
                _homePageConfiguration.HomePageBanner = newBannerFileListing;
            }
        }

        // Page content is already bound by the text editor so just save
        context.Update(_homePageConfiguration);
        await context.SaveChangesAsync();

        // Clear the memory cache of the home page values
        MemoryCache.Remove(OpenArchivalConstants.HomePageConfigurationCacheKey);

        Snackbar.Add("Saved changes to home page configuration!", Severity.Success);
    }

    private async Task OnFilesChanged(InputFileChangeEventArgs args)
    {
        _hasFileChanged = true;
        _bannerPhotoFile = args.File;
    }

    public async Task HandleChipContainerEnter<Type>(KeyboardEventArgs args, ChipContainer<Type> container, Type value, Action resetInputAction)
    {
        if (args.Key == "Enter")
        {
            await using var context = await ContextFactory.CreateDbContextAsync();
            ArtifactEntryTag? tagToAdd = await context.ArtifactEntryTags.Where(tag => tag.Name == _tagsInputValue).FirstOrDefaultAsync();
            if (tagToAdd is null)
            {
                tagToAdd = new ArtifactEntryTag() { Name = _tagsInputValue };
            }
            _selectedTags.Add(tagToAdd);

            await container.AddItem(value);
            resetInputAction?.Invoke();
            StateHasChanged();
        }
    }

    private async Task OnAddSlider(MouseEventArgs args)
    {
        if (string.IsNullOrEmpty(_titleInputValue))
        {
            Snackbar.Add("A slider title is required.", Severity.Error);
            return;
        }

        if (!_selectedTags.Any())
        {
            Snackbar.Add("At least one tag is required", Severity.Error);
            return;
        }

        await using var context = await ContextFactory.CreateDbContextAsync();

        // Attach all of the existing tags to the context
        foreach (var tag in _selectedTags.Where(t => t.Id != 0))
        {
            context.ArtifactEntryTags.Attach(tag);
        }

        var newEntry = new SearchPageSliderEntry()
            {
                Title = _titleInputValue,
                Description = _descriptionInputValue,
                FilterTags = _selectedTags,
                IsHomePageSlider = true,
                HomePageConfiguration = _homePageConfiguration
            };

        _homePageConfiguration.SliderEntries!.Add(newEntry);
        context.Update(_homePageConfiguration);
        await context.SaveChangesAsync();

        Snackbar.Add("Added slider", Severity.Success);

        _selectedTags = new List<ArtifactEntryTag>();
        _selectedTagStrings.Clear();
        _titleInputValue = "";
        _descriptionInputValue = "";

        // Clear the memory cache of the home page values
        MemoryCache.Remove(OpenArchivalConstants.HomePageConfigurationCacheKey);

        StateHasChanged();
    }

    private void OnTagRemoved(string tagString)
    {
        int countRemoved = _selectedTags.RemoveAll(t => t.Name == tagString);

        if (countRemoved != 1)
        {
            throw new ArgumentException("Did not remove 1 element from the list of tags");
        }
    }

    private async Task OnDeleteSliderClicked(SearchPageSliderEntry entry)
    {
        await using var context = await ContextFactory.CreateDbContextAsync();
        SearchPageSliderEntry? entryToRemove = await context.SearchPageSliderEntries.Where(en => en.Id == entry.Id).FirstOrDefaultAsync();
        if (entryToRemove is null)
        {
            throw new ArgumentException("The entry to remove was null and not in the database");
        }

        _homePageConfiguration.SliderEntries!.Remove(entry);
        context.SearchPageSliderEntries.Remove(entryToRemove);
        await context.SaveChangesAsync();

        // Clear the memory cache of the home page values
        MemoryCache.Remove(OpenArchivalConstants.HomePageConfigurationCacheKey);

        StateHasChanged();
    }
}
