@implements IDisposable

@using Microsoft.AspNetCore.SignalR.Client
@using RobotNet.Clients
@using RobotNet.Shares

@inject IHttpClientFactory httpFactory
@inject ISnackbar Snackbar
@inject IDialogService DialogService

<div class="flex-grow-1 h-100 position-relative overflow-hidden">
    <div @ref="divRef" class="w-100 h-100 position-absolute top-0 start-0 overflow-hidden">
        <MudTable Style="margin: 10px;" Items="_items" Height="@TableHeight" FixedHeader Virtualize Hover Elevation="6">
            <ToolBarContent>
                <div @ref="toolbarRef" class="w-100 d-flex flex-row">
                    <h3>Global Variables</h3>
                    <MudSpacer />
                    <ActionButton Icon="mdi-refresh text-primary" Large Tooltip="Reset" OnClick="ReloadData" />
                </div>
            </ToolBarContent>
            <ColGroup>
                <col style="width:60px;" />
                <col />
                <col />
                <col />
                <col style="width:90px;" />
            </ColGroup>
            <HeaderContent>
                <MudTh></MudTh>
                <MudTh>Name</MudTh>
                <MudTh>Type</MudTh>
                <MudTh>Value</MudTh>
                <MudTh></MudTh>
            </HeaderContent>
            <RowTemplate>
                <MudTd>@context.Index</MudTd>
                <MudTd DataLabel="Name">@context.Name</MudTd>
                <MudTd DataLabel="Type">@context.TypeName</MudTd>
                <MudTd DataLabel="Value">@context.Value</MudTd>
                <MudTd>
                    <span>
                        <MudIconButton Icon="@Icons.Material.Filled.Edit" Color="Color.Primary" Size="Size.Small"
                                       Disabled="@CallDisabled" OnClick="@(() => ShowSetValueDialog(context))" />
                    </span>
                    <span>
                        <MudIconButton Icon="@Icons.Material.Filled.Refresh" Color="Color.Secondary" Size="Size.Small"
                                       Disabled="@CallDisabled" OnClick="@(() => ResetValue(context))" />
                    </span>
                </MudTd>
            </RowTemplate>
        </MudTable>
    </div>
</div>

@code {
    [CascadingParameter]
    private ProcessorHubClient ProcessorHub { get; set; } = null!;

    private string TableHeight = "0px";
    private ElementReference divRef;
    private ElementReference toolbarRef;

    private HttpClient http = default!;
    private List<ScriptVariableModel> _items = [];

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        await base.OnAfterRenderAsync(firstRender);
        if (firstRender)
        {
            var rect = await divRef.MudGetBoundingClientRectAsync();
            var toolbarRect = await toolbarRef.MudGetBoundingClientRectAsync();
            TableHeight = $"{rect.Height - 25 - Math.Max(toolbarRect.Height, 64)}px";
            StateHasChanged();
        }
    }

    protected override async Task OnInitializedAsync()
    {
        await base.OnInitializedAsync();
        http = httpFactory.CreateClient("ScriptManagerAPI");
        await ReloadData();

        if (ProcessorHub.IsConnected)
        {
            OnProcessorStateChanged(await ProcessorHub.GetState());
        }

        ProcessorHub.StateChanged += OnProcessorStateChanged;
        ProcessorHub.ConnectionStateChanged += OnConnectionStateChanged;
    }


    private void OnConnectionStateChanged(HubConnectionState state)
    {
        if (state == HubConnectionState.Connected)
        {
            _ = InvokeAsync(async Task () =>
            {
                OnProcessorStateChanged(await ProcessorHub.GetState());
            });

        }
    }

    private bool CallDisabled = true;
    private void OnProcessorStateChanged(ProcessorState state)
    {
        if (state == ProcessorState.Ready)
        {
            _ = InvokeAsync(async Task () =>
            {
                await ReloadData();
            });
        }

        if (CallDisabled)
        {
            if (state == ProcessorState.Running)
            {
                CallDisabled = false;
                StateHasChanged();
            }
        }
        else
        {
            if (state != ProcessorState.Running)
            {
                CallDisabled = true;
                StateHasChanged();
            }
        }
    }

    private async Task ReloadData()
    {
        _items.Clear();

        var vars = await http.GetFromJsonAsync<IEnumerable<ScriptVariableDto>>("/api/ScriptVariables") ?? [];
        foreach (var item in vars.Select((value, index) => (value, index)))
        {
            _items.Add(new ScriptVariableModel(item.index + 1, item.value));
        }
        StateHasChanged();
    }

    private async Task ResetValue(ScriptVariableModel model)
    {
        if (CallDisabled) return;

        var result = await http.PutFromJsonAsync<MessageResult>($"/api/ScriptVariables/{model.Name}/Reset", new UpdateVariableModel(model.Name, ""));
        if(result == null)
        {
            Snackbar.Add("Failed to reset variable value: server response null", Severity.Error);
        }
        else if (result.IsSuccess)
        {
            Snackbar.Add(result.Message, Severity.Success);
        }
        else
        {
            Snackbar.Add($"Failed to reset variable value: {result.Message}", Severity.Error);
        }
    }

    private async Task ShowSetValueDialog(ScriptVariableModel model)
    {

        if (CallDisabled) return;

        var parameters = new DialogParameters<SetVariableValueDialog>()
        {
            {x => x.Model, model},
        };

        var dialog = await DialogService.ShowAsync<SetVariableValueDialog>("Set Variable Value", parameters);
        var resultDialog = await dialog.Result;
    }

    public void Dispose()
    {
        ProcessorHub.StateChanged -= OnProcessorStateChanged;
        ProcessorHub.ConnectionStateChanged -= OnConnectionStateChanged;
    }
}
