@using Iceshrimp.Frontend.Localization
@using Iceshrimp.Shared.Schemas.Web
@using Microsoft.Extensions.Localization
@using Iceshrimp.Assets.PhosphorIcons
@using Iceshrimp.Frontend.Core.Miscellaneous
@using Iceshrimp.Frontend.Core.Services
@inject ApiService                     Api;
@inject GlobalComponentSvc             Global;
@inject IJSRuntime                     Js;
@inject IStringLocalizer<Localization> Loc;
@inject NavigationManager              Nav;

@if (File != null && Folder == null)
{
    <div @ref="FileButton" class="drive-entry" @onclick="SelectFile" @onclick:stopPropagation="true">
        <div class="labels">
            @if (File.IsAvatar)
            {
                <Icon Name="Icons.UserCircle" title="@Loc["Avatar"]"/>
            }
            @if (File.IsBanner)
            {
                <Icon Name="Icons.Image" title="@Loc["Banner"]"/>
            }
            @if (File.Description != null)
            {
                <Icon Name="Icons.ClosedCaptioning" title="@File.Description"/>
            }
            else
            {
                <Icon Name="Icons.Warning" title="@Loc["No alt text"]"/>
            }
            @if (File.Sensitive)
            {
                <Icon Name="Icons.EyeSlash" title="@Loc["Sensitive"]"/>
            }
        </div>
        @if (File.ContentType.StartsWith("image"))
        {
            <img class="thumbnail" src="@File.ThumbnailUrl" alt="@File.Description"/>
        }
        else if (File.ContentType.StartsWith("audio"))
        {
            <Icon Name="Icons.FileAudio" Size="5em"/>
        }
        else if (File.ContentType.StartsWith("video"))
        {
            <Icon Name="Icons.FileVideo" Size="5em"/>
        }
        else
        {
            <Icon Name="Icons.File" Size="5em"/>
        }
        <span>@File.Filename</span>
        <Menu @ref="FileMenu">
            <MenuElement Icon="Icons.ArrowSquareOut" OnSelect="OpenFile">
                <Text>@Loc["Open"]</Text>
            </MenuElement>
            <MenuElement Icon="Icons.Share" OnSelect="CopyFileLink">
                <Text>@Loc["Copy link"]</Text>
            </MenuElement>
            <MenuElement Icon="Icons.CursorText" OnSelect="RenameFile">
                <Text>@Loc["Rename"]</Text>
            </MenuElement>
            @if (File.Sensitive)
            {
                <MenuElement Icon="Icons.Eye" OnSelect="MarkFileNotSensitive">
                    <Text>@Loc["Mark as not sensitive"]</Text>
                </MenuElement>
            }
            else
            {
                <MenuElement Icon="Icons.EyeSlash" OnSelect="MarkFileAsSensitive">
                    <Text>@Loc["Mark as sensitive"]</Text>
                </MenuElement>
            }
            <MenuElement Icon="Icons.ClosedCaptioning" OnSelect="SetFileAltText">
                <Text>@Loc["Set alt text"]</Text>
            </MenuElement>
            @if (ParentId != null || FolderList.Count != 0)
            {
                <MenuElement Icon="Icons.FolderDashed" OnSelect="MoveFile">
                    <Text>@Loc["Move"]</Text>
                </MenuElement>
            }
            <MenuElement Icon="Icons.Trash" OnSelect="DeleteFile">
                <Text>@Loc["Delete"]</Text>
            </MenuElement>
            <ClosingBackdrop OnClose="FileMenu.Close"></ClosingBackdrop>
        </Menu>
    </div>
}
@if (Folder != null && File == null)
{
    <div @ref="FolderButton" class="drive-entry" @onclick="SelectFolder" @onclick:stopPropagation="true">
        <Icon Name="Icons.FolderOpen" Size="5em" Pack="IconStyle.Fill"/>
        <span>@Folder.Name</span>
        <Menu @ref="FolderMenu">
            <MenuElement Icon="Icons.FolderOpen" OnSelect="OpenFolder">
                <Text>@Loc["Open"]</Text>
            </MenuElement>
            <MenuElement Icon="Icons.CursorText" OnSelect="RenameFolder">
                <Text>@Loc["Rename"]</Text>
            </MenuElement>
            @if (ParentId != null || FolderList.Count > 1)
            {
                <MenuElement Icon="Icons.FolderDashed" OnSelect="MoveFolder">
                    <Text>@Loc["Move"]</Text>
                </MenuElement>
            }
            <ClosingBackdrop OnClose="FolderMenu.Close"></ClosingBackdrop>
        </Menu>
    </div>
}

