using System.Reflection;
using adas_core.Domain.Models;
using MongoDB.Bson.Serialization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;

namespace adas_core.Infrastructure.Utils;

public class PersonConverter(Type valueType) : JsonConverter<Person>, IBsonSerializer
{
    public object Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
    {
        throw new NotImplementedException();
    }

    public void Serialize(BsonSerializationContext context, BsonSerializationArgs args, object value)
    {
        throw new NotImplementedException();
    }

    public Type ValueType { get; } = valueType;

    public override void WriteJson(JsonWriter writer, Person? value, JsonSerializer serializer)
    {
        if (value == null) return;

        var jo = JObject.FromObject(value);

        // Add [JsonConverter(typeof(StringEnumConverter))] attribute to specified properties
        AddStringEnumConverterAttribute(value, "Gender");

        jo.WriteTo(writer);
    }

    private static void AddStringEnumConverterAttribute(object value, string propertyName)
    {
        var prop = value.GetType().GetProperty(propertyName);
        var attr = new JsonConverterAttribute(typeof(StringEnumConverter));

        if (prop == null) return;
        var attrs = prop.GetCustomAttributes(false);

        // Check if the attribute is not already applied
        if (Array.Find(attrs, a => a is JsonConverterAttribute) != null) return;

        // Create a new array that includes the existing attributes and the new one
        var newAttrs = new object[attrs.Length + 1];
        Array.Copy(attrs, newAttrs, attrs.Length);
        newAttrs[attrs.Length] = attr;

        // Use reflection to set the new attributes array
        var field = typeof(PropertyInfo).GetField("m_customAttributes",
            BindingFlags.Instance | BindingFlags.NonPublic);
        field?.SetValue(prop, newAttrs);
    }

    public override Person ReadJson(JsonReader reader, Type objectType, Person? existingValue, bool hasExistingValue,
        JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}