@page "/mod/emojis"
@using Iceshrimp.Frontend.Core.Services
@using Iceshrimp.Frontend.Localization
@using Microsoft.AspNetCore.Authorization
@using Microsoft.Extensions.Localization
@using Microsoft.AspNetCore.Components.Sections
@using Iceshrimp.Assets.PhosphorIcons
@using Iceshrimp.Frontend.Core.Miscellaneous
@using Iceshrimp.Shared.Schemas.Web
@using Iceshrimp.Frontend.Components
@attribute [Authorize(Roles = "moderator")]
@layout ModerationLayout
@inject ApiService                     Api;
@inject GlobalComponentSvc             Global;
@inject IJSRuntime                     Js;
@inject IStringLocalizer<Localization> Loc;

<HeadTitle Text="@Loc["Custom Emojis"]"/>

<SectionContent SectionName="top-bar">
    <Icon Name="Icons.Smiley"></Icon>
    @Loc["Custom Emojis"]
    @if (State is State.Empty or State.Loaded)
    {
        <span class="action btn" @onclick="OpenUpload">
            <Icon Name="Icons.Upload"/>
            <span>@Loc["Upload"]</span>
        </span>
        <span class="action btn" @onclick="OpenImport">
            <Icon Name="Icons.FileArrowUp"/>
            <span>@Loc["Import pack"]</span>
        </span>
    }
    @if (State is not State.Loading)
    {
        <a class="action btn" href="/mod/emojis/remote">
            <Icon Name="Icons.ArrowSquareOut"/>
            <span>@Loc["Remote"]</span>
        </a>
    }
</SectionContent>

@if (State is State.Empty or State.Error or State.Loaded)
{
    <div class="emoji-search">
        <input @bind="EmojiFilter" class="search" type="text" placeholder="@Loc["Name"]" aria-label="search name"/>
        <button @onclick="FilterEmojis" class="button">@Loc["Search"]</button>
    </div>
}
@if (State is State.Loaded)
{
    @foreach (var category in Categories)
    {
        <span class="category-name">@category.Key</span>
        <div class="emoji-list">
            @foreach (var emoji in category.Value)
            {
                <EmojiManagementEntry Emoji="@emoji" GetEmojis="GetEmojis"/>
            }
        </div>
    }
}
@if (State is State.Empty || (State is State.Loaded && Categories.Count == 0))
{
    @Loc["No emojis were found"]
}
@if (State is State.Loading)
{
    <div class="loading">
        <LoadingSpinner Scale="2"/>
    </div>
}

<div class="file-input">
    <InputFile @ref="UploadInput" OnChange="Upload" accept="image/*">Upload</InputFile>
    <InputFile @ref="ImportInput" OnChange="Import" accept=".zip">Import</InputFile>
</div>

@code {
    private List<EmojiResponse>                     Emojis      { get; set; } = [];
    private Dictionary<string, List<EmojiResponse>> Categories  { get; set; } = new();
    private string                                  EmojiFilter { get; set; } = "";
    private State                                   State       { get; set; }
    private InputFile                               UploadInput { get; set; } = null!;
    private IBrowserFile                            UploadFile  { get; set; } = null!;
    private InputFile                               ImportInput { get; set; } = null!;
    private IBrowserFile                            ImportFile  { get; set; } = null!;
    private IJSObjectReference                      _module = null!;

    private void FilterEmojis()
    {
        Categories = Emojis
                     .Where(p => p.Name.Contains(EmojiFilter.Trim()) || p.Tags.Count(a => a.Contains(EmojiFilter.Trim())) != 0)
                     .OrderBy(p => p.Name)
                     .ThenBy(p => p.Id)
                     .GroupBy(p => p.Category)
                     .OrderBy(p => string.IsNullOrEmpty(p.Key))
                     .ThenBy(p => p.Key)
                     .ToDictionary(p => p.Key ?? Loc["Other"], p => p.ToList());
    }

    private async Task GetEmojis()
    {
        State = State.Loading;

        Emojis = await Api.Emoji.GetAllEmojiAsync();

        if (Emojis.Count == 0)
        {
            State = State.Empty;
        }
        else
        {
            FilterEmojis();
            State = State.Loaded;
        }
    }

    // The <InputFile> Component is hidden, and triggered by a sepperate button.
    // That way we get it's functionality, without the styling limitations of the InputFile component
    private async Task OpenUpload()
    {
        await _module.InvokeVoidAsync("openUpload", UploadInput.Element);
    }

    private async Task OpenImport()
    {
        await _module.InvokeVoidAsync("openUpload", ImportInput.Element);
    }

    private async Task Upload(InputFileChangeEventArgs e)
    {
        if (!e.File.ContentType.StartsWith("image/")) return;
        UploadFile = e.File;
        await Global.PromptDialog?.Prompt(new EventCallback<string?>(this, UploadCallback), Loc["Set emoji name"], "", e.File.Name.Split(".")[0], buttonText: Loc["Upload"])!;
    }

    private async Task UploadCallback(string? name)
    {
        if (name == null) return;

        try
        {
            await Api.Emoji.UploadEmojiAsync(UploadFile, name);
            await Global.NoticeDialog?.Display(Loc["Successfully uploaded {0}", name])!;
            await GetEmojis();
        }
        catch (ApiException e)
        {
            await Global.NoticeDialog?.Display(e.Response.Message ?? Loc["An unknown error occurred"], NoticeDialog.NoticeType.Error)!;
        }
    }

    private async Task Import(InputFileChangeEventArgs e)
    {
        if (e.File.ContentType != "application/zip") return;
        ImportFile = e.File;
        await Global.ConfirmDialog?.Confirm(new EventCallback<bool>(this, ImportCallback), Loc["Import {0}?", e.File.Name], Icons.FileArrowUp, Loc["Import"])!;
    }

    private async Task ImportCallback(bool import)
    {
        if (!import) return;

        try
        {
            await Api.Emoji.ImportEmojiAsync(ImportFile);
            await Global.NoticeDialog?.Display(Loc["Successfully imported emoji pack"])!;
            await GetEmojis();
        }
        catch (ApiException e)
        {
            await Global.NoticeDialog?.Display(e.Response.Message ?? Loc["An unknown error occurred"], NoticeDialog.NoticeType.Error)!;
        }
    }

    protected override async Task OnInitializedAsync()
    {
        _module = await Js.InvokeAsync<IJSObjectReference>("import",
                                                           "./Pages/Moderation/CustomEmojis.razor.js");
        await GetEmojis();
    }
}
