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

namespace adas_core.Infrastructure.Utils.MongoMaps;

/// <summary>
/// Represents a contributor that participates in entity mapping for treatment-related entities by implementing the <see cref="IEntityMapContributor"/> contract.
/// </summary>
/// <remarks>
/// This class is intended to be used as a mapping contributor within an entity mapping pipeline, providing configuration logic specific to treatment entities.</remarks>
public class TreatmentMapContributor : IEntityMapContributor
{
    /// <summary>
    /// Registers the BSON class maps required to serialize and deserialize the patient treatment
    /// domain models (such as PatientTreatment, Medicine, Code, CodeStatus, Note, TreatmentRoute,
    /// Entity, CodeAction, and PredictMedicationObservation) to and from MongoDB. Each map is only
    /// registered when no class map already exists for the corresponding type, and the registrations
    /// define custom element names, default values, null-ignoring behavior, and specialized
    /// serializers for object identifiers and enum values.
    /// </summary>
    public void RegisterMaps()
        {
            if (!BsonClassMap.IsClassMapRegistered(typeof(PatientTreatment)))
                BsonClassMap.RegisterClassMap<PatientTreatment>(cm =>
                {
                    cm.AutoMap();
    
                    cm.MapIdMember(c => c.Id).SetElementName("_id");
                    cm.MapMember(c => c.PatientId)
                        .SetSerializer(new ObjectIdSerializer(BsonType.String))
                        .SetIgnoreIfNull(true);
                    cm.MapMember(c => c.OrderControl)
                        .SetSerializer(new EnumSerializer<OrderControlType>(BsonType.String));
                    cm.MapMember(c => c.PlacerOrder).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.FillerOrder).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.OrderStatus).SetDefaultValue(string.Empty);
                    cm.MapMember(c => c.OrderTime).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.StartTime).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.EndTime).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.RequestedGiveCodes).SetDefaultValue(new List<Code>());
                    cm.MapMember(c => c.RequestedGiveTreatment).SetDefaultValue(string.Empty);
                    cm.MapMember(c => c.RequestedGiveCodesStatus).SetDefaultValue(new List<CodeStatus>());
                    cm.MapMember(c => c.RequestedGiveAmountMinimum).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.RequestedGiveAmountMaximum).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.RequestedGiveUnits).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.RequestedDosageForm).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.Notes).SetDefaultValue(new List<Note>());
                    cm.MapMember(c => c.Routes).SetDefaultValue(new List<TreatmentRoute>());
                    cm.MapMember(c => c.SingleDose).SetDefaultValue(false);
                    cm.MapMember(c => c.BoloPom).SetDefaultValue(false);
                    cm.MapMember(c => c.MessageTime);
                    cm.MapMember(c => c.SystemId).SetIgnoreIfNull(true);
                });
    
            if (!BsonClassMap.IsClassMapRegistered(typeof(Entity)))
                BsonClassMap.RegisterClassMap<Entity>(cm =>
                {
                    cm.AutoMap();
                    cm.MapMember(c => c.EntityIdentifier).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.NamespaceId).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.UniversalId).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.UniversalIdType).SetIgnoreIfNull(true);
                });
    
            if (!BsonClassMap.IsClassMapRegistered(typeof(Code)))
                BsonClassMap.RegisterClassMap<Code>(cm =>
                {
                    cm.AutoMap();
                    cm.MapMember(c => c.Identifier).SetDefaultValue(string.Empty);
                    cm.MapMember(c => c.Text).SetDefaultValue(string.Empty);
                    cm.MapMember(c => c.CodingSystem).SetDefaultValue(string.Empty);
                });
    
            if (!BsonClassMap.IsClassMapRegistered(typeof(CodeStatus)))
                BsonClassMap.RegisterClassMap<CodeStatus>(cm =>
                {
                    cm.AutoMap();
                    cm.MapMember(c => c.Code).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.Status).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.AdministrationTime).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.EndAdministrationTime).SetIgnoreIfNull(true);
                });
    
            if (!BsonClassMap.IsClassMapRegistered(typeof(Note)))
                BsonClassMap.RegisterClassMap<Note>(cm =>
                {
                    cm.AutoMap();
                    cm.MapMember(c => c.CommentType).SetDefaultValue(string.Empty);
                    cm.MapMember(c => c.Comment).SetDefaultValue(string.Empty);
                    cm.MapMember(c => c.EnteredTime).SetIgnoreIfNull(true);
                });
    
            if (!BsonClassMap.IsClassMapRegistered(typeof(TreatmentRoute)))
                BsonClassMap.RegisterClassMap<TreatmentRoute>(cm =>
                {
                    cm.AutoMap();
                    cm.MapMember(c => c.Route).SetIgnoreIfNull(true);
                });
    
            if (!BsonClassMap.IsClassMapRegistered(typeof(Medicine)))
                BsonClassMap.RegisterClassMap<Medicine>(cm =>
                {
                    cm.AutoMap();
                    cm.MapIdMember(c => c.Id).SetElementName("_id");
                    cm.MapMember(c => c.Name).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.Codes).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.Notes).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.Type).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.Group).SetIgnoreIfNull(true);
                });
    
            if (!BsonClassMap.IsClassMapRegistered(typeof(CodeAction)))
                BsonClassMap.RegisterClassMap<CodeAction>(cm =>
                {
                    cm.AutoMap();
                    cm.MapMember(c => c.Code).SetIsRequired(true);
                    cm.MapMember(c => c.Action)
                        .SetSerializer(new EnumSerializer<ActionsEnum.ResourceAction>(BsonType.String));
                });
    
            if (!BsonClassMap.IsClassMapRegistered(typeof(PredictMedicationObservation)))
                BsonClassMap.RegisterClassMap<PredictMedicationObservation>(cm => { cm.AutoMap(); });
        }
}