@code {
    [Parameter] public DriveFileResponse?   File         { get; set; } = null;
    [Parameter] public DriveFolderResponse? Folder       { get; set; } = null;
    private            Menu                 FileMenu     { get; set; } = null!;
    private            Menu                 FolderMenu   { get; set; } = null!;
    private            ElementReference     FileButton   { get; set; }
    private            ElementReference     FolderButton { get; set; }

    [Parameter, EditorRequired] public required string?                   ParentId   { get; set; }
    [Parameter, EditorRequired] public required List<DriveFolderResponse> FolderList { get; set; }

    private void SelectFile() => FileMenu.Toggle(FileButton);

    private async Task RenameFile() =>
        await Global.PromptDialog?.Prompt(new EventCallback<string?>(this, RenameFileCallback), Loc["Rename file"], Loc["File name"], File!.Filename, buttonText: Loc["Rename"])!;

    private async Task RenameFileCallback(string? filename)
    {
        if (string.IsNullOrWhiteSpace(filename)) return;

        try
        {
            var res = await Api.Drive.UpdateFileAsync(File!.Id, new UpdateDriveFileRequest { Filename = filename });
            if (res != null)
            {
                File.Filename = res.Filename;
                StateHasChanged();
            }
        }
        catch (ApiException e)
        {
            await Global.NoticeDialog?.Display(e.Response.Message ?? Loc["An unknown error occurred"], NoticeDialog.NoticeType.Error)!;
        }
    }

    private async Task MarkFileSensitive(bool sensitive)
    {
        try
        {
            var res = await Api.Drive.UpdateFileAsync(File!.Id, new UpdateDriveFileRequest { Sensitive = sensitive });
            if (res != null)
            {
                File.Sensitive = res.Sensitive;
                StateHasChanged();
            }
        }
        catch (ApiException e)
        {
            await Global.NoticeDialog?.Display(e.Response.Message ?? Loc["An unknown error occurred"], NoticeDialog.NoticeType.Error)!;
        }
    }

    private async Task MarkFileNotSensitive() => await MarkFileSensitive(false);

    private async Task MarkFileAsSensitive() => await MarkFileSensitive(true);

    private async Task SetFileAltText() =>
        await Global.PromptDialog?.Prompt(new EventCallback<string?>(this, SetFileAltTextCallback), Loc["Set alt text"], "", File!.Description ?? "", true, true)!;

    private async Task SetFileAltTextCallback(string? alt)
    {
        if (alt == null) return;

        try
        {
            var res = await Api.Drive.UpdateFileAsync(File!.Id, new UpdateDriveFileRequest { Description = string.IsNullOrWhiteSpace(alt) ? null : alt });
            if (res != null)
            {
                File.Description = res.Description;
                StateHasChanged();
            }
        }
        catch (ApiException e)
        {
            await Global.NoticeDialog?.Display(e.Response.Message ?? Loc["An unknown error occurred"], NoticeDialog.NoticeType.Error)!;
        }
    }

    private async Task MoveFile()
    {
        var folders = FolderList.Select(f => (f.Name ?? "/", (object)(f.Id ?? ""))).OrderBy(f => f.Item1).ToList();
        if (ParentId != null) folders.Insert(0, ("/", ""));
        await Global.SelectDialog?.Select(new EventCallback<object?>(this, MoveFileCallback), Loc["Move to folder"], folders)!;
    }

    private async Task MoveFileCallback(object? folderId)
    {
        if (folderId is not string id) return;

        try
        {
            var res = await Api.Drive.UpdateFileParentAsync(File!.Id, string.IsNullOrWhiteSpace(id) ? null : id);
            if (res != null)
            {
                File = null;
                StateHasChanged();
            }
        }
        catch (ApiException e)
        {
            await Global.NoticeDialog?.Display(e.Response.Message ?? Loc["An unknown error occurred"], NoticeDialog.NoticeType.Error)!;
        }
    }

    private void OpenFile() => Js.InvokeVoidAsync("open", File!.Url, "_blank");

    private void CopyFileLink() => Js.InvokeVoidAsync("navigator.clipboard.writeText", File!.Url);

    private async Task DeleteFile() =>
        await Global.ConfirmDialog?.Confirm(new EventCallback<bool>(this, DeleteFileCallback), Loc["Delete {0}?", File!.Filename], Icons.Trash, Loc["Delete"])!;

    private async Task DeleteFileCallback(bool delete)
    {
        if (!delete) return;

        try
        {
            await Api.Drive.DeleteFileAsync(File!.Id);
            File = null;
            StateHasChanged();
        }
        catch (ApiException e)
        {
            await Global.NoticeDialog?.Display(e.Response.Message ?? Loc["An unknown error occurred"], NoticeDialog.NoticeType.Error)!;
        }
    }

    private void SelectFolder() => FolderMenu.Toggle(FolderButton);

    private async Task RenameFolder()
    {
        if (Folder is not { Id: not null, Name: not null }) return;
        await Global.PromptDialog?.Prompt(new EventCallback<string?>(this, RenameFolderCallback), Loc["Rename folder"], Loc["Folder name"], Folder!.Name, buttonText: Loc["Rename"])!;
    }

    private async Task RenameFolderCallback(string? name)
    {
        if (Folder is not { Id: not null, Name: not null }) return;
        if (string.IsNullOrWhiteSpace(name)) return;

        try
        {
            var res = await Api.Drive.UpdateFolderAsync(Folder.Id, name);
            if (res != null)
            {
                Folder.Name = res.Name;
                StateHasChanged();
            }
        }
        catch (ApiException e)
        {
            await Global.NoticeDialog?.Display(e.Response.Message ?? Loc["An unknown error occurred"], NoticeDialog.NoticeType.Error)!;
        }
    }

    private async Task MoveFolder()
    {
        var folders = FolderList.Where(f => f.Id != Folder!.Id).Select(f => (f.Name ?? "/", (object)(f.Id ?? ""))).OrderBy(f => f.Item1).ToList();
        if (ParentId != null) folders.Insert(0, ("/", ""));
        await Global.SelectDialog?.Select(new EventCallback<object?>(this, MoveFolderCallback), Loc["Move to folder"], folders)!;
    }

    private async Task MoveFolderCallback(object? folderId)
    {
        if (Folder is not { Id: not null, Name: not null }) return;
        if (folderId is not string id) return;

        try
        {
            var res = await Api.Drive.UpdateFolderParentAsync(Folder.Id, string.IsNullOrWhiteSpace(id) ? null : id);
            if (res != null)
            {
                Folder = null;
                StateHasChanged();
            }
        }
        catch (ApiException e)
        {
            await Global.NoticeDialog?.Display(e.Response.Message ?? Loc["An unknown error occurred"], NoticeDialog.NoticeType.Error)!;
        }
    }

    private void OpenFolder() => Nav.NavigateTo($"/drive/{Folder!.Id}");
}