using adas_core.Domain.Enums;
using adas_core.Domain.Models;
using adas_core.Domain.Models.MongoModels;
using adas_core.Domain.Models.Observations;
using adas_core.Domain.Utils;
using adas_core.Infrastructure.Utils.MongoMaps.Interfaz;
using MongoDB.Bson;
using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.Serializers;
using static adas_core.Domain.Models.GroupedObservation;

namespace adas_core.Infrastructure.Utils.MongoMaps;

/// <summary>
/// Represents a contributor that provides entity mapping logic for observations.
/// </summary>
/// <remarks>
/// Implements the <see cref="IEntityMapContributor"/> interface to participate in the entity mapping process.
/// </remarks>
public class ObservationMapContributor : IEntityMapContributor
{
    /// <summary>
    /// Registers BSON class maps for the observation-related domain types used by the application. Each registration is guarded by an <see cref="BsonClassMap.IsClassMapRegistered"/> check so the method is safe to invoke multiple times, configuring element names, ignoring null members, unmapping non-persisted members, and supplying custom enum and complex-object serializers where required.
    /// </summary>
    public void RegisterMaps()
        {
            if (!BsonClassMap.IsClassMapRegistered(typeof(BasePatientObservation)))
                BsonClassMap.RegisterClassMap<BasePatientObservation>(cm =>
                {
                    cm.AutoMap();
                    cm.MapIdMember(c => c.Id).SetElementName("_id");
                    cm.MapMember(c => c.PatientId).SetElementName("patientid");
                    cm.MapMember(c => c.UserId).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.ClinicalEpisode).SetIgnoreIfNull(true);
    
                    cm.UnmapMember(c => c.Patient);
                    cm.MapMember(c => c.SystemId).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.Code).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.CodingSystem).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.ParentData).SetIgnoreIfNull(true);
    
                    cm.MapMember(c => c.Time);
                    cm.MapMember(c => c.EndTime).SetIgnoreIfNull(true);
    
                    cm.MapMember(c => c.Name).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.Units).SetIgnoreIfNull(true);
                    cm.UnmapMember(c => c.CheckObservations);
    
                    cm.UnmapMember(c => c.CreateObservation);
    
    
                    cm.MapMember(c => c.PatientId).SetElementName("patientid");
                    cm.MapMember(c => c.EndTime).SetIgnoreIfNull(true);
                });
    
            if (!BsonClassMap.IsClassMapRegistered(typeof(BasePatientObservationValue)))
                BsonClassMap.RegisterClassMap<BasePatientObservationValue>(cm =>
                {
                    cm.AutoMap();
                    cm.MapMember(c => c.Value)
                        .SetDefaultValue(new object())
                        .SetSerializer(new ComplexObjectValueTypeSerializer());
                });
    
            if (!BsonClassMap.IsClassMapRegistered(typeof(PatientObservation)))
                BsonClassMap.RegisterClassMap<PatientObservation>(cm =>
                {
                    cm.AutoMap();
                    cm.MapMember(c => c.Max).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.Min).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.MaxWarn).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.MinWarn).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.WarnColor).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.AlertColor).SetIgnoreIfNull(true);
                    cm.UnmapMember(c => c.ShowOnExpired);
                    cm.MapMember(c => c.InsertMode)
                        .SetDefaultValue(ObservationEnum.InsertMode.Auto)
                        .SetSerializer(new EnumSerializer<ObservationEnum.InsertMode>(BsonType.String));
                    cm.UnmapMember(c => c.Persist);
                    cm.MapMember(c => c.ColorOnExpired).SetIgnoreIfNull(true);
                    cm.UnmapMember(c => c.MessageTime);
    
                    cm.MapMember(c => c.Result).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.Status)
                        .SetDefaultValue(StatusEnum.Type.Ok)
                        .SetSerializer(new EnumSerializer<StatusEnum.Type>(BsonType.String));
                    cm.UnmapMember(c => c.Level);
                    cm.UnmapMember(c => c.Expires);
                    cm.MapMember(c => c.Expired).SetDefaultValue(false);
                    cm.UnmapMember(c => c.UiConfiguration);
                    cm.UnmapMember(c => c.Alarm);
                });
    
            if (!BsonClassMap.IsClassMapRegistered(typeof(ParentDataClass)))
                BsonClassMap.RegisterClassMap<ParentDataClass>(cm =>
                {
                    cm.AutoMap();
                    cm.GetMemberMap(c => c.Code).SetIgnoreIfNull(true);
                    cm.GetMemberMap(c => c.CodingSystem).SetIgnoreIfNull(true);
                    cm.GetMemberMap(c => c.Name).SetIgnoreIfNull(true);
                });
    
            if (!BsonClassMap.IsClassMapRegistered(typeof(ObservationData)))
                BsonClassMap.RegisterClassMap<ObservationData>(cm =>
                {
                    cm.AutoMap();
                    cm.MapMember(c => c.CodingSystem).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.Code).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.Text).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.Time).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.Value).SetIgnoreIfNull(true);
                });
    
            if (!BsonClassMap.IsClassMapRegistered(typeof(ObservationsRequest)))
                BsonClassMap.RegisterClassMap<ObservationsRequest>(cm =>
                {
                    cm.AutoMap();
                    cm.MapMember(c => c.PatientNumber).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.ObservationNames).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.StartTime).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.EndTime).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.PageNumber).SetDefaultValue(1);
                    cm.MapMember(c => c.PageSize).SetDefaultValue(10);
                });
    
            if (!BsonClassMap.IsClassMapRegistered(typeof(DemoConfig)))
                BsonClassMap.RegisterClassMap<DemoConfig>(cm =>
                {
                    cm.AutoMap();
                    cm.MapMember(c => c.ValueOption)
                        .SetIgnoreIfNull(true);
                });
    
            if (!BsonClassMap.IsClassMapRegistered(typeof(ConfigObservation)))
                BsonClassMap.RegisterClassMap<ConfigObservation>(cm =>
                {
                    cm.AutoMap();
                    cm.MapIdMember(c => c.Id).SetElementName("_id");
                    cm.MapMember(c => c.DemoConfig).SetIgnoreIfNull(true);
                });
    
            if (!BsonClassMap.IsClassMapRegistered(typeof(ConfigObservation)))
                BsonClassMap.RegisterClassMap<ConfigObservation>(cm =>
                {
                    cm.AutoMap();
    
                    cm.MapMember(c => c.Code).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.CodingSystem).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.OriginalName).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.ParentCode).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.ParentCodingSystem).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.ParentName).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.Name).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.Units).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.ArrowType)
                        .SetSerializer(new EnumSerializer<ObservationEnum.ArrowType>(BsonType.String))
                        .SetDefaultValue(ObservationEnum.ArrowType.Default);
                    cm.MapMember(c => c.ShowArrow).SetDefaultValue(true);
                    cm.MapMember(c => c.ShowValue).SetDefaultValue(true);
                    cm.MapMember(c => c.ForceUnits).SetDefaultValue(false);
                    cm.MapMember(c => c.MinAlert).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.MaxAlert).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.MaxWarn).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.MinWarn).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.WarnColor).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.AlertColor).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.AlertValues).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.WarningValues).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.ForceWarn).SetDefaultValue(false);
                    cm.MapMember(c => c.ForceAlert).SetDefaultValue(false);
    
                    cm.MapMember(c => c.Alert).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.Expires).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.ShowOnExpired).SetIgnoreIfDefault(true);
                    cm.MapMember(c => c.Persist).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.ColorOnExpired).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.RetentionPolicy)
                        .SetIgnoreIfNull(true)
                        .SetSerializer(
                            new NullableSerializer<RetentionPolicy>(new EnumSerializer<RetentionPolicy>(BsonType.String)));
    
                    cm.MapMember(c => c.RetentionPolicyValue).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.LevelCondition).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.Grouped).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.UiConfiguration).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.Alarm).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.Description).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.RequiredValue).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.Preconditions).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.CheckObservations).SetDefaultValue(false);
                    cm.MapMember(c => c.CreateObservation).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.InsertMode)
                        .SetDefaultValue(ObservationEnum.InsertMode.Auto)
                        .SetSerializer(new EnumSerializer<ObservationEnum.InsertMode>(BsonType.String));
    
                    cm.MapMember(c => c.TimeFromMessageTime).SetIgnoreIfDefault(true);
                    cm.MapMember(c => c.ColorRanges).SetIgnoreIfNull(true);
                });
    
            if (!BsonClassMap.IsClassMapRegistered(typeof(ConfigObservation.ColorRange)))
                BsonClassMap.RegisterClassMap<ConfigObservation.ColorRange>(cm =>
                {
                    cm.AutoMap();
                    cm.MapMember(s => s.ValueType)
                        .SetIgnoreIfNull(true)
                        .SetSerializer(
                            new NullableSerializer<ObservationEnum.ValueType>(
                                new EnumSerializer<ObservationEnum.ValueType>(BsonType.String)));
                    cm.MapMember(s => s.Min).SetIgnoreIfNull(true);
                    cm.MapMember(s => s.Max).SetIgnoreIfNull(true);
                    cm.MapMember(s => s.MatchText).SetIgnoreIfNull(true);
                    cm.MapMember(s => s.MatchBoolean).SetIgnoreIfNull(true);
                    cm.MapMember(s => s.MinDate).SetIgnoreIfNull(true);
                    cm.MapMember(s => s.MaxDate).SetIgnoreIfNull(true);
                    cm.MapMember(s => s.Color).SetIgnoreIfNull(true);
                    cm.MapMember(s => s.Label).SetIgnoreIfNull(true);
                });
    
            if (!BsonClassMap.IsClassMapRegistered(typeof(GroupedObservation)))
                BsonClassMap.RegisterClassMap<GroupedObservation>(cm =>
                {
                    cm.AutoMap();
                    cm.MapMember(c => c.PatientId);
                    cm.MapMember(c => c.Name).SetDefaultValue(string.Empty);
                    cm.MapMember(c => c.Group).SetDefaultValue(string.Empty);
                    cm.MapMember(c => c.Observations).SetDefaultValue(new List<GroupedObservationObs>());
                });
    
            if (!BsonClassMap.IsClassMapRegistered(typeof(GroupedObservationObs)))
                BsonClassMap.RegisterClassMap<GroupedObservationObs>(cm =>
                {
                    cm.AutoMap();
                    cm.MapMember(c => c.Name).SetDefaultValue(string.Empty);
                    cm.MapMember(c => c.First).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.Last).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.Min).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.Max).SetIgnoreIfNull(true);
    
                    cm.MapMember(c => c.MinAlert).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.MaxAlert).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.Average).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.Sum).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.Count).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.HalfHour).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.LastFilled).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.Time);
                    cm.MapMember(c => c.Shift).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.ShiftDate);
                    cm.MapMember(c => c.IsFilled);
                });
    
            if (!BsonClassMap.IsClassMapRegistered(typeof(GroupedObservationObsValue)))
                BsonClassMap.RegisterClassMap<GroupedObservationObsValue>(cm =>
                {
                    cm.AutoMap();
                    cm.MapMember(c => c.Type)
                        .SetDefaultValue(StatusEnum.Type.Ok)
                        .SetSerializer(new EnumSerializer<StatusEnum.Type>(BsonType.String));
                    cm.MapMember(c => c.Value);
                    cm.MapMember(c => c.Time).SetIgnoreIfNull(true);
                });
    
            if (!BsonClassMap.IsClassMapRegistered(typeof(PredictMedicationObservation)))
                BsonClassMap.RegisterClassMap<PredictMedicationObservation>(cm =>
                {
                    cm.AutoMap();
                    cm.MapMember(c => c.MedicineText).SetDefaultValue(string.Empty);
                    cm.MapMember(c => c.DegreeSimilarity);
                });
    
            if (!BsonClassMap.IsClassMapRegistered(typeof(ObservationTextRule)))
                BsonClassMap.RegisterClassMap<ObservationTextRule>(cm =>
                {
                    cm.AutoMap();
                    cm.MapMember(c => c.ValueType)
                        .SetDefaultValue(ObservationEnum.ValueType.String)
                        .SetSerializer(new EnumSerializer<ObservationEnum.ValueType>(BsonType.String));
                    cm.MapMember(c => c.Value).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.MatchText).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.MatchBoolean).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.MatchNumber).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.MatchDate).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.Label).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.MinDate).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.MaxDate).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.MinNum).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.MaxNum).SetIgnoreIfNull(true);
                });
    
            if (!BsonClassMap.IsClassMapRegistered(typeof(ConditionsConfig)))
                BsonClassMap.RegisterClassMap<ConditionsConfig>(cm =>
                {
                    cm.AutoMap();
                    cm.MapMember(c => c.Condition).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.FieldCondition).SetIgnoreIfNull(true);
                });
        }
}