#nullable enable
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.JSInterop;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Bootstrap
{
    public partial class Popover : IAsyncDisposable
    {
        [Parameter] public PopoverOptions Options { get; set; } = new PopoverOptions();
        [Parameter] public RenderFragment? ChildContent { get; set; }
        [Parameter] public string Title { get; set; } = String.Empty;
        [Parameter] public string Content { get; set; } = String.Empty;
        [Parameter] public bool Html { get; set; } = true;
        [Parameter] public PopoverPlacement Placement { get; set; } = PopoverPlacement.Right;
        [Parameter] public Func<Task<string>>? GetContent { get; set; }
        [Parameter(CaptureUnmatchedValues = true)] public Dictionary<string, object> AllOtherAttributes { get; set; } = new Dictionary<string, object>();

        private Guid _id;
        private bool _rendered = false;
        private bool _isDisposed;

        private IJSObjectReference? jsModule { get; set; }
        public Popover()
        {
            _id = Guid.NewGuid();
        }

        protected override async Task OnAfterRenderAsync(bool firstRender)
        {
            if (firstRender)
            {
                _rendered = true;
                jsModule = await jsRuntime.InvokeAsync<IJSObjectReference>("import", "./_content/Bootstrap/bootstrap.popover.js");
                await Setup();
            }
        }

        protected override async Task OnParametersSetAsync()
        {
            if (_rendered && !_isDisposed)
            {
                await Update();
            }
        }

        public async ValueTask DisposeAsync()
        {
            _isDisposed = true;
            await Destroy();
            if (jsModule is not null)
            {
                await jsModule.DisposeAsync();
                jsModule = null;
            }
        }

        private async Task Setup()
        {
            if (jsModule is not null)
            {
                var realOpt = GetOptions();

                if (GetContent is not null)
                {
                    realOpt.Content = await GetContent.Invoke();
                }
                try
                {
                    await jsModule.InvokeVoidAsync("setup", new object[] { _id, realOpt.ToJSON() });
                }
                catch (Exception e)
                {

                }
            }
        }

        private async Task Destroy()
        {
            if (jsModule is not null)
            {
                try
                {
                    await jsModule.InvokeVoidAsync("destroy", _id);
                    await jsModule.DisposeAsync();
                }
                catch (TaskCanceledException)
                {
                }
                catch (JSDisconnectedException)
                {
                }
            }
        }

        private async Task Update()
        {
            if (jsModule is not null)
            {
                await jsModule.InvokeVoidAsync("update", new object[] { _id, GetOptions().ToJSON() });
            }
        }

        private PopoverOptions GetOptions()
        {
            Options.Html = Html;
            Options.Title = Title;
            Options.Content = Content;
            Options.Placement = Placement;
            return Options;
        }
    }
}