using System.Reflection;
using System.Text.Json;
using System.Text.Json.Serialization;

using Myriad.Utils;

namespace Myriad.Serialization;

public class OptionalConverterFactory: JsonConverterFactory
{
    public override JsonConverter? CreateConverter(Type typeToConvert, JsonSerializerOptions options)
    {
        var innerType = typeToConvert.GetGenericArguments()[0];
        return (JsonConverter?)Activator.CreateInstance(
            typeof(Inner<>).MakeGenericType(innerType),
            BindingFlags.Instance | BindingFlags.Public,
            null,
            null,
            null);
    }

    public override bool CanConvert(Type typeToConvert)
    {
        if (!typeToConvert.IsGenericType)
            return false;

        if (typeToConvert.GetGenericTypeDefinition() != typeof(Optional<>))
            return false;

        return true;
    }

    public class Inner<T>: JsonConverter<Optional<T>>
    {
        public override Optional<T> Read(ref Utf8JsonReader reader, Type typeToConvert,
                                         JsonSerializerOptions options)
        {
            var inner = JsonSerializer.Deserialize<T>(ref reader, options);
            return new Optional<T>(inner!);
        }

        public override void Write(Utf8JsonWriter writer, Optional<T> value, JsonSerializerOptions options)
        {
            JsonSerializer.Serialize(writer, value.HasValue ? value.GetValue() : default, typeof(T), options);
        }
    }
}