@implements IAsyncDisposable
@using Microsoft.JSInterop
@inject IJSRuntime JSRuntime

@foreach (var tooltip in tooltips)
{
    @if (tooltip?.Options?.ChildContent != null && Service != null)
    {
        <div id="@UniqueID"
             style="display: none; top: 0; left: 0; z-index: 1001; position: absolute;"
             class="@($"rz-scheme-{tooltip.Options.ColorScheme.ToString().ToLowerInvariant()}")">
            @tooltip.Options.ChildContent(Service)
        </div>
    }
}

@code {
    public string? UniqueID { get; set; }

    [Inject] private TooltipService? Service { get; set; }

    List<ChartTooltip> tooltips = new List<ChartTooltip>();

    async Task Open(ElementReference chart, double x, double y, ChartTooltipOptions options)
    {
        tooltips.Clear();
        tooltips.Add(new ChartTooltip { Options = options, Chart = chart, X = x, Y = y });

        await InvokeAsync(StateHasChanged);

        var tooltip = tooltips.LastOrDefault();

        if (tooltip != null)
        {
            await JSRuntime.InvokeVoidAsync("Radzen.openChartTooltip",
                tooltip.Chart,
                x,
                y,
                UniqueID);
        }
    }

    bool IsJSRuntimeAvailable { get; set; }

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        IsJSRuntimeAvailable = true;

        var tooltip = tooltips.LastOrDefault();

        if (tooltip != null)
        {
            await JSRuntime.InvokeVoidAsync("Radzen.openChartTooltip",
                tooltip.Chart,
                tooltip.X,
                tooltip.Y,
                UniqueID,
                Reference,
                "RadzenChartTooltip.CloseTooltip");
        }
    }

private DotNetObjectReference<RadzenChartTooltip>? reference;

    /// <summary>
    /// Gets the reference for the current component.
    /// </summary>
    /// <value>The reference.</value>
    protected DotNetObjectReference<RadzenChartTooltip> Reference
    {
        get
        {
            if (reference == null)
            {
                reference = DotNetObjectReference.Create(this);
            }

            return reference;
        }
    }

    /// <summary>
    /// Closes this instance.
    /// </summary>
    [JSInvokable("RadzenChartTooltip.CloseTooltip")]
    public void CloseTooltip()
    {
        Service?.Close();
    }

    public async Task Close()
    {
        var lastTooltip = tooltips.LastOrDefault();
        if (lastTooltip != null)
        {
            if (IsJSRuntimeAvailable)
            {
                try
                {
                    tooltips.Remove(lastTooltip);
                    await JSRuntime.InvokeVoidAsync("Radzen.closeTooltip", UniqueID);
                }
                catch
                {
                    // ignored
                }
            }

        }

        await InvokeAsync(StateHasChanged);
    }

    public async ValueTask DisposeAsync()
    {
        while (tooltips.Count != 0)
        {
            await Close();
        }
        reference?.Dispose();
        reference = null;

        if (IsJSRuntimeAvailable)
        {
            try
            {
               await JSRuntime.InvokeVoidAsync("Radzen.destroyPopup", UniqueID);
            }
            catch
            {
                // ignored
            }
        }

        if (Service != null)
        {
            Service.OnOpenChartTooltip -= OnOpen;
            Service.OnClose -= OnClose;
            Service.OnNavigate -= OnNavigate;
        }
    }

    protected override void OnInitialized()
    {
        UniqueID = Convert.ToBase64String(Guid.NewGuid().ToByteArray()).Replace("/", "-").Replace("+", "-").Substring(0, 10);

        if (Service != null)
        {
            Service.OnOpenChartTooltip += OnOpen;
            Service.OnClose += OnClose;
            Service.OnNavigate += OnNavigate;
        }
    }

    void OnOpen(ElementReference element, double x, double y, ChartTooltipOptions options)
    {
        Open(element, x, y, options).ConfigureAwait(false);
    }

    void OnClose()
    {
        Close().ConfigureAwait(false);
    }

    void OnNavigate()
    {
        JSRuntime.InvokeVoidAsync("Radzen.closePopup", UniqueID);
    }

    private sealed class ChartTooltip
    {
        /// <summary>
        /// Gets or sets the owning chart.
        /// </summary>
        /// <value>The chart.</value>
        public ElementReference Chart { get; set; }
        /// <summary>
        /// Gets or sets the horizontal position of the tooltip.
        /// </summary>
        /// <value>The position.</value>
        public double X { get; set; }
        /// <summary>
        /// Gets or sets the vertical position of the tooltip.
        /// </summary>
        /// <value>The position.</value>
        public double Y { get; set; }
        /// <summary>
        /// Gets or sets the options.
        /// </summary>
        /// <value>The options.</value>
        public ChartTooltipOptions? Options { get; set; }
    }
}
