using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace PCL.Core.Utils;

// Partly generated by o4-mini (20250611)
// ReSharper disable All
#nullable disable

public sealed class ExpandoObjectConverter : JsonConverter<ExpandoObject>
{
    public static readonly ExpandoObjectConverter Default = new ExpandoObjectConverter();

    public ExpandoObjectConverter()
    {
    }

    public override ExpandoObject Read(
        ref Utf8JsonReader reader,
        Type typeToConvert,
        JsonSerializerOptions options)
    {
        if (reader.TokenType == JsonTokenType.Null)
        {
            return null;
        }

        using (JsonDocument document = JsonDocument.ParseValue(ref reader))
        {
            JsonElement root = document.RootElement;
            return Read(root, options);
        }
    }

    public static ExpandoObject Read(
        JsonElement element,
        JsonSerializerOptions options)
    {
        ExpandoObject expandoObject = new ExpandoObject();
        IDictionary<string, object> dict = expandoObject;
        foreach (JsonProperty property in element.EnumerateObject())
        {
            dict.Add(property.Name, _ConvertElement(property.Value, options));
        }

        return expandoObject;
    }

    private static object _ConvertElement(JsonElement element, JsonSerializerOptions options)
    {
        return element.ValueKind switch
        {
            JsonValueKind.Object => Read(element, options),
            JsonValueKind.Array => element.EnumerateArray()
                .Select(item => _ConvertElement(item, options))
                .ToList(),
            JsonValueKind.String => element.GetString(),
            JsonValueKind.Number when element.TryGetInt64(out var integer) => integer,
            JsonValueKind.Number when element.TryGetDouble(out var number) => number,
            JsonValueKind.True => true,
            JsonValueKind.False => false,
            JsonValueKind.Null => null,
            JsonValueKind.Undefined => null,
            _ => element.GetRawText()
        };
    }

    public override void Write(
        Utf8JsonWriter writer,
        ExpandoObject value,
        JsonSerializerOptions options)
    {
        if (value is null)
        {
            writer.WriteNullValue();
            return;
        }

        writer.WriteStartObject();

        foreach (KeyValuePair<string, object> kvp in value)
        {
            writer.WritePropertyName(kvp.Key);
            JsonSerializer.Serialize(writer, kvp.Value, options);
        }

        writer.WriteEndObject();
    }
}