@inherits Radzen.RadzenComponent

<div @ref="editor" class="code-editor" dir="ltr"></div>
@code {
    IJSObjectReference monaco;
    ElementReference editor;
    DotNetObjectReference<Monaco> reference;

    [Parameter]
    public string Value { get; set; }

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

    [Parameter]
    public EventCallback<string> ValueChanged { get; set; }

    [Parameter]
    public string Language { get; set; }

    public string Id => GetId();

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            reference = DotNetObjectReference.Create(this);

            monaco = await JSRuntime.InvokeAsync<IJSObjectReference>("createEditor", editor, GetId(), reference, new {
                language = Language,
                theme = "vs",
                codeLens = false,
                readOnly = ReadOnly,
                minimap = new {
                    enabled = false
                },
                automaticLayout = true
            });

            interopValue = Value;

            await monaco.InvokeVoidAsync("setValue", interopValue);
        }
    }

    private string interopValue;

    [JSInvokable]
    public async Task OnChangeAsync(string value)
    {
        if (Value != value)
        {
            interopValue = value;
            await ValueChanged.InvokeAsync(value);
        }
    }

    public override async Task SetParametersAsync(ParameterView parameters)
    {
        var valueChanged = parameters.DidParameterChange(nameof(Value), Value);
        var readOnlyChanged = parameters.DidParameterChange(nameof(ReadOnly), ReadOnly);

        await base.SetParametersAsync(parameters);

        if (monaco != null && valueChanged && interopValue != Value)
        {
            interopValue = Value;

            await monaco.InvokeVoidAsync("setValue", interopValue);
        }

        if (monaco != null && readOnlyChanged)
        {
            await monaco.InvokeVoidAsync("setOptions", new { readOnly = ReadOnly });
        }
    }

    public override void Dispose()
    {
        base.Dispose();

        if (JSRuntime != null && monaco != null)
        {
            monaco.InvokeVoidAsync("dispose");
        }

        monaco?.DisposeAsync();

        reference?.Dispose();
    }
}