using System.Text.Json;
using System.Text.Json.Serialization;
using OneOf;

namespace AsyncApiRenderer.Data;

public class OneOfConverter<T1, T2> : JsonConverter<OneOf<T1, T2>?>
    where T1 : notnull
    where T2 : notnull
{
    public override OneOf<T1, T2>? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        if (reader.TokenType == JsonTokenType.Null)
            return (OneOf<T1, T2>?)null;
        var conv1 = (JsonConverter<T1>)options.GetConverter(typeof(T1));
        try
        {
            var readerCopy = reader;
            var value = conv1.Read(ref readerCopy, typeof(T1), options);
            if (value is not null)
            {
                reader = readerCopy;
                return value;
            }
        }
        catch (JsonException) {}
        
        var conv2 = (JsonConverter<T2>)options.GetConverter(typeof(T2));
        var value2 = conv2.Read(ref reader, typeof(T2), options)!;
        if (value2 is null)
        {
            return new OneOf<T1, T2>?();
        }
        else return value2;
    }

    public override void Write(Utf8JsonWriter writer, OneOf<T1, T2>? value, JsonSerializerOptions options)
    {
        if (value is null)
            writer.WriteNullValue();
        else value.Value.Switch(
            v =>
            {
                var conv = (JsonConverter<T1>)options.GetConverter(typeof(T1));
                conv.Write(writer, v, options);
            },
            v => 
            {
                var conv = (JsonConverter<T2>)options.GetConverter(typeof(T2));
                conv.Write(writer, v, options);
            }
        );
    }
}