@implements IAsyncDisposable

@using Microsoft.AspNetCore.SignalR.Client
@using RobotNet.WebApp.Scripts.Models

@inject IHttpClientFactory httpFactory
@inject ScriptTaskHubClient ScriptTaskHub
@inject ISnackbar Snackbar

<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="scriptTasks" Height="@TableHeight" FixedHeader Virtualize Hover Elevation="6">
            <ToolBarContent>
                <div @ref="toolbarRef" class="w-100 d-flex flex-row">
                    <h3>Danh sách Script Tasks</h3>
                    <MudSpacer />
                </div>
            </ToolBarContent>
            <ColGroup>
                <col style="width:60px;" />
                <col />
                <col />
                <col style="width:60px;" />
                <col style="width:60px;" />
            </ColGroup>
            <HeaderContent>
                <MudTh></MudTh>
                <MudTh>Tên</MudTh>
                <MudTh>Khoảng thời gian (ms)</MudTh>
                <MudTh>Enable</MudTh>
                <MudTh>Script</MudTh>
            </HeaderContent>
            <RowTemplate>
                <MudTd>@context.Index</MudTd>
                <MudTd DataLabel="Tên">@context.Name</MudTd>
                <MudTd DataLabel="Khoảng thời gian">@context.Interval</MudTd>
                <MudTd DataLabel="Enable">
                    <MudSwitch T="bool" @bind-Value="context.Enable" @bind-Value:after="@(() => RequestTaskAction(context.Name, context.Enable))" Color="Color.Primary" Disabled="@actionDisable" />
                </MudTd>
                <MudTd DataLabel="Script">
                    <MudIconButton Icon="@Icons.Material.Filled.Visibility" Color="Color.Primary" Size="Size.Small"
                                   OnClick="@(() => ShowCodeDialog(context.Code))" />
                </MudTd>
            </RowTemplate>
        </MudTable>
    </div>
</div>

<MudDialog @bind-Visible="_codeDialogOpen" Style="min-width: 900px;">
    <DialogContent>
        <h6>Mã Script đầy đủ</h6>
        <MudPaper Class="pa-2" Style="overflow-x:auto;">
            <pre style="white-space:pre-wrap;word-break:break-all;">@_selectedCode</pre>
        </MudPaper>
    </DialogContent>
    <DialogActions>
        <MudButton OnClick="CloseCodeDialog">Đóng</MudButton>
    </DialogActions>
</MudDialog>

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

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

    private HttpClient http = default!;
    private List<ScriptTaskModel> scriptTasks = [];

    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();
        }
    }

    // Dialog state
    private bool _codeDialogOpen = false;
    private string? _selectedCode;

    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;

        ScriptTaskHub.TaskResumed += OnTaskResumed;
        ScriptTaskHub.TaskPaused += OnTaskPaused;

        await ScriptTaskHub.StartAsync();
    }

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

        }
    }

    private bool isRebuild = false;
    private bool actionDisable = true;
    private void OnProcessorStateChanged(ProcessorState state)
    {
        if (state == ProcessorState.Building)
        {
            isRebuild = true;
        }
        else if (state == ProcessorState.Ready)
        {
            if (isRebuild)
            {
                isRebuild = false;
                _ = InvokeAsync(async Task () =>
                {
                    await ReloadData();
                });
            }
        }

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

        if (state == ProcessorState.Running)
        {
            _ = InvokeAsync(async Task () =>
            {
                var states = await ScriptTaskHub.GetTaskStates();
                foreach (var task in scriptTasks)
                {
                    task.Enable = states.ContainsKey(task.Name) && states[task.Name];
                }
                StateHasChanged();
            });
        }
    }

    private async Task ReloadData()
    {
        await InvokeAsync(async Task () =>
        {
            scriptTasks.Clear();
            var tasks = await http.GetFromJsonAsync<List<ScriptTaskDto>>("/api/ScriptTasks") ?? [];
            foreach (var item in tasks.Select((value, index) => (value, index)))
            {
                scriptTasks.Add(new ScriptTaskModel(item.index + 1, item.value));
            }
            if (!actionDisable)
            {
                var states = await ScriptTaskHub.GetTaskStates();
                foreach (var task in scriptTasks)
                {
                    task.Enable = states.ContainsKey(task.Name) && states[task.Name];
                }

            }
            StateHasChanged();
        });
    }

    private void ShowCodeDialog(string code)
    {
        _selectedCode = code;
        _codeDialogOpen = true;
    }

    private void CloseCodeDialog()
    {
        _codeDialogOpen = false;
        _selectedCode = null;
    }

    private void OnTaskResumed(string taskName)
    {
        foreach (var task in scriptTasks)
        {
            if (task.Name == taskName)
            {
                task.Enable = true;
                StateHasChanged();
                break;
            }
        }
    }

    private void OnTaskPaused(string taskName)
    {
        foreach (var task in scriptTasks)
        {
            if (task.Name == taskName)
            {
                task.Enable = false;
                StateHasChanged();
                break;
            }
        }
    }

    private async Task RequestTaskAction(string name, bool enable)
    {
        if (actionDisable) return;
        if (enable)
        {
            var result = await ScriptTaskHub.Resume(name);
            if (!result.IsSuccess)
            {
                Snackbar.Add(result.Message, Severity.Error);
                OnTaskPaused(name);
            }
        }
        else
        {
            var result = await ScriptTaskHub.Pause(name);
            if (!result.IsSuccess)
            {
                Snackbar.Add(result.Message, Severity.Error);
                OnTaskResumed(name);
            }
        }
    }

    public async ValueTask DisposeAsync()
    {
        ProcessorHub.StateChanged -= OnProcessorStateChanged;
        ProcessorHub.ConnectionStateChanged -= OnConnectionStateChanged;
        ScriptTaskHub.TaskResumed -= OnTaskResumed;
        ScriptTaskHub.TaskPaused -= OnTaskPaused;
        await ScriptTaskHub.StartAsync();
    }
}
