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 PatientObservationAlarmConverter : JsonConverter<PatientObservationAlarm>, 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 => typeof(PatientObservationAlarm);

    public override PatientObservationAlarm? ReadJson(JsonReader reader, Type objectType,
        PatientObservationAlarm? existingValue,
        bool hasExistingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
            return null;

        // Implement your custom deserialization logic here
        var jsonObject = JObject.Load(reader);
        // Deserialize properties from jsonObject to PatientObservationAlarm object

        // Example: Deserialize 'Value' property
        var value = jsonObject.GetValue("value")?.ToObject<object>();

        return new PatientObservationAlarm
        {
            Value = value ?? new object()
            // Other property assignments...
        };
    }

    public new void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
    {
        if (value != null)
        {
            var jo = JObject.FromObject(value);

            // Add [JsonConverter(typeof(StringEnumConverter))] attribute to specified properties
            AddStringEnumConverterAttribute(value, "eventPhase");
            AddStringEnumConverterAttribute(value, "state");
            AddStringEnumConverterAttribute(value, "priority");
            AddStringEnumConverterAttribute(value, "type");

            jo.Property("messageTime")?.Remove();
            jo.Property("expired")?.Remove();
            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)
        {
            var attrs = prop.GetCustomAttributes(false);

            // Check if the attribute is not already applied
            if (Array.Find(attrs, a => a is JsonConverterAttribute) == null)
            {
                // 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 void WriteJson(JsonWriter writer, PatientObservationAlarm? value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

/*How to use it:
    BsonSerializer.RegisterSerializer(new PatientObservationAlarmConverter());
    JsonConvert.DefaultSettings = () => new JsonSerializerSettings
    {
        Converters = { new PatientObservationAlarmConverter() }
    };
*/