@if (_isOpen)
{
    <div class="modal fade show"
         style="display: block;"
         tabindex="-1"
         role="dialog"
         aria-modal="true"
         @onkeydown="OnKeyDown">

        <div class="modal-dialog" role="document">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title">@_title</h5>
                    <button type="button" class="btn-close" aria-label="Close" @onclick="Cancel"></button>
                </div>

                <div class="modal-body">
                    <p class="mb-0">@_message</p>
                </div>

                <div class="modal-footer">
                    <button type="button" class="btn btn-outline-secondary" @onclick="Cancel" disabled="@_isBusy">
                        @_cancelText
                    </button>
                    <button type="button" class="btn btn-danger" @onclick="Confirm" disabled="@_isBusy">
                        @_confirmText
                    </button>
                </div>
            </div>
        </div>
    </div>

    <div class="modal-backdrop fade show"></div>
}

@code {
    private bool _isOpen;
    private bool _isBusy;

    private string _title = "Confirm";
    private string _message = "";
    private string _confirmText = "Confirm";
    private string _cancelText = "Cancel";

    private TaskCompletionSource<bool>? _tcs;

    public Task<bool> ShowAsync(
        string title,
        string message,
        string confirmText = "Delete",
        string cancelText = "Cancel")
    {
        // If already open, complete the previous request as "false"
        _tcs?.TrySetResult(false);

        _title = title;
        _message = message;
        _confirmText = confirmText;
        _cancelText = cancelText;

        _isBusy = false;
        _isOpen = true;

        _tcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
        StateHasChanged();

        return _tcs.Task;
    }

    private void Confirm()
    {
        if (!_isOpen) return;

        _isBusy = true;
        StateHasChanged();

        Close(true);
    }

    private void Cancel()
    {
        if (!_isOpen) return;
        Close(false);
    }

    private void Close(bool result)
    {
        _isOpen = false;
        _isBusy = false;

        var tcs = _tcs;
        _tcs = null;

        StateHasChanged();
        tcs?.TrySetResult(result);
    }

    private void OnKeyDown(KeyboardEventArgs e)
    {
        if (e.Key is "Escape")
            Cancel();
    }
}