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

namespace adas_core.Infrastructure.Utils;

public class PatientPumpObservationConverter : JsonConverter<PumpObservation>, 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 PumpObservation ReadJson(JsonReader reader, Type objectType,
        PumpObservation? existingValue,
        bool hasExistingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    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, "Event");
            AddStringEnumConverterAttribute(value, "Status");
            AddStringEnumConverterAttribute(value, "PumpMode");
            AddStringEnumConverterAttribute(value, "InfusingStatus");
            AddStringEnumConverterAttribute(value, "AlarmMode");

            jo.WriteTo(writer);
        }
    }

    public override void WriteJson(JsonWriter writer, PumpObservation? value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    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);
            }
        }
    }
}

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