@using MudBlazor
@using System.Reflection

<MudDialog>
    <DialogContent>
        @if (_isSimpleType)
        {
            @RenderEditor(ItemType, _workingValue, v => _workingValue = v, "Value")
        }
        else
        {
            @foreach (var prop in _properties)
            {
                var p = prop;
                var currentVal = p.GetValue(_workingValue);
                @RenderEditor(p.PropertyType, currentVal, v => p.SetValue(_workingValue, v), p.Name)
            }
        }
    </DialogContent>
    <DialogActions>
        <MudButton OnClick="Cancel">Cancel</MudButton>
        <MudButton Color="Color.Primary" OnClick="Ok">OK</MudButton>
    </DialogActions>
</MudDialog>

@code {
    [CascadingParameter] private IMudDialogInstance MudDialog { get; set; } = null!;
    [Parameter] public Type ItemType { get; set; } = null!;
    [Parameter] public object? InitialValue { get; set; }

    private object? _workingValue;
    private bool _isSimpleType;
    private PropertyInfo[] _properties = Array.Empty<PropertyInfo>();

    protected override void OnParametersSet()
    {
        _isSimpleType = ItemType.IsValueType || ItemType == typeof(string) || ItemType.IsEnum;
        _workingValue = InitialValue;

        if (!_isSimpleType && _workingValue != null)
        {
            _properties = ItemType.GetProperties(BindingFlags.Public | BindingFlags.Instance)
                .Where(p => p.CanRead && p.CanWrite)
                .ToArray();
        }
    }

    private RenderFragment RenderEditor(Type type, object? value, Action<object?> onChanged, string label) => builder =>
    {
        builder.OpenElement(0, "div");
        builder.AddAttribute(1, "class", "settings-field");

        if (type == typeof(bool))
        {
            var boolVal = (bool)(value ?? false);
            builder.OpenComponent<MudSwitch<bool>>(2);
            builder.AddAttribute(3, "Value", boolVal);
            builder.AddAttribute(4, "ValueChanged", EventCallback.Factory.Create<bool>(this, v => { onChanged(v); StateHasChanged(); }));
            builder.AddAttribute(5, "Label", label);
            builder.AddAttribute(6, "Color", Color.Primary);
            builder.CloseComponent();
        }
        else if (type == typeof(int))
        {
            var intVal = value is int iv ? iv : 0;
            builder.OpenComponent<MudNumericField<int>>(2);
            builder.AddAttribute(3, "Value", intVal);
            builder.AddAttribute(4, "ValueChanged", EventCallback.Factory.Create<int>(this, v => { onChanged(v); StateHasChanged(); }));
            builder.AddAttribute(5, "Label", label);
            builder.AddAttribute(6, "Variant", Variant.Outlined);
            builder.CloseComponent();
        }
        else if (type == typeof(double))
        {
            var dblVal = value is double dv ? dv : 0.0;
            builder.OpenComponent<MudNumericField<double>>(2);
            builder.AddAttribute(3, "Value", dblVal);
            builder.AddAttribute(4, "ValueChanged", EventCallback.Factory.Create<double>(this, v => { onChanged(v); StateHasChanged(); }));
            builder.AddAttribute(5, "Label", label);
            builder.AddAttribute(6, "Variant", Variant.Outlined);
            builder.CloseComponent();
        }
        else if (type.IsEnum)
        {
            builder.OpenComponent<MudSelect<object>>(2);
            builder.AddAttribute(3, "Value", value);
            builder.AddAttribute(4, "ValueChanged", EventCallback.Factory.Create<object>(this, v => { onChanged(v); StateHasChanged(); }));
            builder.AddAttribute(5, "Label", label);
            builder.AddAttribute(6, "Variant", Variant.Outlined);
            builder.AddAttribute(7, "ChildContent", (RenderFragment)(innerBuilder =>
            {
                foreach (var enumVal in Enum.GetValues(type))
                {
                    innerBuilder.OpenComponent<MudSelectItem<object>>(0);
                    innerBuilder.AddAttribute(1, "Value", enumVal);
                    innerBuilder.AddAttribute(2, "ChildContent", (RenderFragment)(b => b.AddContent(0, enumVal.ToString())));
                    innerBuilder.CloseComponent();
                }
            }));
            builder.CloseComponent();
        }
        else
        {
            var strVal = value?.ToString() ?? "";
            builder.OpenComponent<MudTextField<string>>(2);
            builder.AddAttribute(3, "Value", strVal);
            builder.AddAttribute(4, "ValueChanged", EventCallback.Factory.Create<string>(this, v => { onChanged(v); StateHasChanged(); }));
            builder.AddAttribute(5, "Label", label);
            builder.AddAttribute(6, "Variant", Variant.Outlined);
            builder.CloseComponent();
        }

        builder.CloseElement();
    };

    private void Ok() => MudDialog.Close(DialogResult.Ok(_workingValue));
    private void Cancel() => MudDialog.Cancel();
}
