@implements IDisposable

@inject IHttpClientFactory HttpClientFactory
@inject IJSRuntime JSRuntime

<g class="element" visibility="@(IsShow ? "visible" : "hidden")" @ondblclick="@(async () =>  await DoubleClick.InvokeAsync(Model))">
    <image @ref="@ImageRef" />
    <text @ref="textRef" visibility="@(ShowName && IsShow ? "visible" : "hidden")">@Model?.Name</text>
</g>

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

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

    [Parameter]
    public EditorState EditorState { get; set; }

    [Parameter]
    public EventCallback<ElementModel> DoubleClick { get; set; }

    private ElementReference ImageRef;
    private ElementReference textRef;
    private ElementModelDto ElementModel = new();

    private bool IsSetting => EditorState == EditorState.View;
    private bool IsShow => EditorState == EditorState.View;
    private HttpClient? Http;

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

        Http = HttpClientFactory.CreateClient("MapManagerAPI");
        var model = await Http.GetFromJsonAsync<MessageResult<ElementModelDto?>>($"api/ElementModels/{Model.ModelId}");
        if (model is not null && model.Data is not null)
        {
            await JSRuntime.InvokeVoidAsync("SetImageAttribute", ImageRef, model.Data.Width, model.Data.Height, -model.Data.Width / 2, -model.Data.Height / 2, $"{Http.BaseAddress}api/images/elementModel/{model.Data.Id}?IsOpen={Model.IsOpen}");
            ElementModel = model.Data;
        }
        if (Model is not null)
        {
            Model.PositionChanged += Model_PositionChanged;
            Model.OffsetChanged += Model_OffsetChanged;
            await UpdatePosition(Model.X, Model.Y, Model.Theta);
        }
    }

    public override async Task SetParametersAsync(ParameterView parameters)
    {
        bool updateRobot = false;
        if (parameters.TryGetValue(nameof(Model), out ElementModel? model) && ((Model?.Id ?? Guid.Empty) != (model?.Id ?? Guid.Empty)))
        {
            if (Model != null)
            {
                Model.OffsetChanged -= Model_OffsetChanged;
                Model.PositionChanged -= Model_PositionChanged;
            }

            if (model != null)
            {
                updateRobot = true;
                model.OffsetChanged += Model_OffsetChanged;
                model.PositionChanged += Model_PositionChanged;

            }
        }
        await base.SetParametersAsync(parameters);
        if (updateRobot && model != null)
        {
            if (Http is null) Http = HttpClientFactory.CreateClient("MapManagerAPI");
            var elementModel = await Http.GetFromJsonAsync<MessageResult<ElementModelDto?>>($"api/ElementModels/{model.ModelId}");
            if (elementModel is not null && elementModel.Data is not null) ElementModel = elementModel.Data;
            await SetElementImage(model.IsOpen);
            await UpdatePosition(model.X, model.Y, model.Theta);
        }
    }

    private async Task SetElementImage(bool isOpen)
    {
        if (Http is null) Http = HttpClientFactory.CreateClient("MapManagerAPI");
        if(ElementModel is null)
        {
            var elementModel = await Http.GetFromJsonAsync<MessageResult<ElementModelDto?>>($"api/ElementModels/{Model.ModelId}");
            if (elementModel is not null && elementModel.Data is not null) ElementModel = elementModel.Data;
        }
        if (ElementModel is not null)
        {
            await JSRuntime.InvokeVoidAsync("SetImageAttribute", ImageRef, ElementModel.Width, ElementModel.Height, (-ElementModel.Width / 2), (-ElementModel.Height / 2), $"{Http.BaseAddress}api/images/elementModel/{ElementModel.Id}?IsOpen={isOpen}");
        }
    }

    public async Task UpdatePosition(double x, double y, double theta)
        => await JSRuntime.InvokeVoidAsync("SetElementPosition", ImageRef, textRef, x + Model.OffsetX, y + Model.OffsetY, theta, -ElementModel.Width / 2, -ElementModel.Height / 2);
    public async Task UpdatePosition(double offsetX, double offsetY)
        => await JSRuntime.InvokeVoidAsync("SetElementPosition", ImageRef, textRef, Model.X + offsetX, Model.Y + offsetY, Model.Theta, -ElementModel.Width / 2, -ElementModel.Height / 2);

    private async Task Model_PositionChanged() => await UpdatePosition(Model.X, Model.Y, Model.Theta);
    private async Task Model_OffsetChanged() => await UpdatePosition(Model.OffsetX, Model.OffsetY);

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