@using System.IO
@inject ILogger<AttachmentUploader> Logger

<div class="col-span-6 sm:col-span-3">
    <InputFile OnChange="@HandleFileSelection" multiple class="block w-full text-sm text-gray-900 border border-gray-300 rounded-lg cursor-pointer bg-gray-50 dark:text-gray-400 focus:outline-none dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400" />
    @if (!string.IsNullOrEmpty(StatusMessage))
    {
        <p class="mt-2 text-sm text-gray-500 dark:text-gray-400">@StatusMessage</p>
    }
    @if (Attachments.Exists(x => !x.IsDeleted))
    {
        <div class="mt-4">
            <h4 class="mb-2 text-lg font-semibold dark:text-white">Attachments:</h4>
            <ul class="list-disc list-inside">
                @foreach (var attachment in Attachments.Where(x => !x.IsDeleted))
                {
                    <li class="flex items-center justify-between text-sm text-gray-600 dark:text-gray-400">
                        @if (attachment.Blob != null && attachment.Blob.Length > 0)
                        {
                            <span>@attachment.Filename</span>
                        }
                        else
                        {
                            <span class="text-gray-400 dark:text-gray-500" title="Attachment data unavailable">@attachment.Filename (unavailable)</span>
                        }
                        <button type="button" @onclick="() => DeleteAttachment(attachment)" class="text-red-500 hover:text-red-700">
                            Delete
                        </button>
                    </li>
                }
            </ul>
        </div>
    }
</div>

@code {
    /// <summary>
    /// Attachments to be uploaded.
    /// </summary>
    [Parameter]
    public List<Attachment> Attachments { get; set; } = [];

    /// <summary>
    /// Callback that is invoked when the attachments are changed.
    /// </summary>
    [Parameter]
    public EventCallback<List<Attachment>> AttachmentsChanged { get; set; }

    /// <summary>
    /// Original attachments that were passed in. This is used to determine if a deleted attachment was part of the original set and
    /// can be hard deleted (did not exist in the original set) or should be soft deleted (was part of the original set).
    /// </summary>
    private List<Guid> OriginalAttachmentsIds { get; set; } = [];

    /// <summary>
    /// Status message to display.
    /// </summary>
    private string StatusMessage { get; set; } = string.Empty;

    /// <summary>
    /// Maximum individual attachment file size in bytes.
    /// </summary>
    private int MaxFileSize { get; set; } = 1024 * 1024 * 10; // 10 MB

    /// <inheritdoc />
    protected override void OnInitialized()
    {
        base.OnInitialized();

        // Keep track of the original attachments.
        OriginalAttachmentsIds = Attachments.Select(a => a.Id).ToList();
    }

    private async Task HandleFileSelection(InputFileChangeEventArgs e)
    {
        StatusMessage = "Uploading...";
        foreach (var file in e.GetMultipleFiles(int.MaxValue))
        {
            try
            {
                using var ms = new MemoryStream();
                await file.OpenReadStream(MaxFileSize).CopyToAsync(ms);

                var attachment = new Attachment
                {
                    Filename = file.Name,
                    Blob = ms.ToArray(),
                    CreatedAt = DateTime.UtcNow,
                    UpdatedAt = DateTime.UtcNow,
                };

                Attachments.Add(attachment);
                await AttachmentsChanged.InvokeAsync(Attachments);

                StatusMessage = "File uploaded successfully.";
            }
            catch (Exception ex)
            {
                StatusMessage = $"Error uploading file: {ex.Message}";
                Logger.LogError(ex, "Error uploading file.");
            }
        }

        StateHasChanged();
    }

    private async Task DeleteAttachment(Attachment attachment)
    {
        try
        {
            // Check if the attachment was part of the original set.
            if (OriginalAttachmentsIds.Contains(attachment.Id))
            {
                // If it was part of the original set, we soft delete it.
                var attachmentToDelete = Attachments.FirstOrDefault(a => a.Id == attachment.Id);
                if (attachmentToDelete is not null)
                {
                    attachmentToDelete.IsDeleted = true;
                    attachmentToDelete.UpdatedAt = DateTime.UtcNow;
                }
            }
            else
            {
                // If it was not part of the original set, we hard delete it.
                Attachments.Remove(attachment);
            }

            await AttachmentsChanged.InvokeAsync(Attachments);
            StatusMessage = "Attachment deleted successfully.";
        }
        catch (Exception ex)
        {
            StatusMessage = $"Error deleting attachment: {ex.Message}";
            Console.Error.WriteLine("Error deleting file: {0}", ex.Message);
        }

        StateHasChanged();
    }
}
