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

namespace adas_core.Domain.Models;

public class PatientTreatment : JsonConverter
{
    //If bolopom plus to bolus opiates.
    public bool BoloPom = false;

    //If single Dose is true, finish at end of actual shift.
    public bool SingleDose = false;
    public ObjectId Id { get; set; }


    public ObjectId PatientId { get; set; }


    // ORC Common Order 

    public OrderControlType OrderControl { get; set; }

    public Entity? PlacerOrder { get; set; }

    public Entity? FillerOrder { get; set; }


    public string OrderStatus { get; set; } = string.Empty;


    public DateTime? OrderTime { get; set; }


    public DateTime? EndTime { get; set; }


    public DateTime? StartTime { get; set; }

    // RXO Pharmacy/Treatment Route

    public List<Code> RequestedGiveCodes { get; set; } = [];

    public string RequestedGiveTreatment { get; set; } = string.Empty;

    // RXA - Pharmacy/Treatment Administration
    public List<CodeStatus> RequestedGiveCodesStatus { get; set; } = [];


    public double? RequestedGiveAmountMinimum { get; set; }


    public double? RequestedGiveAmountMaximum { get; set; }


    public Code? RequestedGiveUnits { get; set; }


    public Code? RequestedDosageForm { get; set; }

    // NTE Notes and comments

    public List<Note> Notes { get; set; } = [];

    // RXR Pharmacy/Treatment Route
    public List<TreatmentRoute> Routes { get; set; } = [];

    //MSH Time of HL7

    public DateTime MessageTime { get; set; }


    public string? SystemId { get; set; }


    public override string ToString()
    {
        try
        {
            List<string> items =
            [
                $"id: {Id}",
                $"patientid: {PatientId}",
                $"orderControl: {OrderControl}"
            ];
            if (PlacerOrder != null) items.Add($"placerOrder: {PlacerOrder}");
            if (FillerOrder != null) items.Add($"fillerOrder: {FillerOrder}");
            if (!string.IsNullOrEmpty(OrderStatus)) items.Add($"orderStatus: {OrderStatus}");

            if (OrderTime != null) items.Add($"orderTime: {OrderTime}");
            if (StartTime != null) items.Add($"startTime: {StartTime}");
            if (EndTime != null) items.Add($"endTime: {EndTime}");

            if (RequestedGiveCodes.Any()) RequestedGiveCodes.ForEach(c => items.Add($"RequestedGiveCodes: {c}"));


            if (!string.IsNullOrEmpty(RequestedGiveTreatment))
                items.Add($"requestedGiveTreatment: {RequestedGiveTreatment}");

            if (RequestedGiveCodesStatus.Any()) RequestedGiveCodesStatus.ForEach(c => items.Add($"{c}"));

            if (RequestedGiveAmountMinimum != null)
                items.Add($"requestedGiveAmountMinimum: {RequestedGiveAmountMinimum}");
            if (RequestedGiveAmountMaximum != null)
                items.Add($"requestedGiveAmountMaximum: {RequestedGiveAmountMaximum}");

            if (RequestedGiveUnits != null) items.Add($"requestedGiveUnits: {RequestedGiveUnits}");
            if (RequestedDosageForm != null) items.Add($"requestedDosageForm: {RequestedDosageForm}");

            Notes.ForEach(n => items.Add($"{n}"));

            Routes.ForEach(r => items.Add($"{r}"));

            items.Add($"singleDose: {SingleDose}");
            items.Add($"boloPom: {BoloPom}");
            items.Add($"messageTime: {MessageTime}");

            if (!string.IsNullOrEmpty(SystemId)) items.Add($"systemId: {SystemId}");


            return "PatientTreatment[" + string.Join(", ", items) + "]";
        }
        catch (Exception ex)
        {
            //Log.Error("Error parsing PatientTreatment to string. Exception: {ex}", ex);
            return "Error deserielizing:" + ex.Message;
        }
    }

    public override 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, nameof(OrderControl));

            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 object ReadJson(JsonReader reader, Type objectType, object? existingValue,
        JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override bool CanConvert(Type objectType)
    {
        throw new NotImplementedException();
    }
}