@inject IJSRuntime JSRuntime
@implements IAsyncDisposable

@ChildContent

@code {
    /// <summary>
    /// Callback when clicked outside the child.
    /// </summary>
    [Parameter]
    public EventCallback<bool> OnClose { get; set; }

    /// <summary>
    /// The content id of the modal which is used to identity if a click is inside or outside the modal.
    /// </summary>
    [Parameter]
    public string ContentId { get; set; } = "modal-content";

    /// <summary>
    /// The child content of the component.
    /// </summary>
    [Parameter]
    public required RenderFragment ChildContent { get; set; }

    private DotNetObjectReference<ClickOutsideHandler>? ObjRef { get; set; }

    private IJSObjectReference? Module { get; set; }

    /// <inheritdoc />
    protected override async Task OnInitializedAsync()
    {
        await LoadModuleAsync();
    }

    /// <inheritdoc />
    protected override async Task OnParametersSetAsync()
    {
        await LoadModuleAsync();

        if (Module != null)
        {
            await Module.InvokeVoidAsync("registerClickOutsideHandler", ObjRef, ContentId, nameof(CloseHandler));
        }
    }

    /// <summary>
    /// Call close handler on parent component.
    /// </summary>
    [JSInvokable]
    public async Task CloseHandler()
    {
        await OnClose.InvokeAsync();
        StateHasChanged();
    }

    /// <inheritdoc />
    public async ValueTask DisposeAsync()
    {
        if (Module is not null)
        {
            await Module.InvokeVoidAsync("unregisterClickOutsideHandler");
            await Module.DisposeAsync();
        }

        ObjRef?.Dispose();
    }

    /// <summary>
    /// Load the JavaScript module.
    /// </summary>
    private async Task LoadModuleAsync()
    {
        if (Module is null)
        {
            Module = await JSRuntime.InvokeAsync<IJSObjectReference>("import", "./js/modules/clickOutsideHandler.js");
            ObjRef = DotNetObjectReference.Create(this);
        }
    }
}
