@implements IDisposable

@inject IJSRuntime JSRuntime
@inject IHttpClientFactory HttpFactory

<image @ref="@RobotRef" />
<image @ref="@ElementRef" visibility="@(isCarrying ? "visible" : "hidden")" />
<text @ref="textRef" visibility="@(ShowName ? "visible" : "hidden")">@Model?.RobotName</text>

@code {
    [Parameter, EditorRequired]
    public RobotVisualizationModel Model { get; set; } = null!;

    [Parameter]
    public bool ShowName { get; set; }

    private ElementReference ElementRef;
    private ElementReference RobotRef;
    private ElementReference textRef;
    private RobotModelDto RobotModel = new();

    private bool isCarrying = false;
    private ElementModelDto ElementModel = new();

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        await base.OnAfterRenderAsync(firstRender);
        if (!firstRender) return;

        using var Http = HttpFactory.CreateClient("RobotManagerAPI");
        var model = await Http.GetFromJsonAsync<MessageResult<RobotModelDto?>>($"api/Robots/Model/{Model.RobotId}");
        if (model is not null && model.Data is not null)
        {
            await JSRuntime.InvokeVoidAsync("SetImageAttribute", RobotRef, model.Data.Length, model.Data.Width, model.Data.OriginX, model.Data.OriginY, $"{Http.BaseAddress}api/RobotModels/image/{model.Data.Id}");
            RobotModel = model.Data;
        }
        if (Model is not null)
        {
            Model.PositionChanged += Model_PositionChanged;
            Model.LoadsChanged += Model_LoadChanged;
            await UpdatePosition(Model.X, Model.Y, Model.Theta);
            if(Model.Loads.Length > 0 && Guid.TryParse(Model.Loads[0].LoadId, out Guid loadId))
            {
                await Model_LoadChanged(loadId);
                await UpdateLoadPosition(Model.X, Model.Y, Model.Theta);
            }
        }
    }

    public override async Task SetParametersAsync(ParameterView parameters)
    {
        bool updateRobot = false;
        if (parameters.TryGetValue(nameof(Model), out RobotVisualizationModel? model) && ((Model?.RobotId ?? string.Empty) != (model?.RobotId ?? string.Empty)))
        {
            if (Model != null)
            {
                Model.PositionChanged -= Model_PositionChanged;
                Model.LoadsChanged -= Model_LoadChanged;
            }

            if (model != null)
            {
                updateRobot = true;
                model.PositionChanged += Model_PositionChanged;
                model.LoadsChanged += Model_LoadChanged;
            }
        }
        await base.SetParametersAsync(parameters);
        if (updateRobot && model != null) 
        {
            await UpdatePosition(model.X, model.Y, model.Theta);
            if (model.Loads.Length > 0) await UpdateLoadPosition(model.X, model.Y, model.Theta);
        }
    }

    private async Task Model_PositionChanged()
    {
        await UpdatePosition(Model.X, Model.Y, Model.Theta); 
        await UpdateLoadPosition(Model.X, Model.Y, Model.Theta);
    }

    public async Task UpdatePosition(double x, double y, double theta) 
        => await JSRuntime.InvokeVoidAsync("SetRobotPosition", RobotRef, textRef, x, y, theta, RobotModel.OriginX, RobotModel.OriginY);

    private async Task UpdateLoadPosition(double x, double y, double theta)
        => await JSRuntime.InvokeVoidAsync("SetRobotPosition", ElementRef, null, x, y, theta, -ElementModel.Width / 2, -ElementModel.Height / 2);

    private async Task Model_LoadChanged(Guid elementModelId)
    {
        if (elementModelId != Guid.Empty)
        {
            using var Http = HttpFactory.CreateClient("MapManagerAPI");
            var model = await Http.GetFromJsonAsync<MessageResult<ElementModelDto?>>($"api/ElementModels/{elementModelId}");
            if (model is not null && model.Data is not null)
            {
                isCarrying = true;;
                await JSRuntime.InvokeVoidAsync("SetImageAttribute", ElementRef, model.Data.Width, model.Data.Height, -model.Data.Width / 2, -model.Data.Height / 2, $"{Http.BaseAddress}api/images/elementModel/{model.Data.Id}?IsOpen=true");
                await UpdateLoadPosition(Model.X, Model.Y, Model.Theta);
                ElementModel = model.Data;
            }
        }
        else isCarrying = false;
        StateHasChanged();
    }

    public void Dispose()
    {
        if (Model != null) Model.PositionChanged -= Model_PositionChanged;
        GC.SuppressFinalize(this);
    }
}
