using Bunit;
using ScadaLink.CentralUI.Components.Shared;

namespace ScadaLink.CentralUI.Tests.Shared;

/// <summary>
/// Regression tests for CentralUI-011. <c>DiffDialog.OpenAsync</c> returns the
/// <c>TaskCompletionSource</c>'s task, completed only by <c>Close()</c>. If the
/// user navigated away while the dialog was open, <c>DisposeAsync</c> ran but
/// never completed the TCS — the awaiting caller was suspended forever and any
/// cleanup after the await was skipped. The fix completes the TCS in
/// <c>DisposeAsync</c>.
/// </summary>
public class DiffDialogTests : BunitContext
{
    [Fact]
    public async Task DisposeAsync_WhileOpen_CompletesPendingTask()
    {
        var cut = Render<DiffDialog>();

        // Open the dialog; the returned task represents the caller's await.
        // Block-bodied lambda so InvokeAsync sees a void delegate — it must NOT
        // await the dialog's own (deliberately long-lived) task.
        Task<bool> pending = null!;
        await cut.InvokeAsync(
            () => { pending = cut.Instance.ShowAsync("Compare", "before", "after"); });

        Assert.False(pending.IsCompleted, "Dialog task should be pending while open.");

        // Simulate navigating away while the dialog is still open.
        await cut.InvokeAsync(async () => await cut.Instance.DisposeAsync());

        // The awaiter must complete deterministically rather than hang forever.
        var completed = await Task.WhenAny(pending, Task.Delay(TimeSpan.FromSeconds(2)));
        Assert.Same(pending, completed);
        Assert.True(pending.IsCompletedSuccessfully);
        var result = await pending;
        Assert.False(result, "Dismiss-on-dispose should resolve to false (not confirmed).");
    }

    [Fact]
    public async Task Close_CompletesPendingTaskWithTrue()
    {
        var cut = Render<DiffDialog>();

        // Block-bodied lambda so InvokeAsync sees a void delegate — it must NOT
        // await the dialog's own (deliberately long-lived) task.
        Task<bool> pending = null!;
        await cut.InvokeAsync(
            () => { pending = cut.Instance.ShowAsync("Compare", "before", "after"); });

        // Closing via the Close button completes the task with true.
        await cut.InvokeAsync(() => cut.Find("button.btn-secondary").Click());

        var completed = await Task.WhenAny(pending, Task.Delay(TimeSpan.FromSeconds(2)));
        Assert.Same(pending, completed);
        var result = await pending;
        Assert.True(result);
    }
}
