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

namespace adas_core.Infrastructure.Utils.MongoMaps;

/// <summary>
/// Represents a contributor that participates in the mapping configuration of the <see cref="Patient"/> entity by implementing the <see cref="IEntityMapContributor"/> interface.
/// </summary>
public class PatientMapContributor : IEntityMapContributor
{
    /// <summary>
    /// Registers BSON class maps for the domain model types (Patient, Person, PatientLocation, and related entities) to configure their MongoDB serialization, including auto-mapping, null-value handling, enum string serialization, dictionary serialization, and ID member mapping. Skips registration for types that already have a registered class map.
    /// </summary>
    public void RegisterMaps()
        {
            if (!BsonClassMap.IsClassMapRegistered(typeof(HistoricalLocation)))
            {
                BsonClassMap.RegisterClassMap<HistoricalLocation>(cm =>
                {
                    cm.AutoMap();
                    cm.MapMember(c => c.AdmTime);
                    cm.MapMember(c => c.PatientLocation);
                });
                
            }
            
            if (!BsonClassMap.IsClassMapRegistered(typeof(Patient)))
                BsonClassMap.RegisterClassMap<Patient>(cm =>
                {
                    cm.AutoMap();
                    cm.MapIdMember(c => c.Id).SetElementName("_id");
                    cm.GetMemberMap(c => c.PatientNumber).SetIgnoreIfNull(true);
                    cm.GetMemberMap(c => c.PatientId).SetIgnoreIfNull(true);
                    cm.GetMemberMap(c => c.AdmTime).SetIgnoreIfNull(true);
                    cm.GetMemberMap(c => c.DischargeStatus).SetIgnoreIfNull(true);
                    cm.GetMemberMap(c => c.Altable).SetIgnoreIfNull(true);
                    cm.GetMemberMap(c => c.Origin).SetIgnoreIfNull(true);
                    cm.GetMemberMap(c => c.OriginAux).SetIgnoreIfNull(true);
                    cm.GetMemberMap(c => c.Diagnosis).SetIgnoreIfNull(true);
                    cm.GetMemberMap(c => c.DiagnosisAux).SetIgnoreIfNull(true);
                    cm.GetMemberMap(c => c.Visits).SetIgnoreIfNull(true);
                    cm.GetMemberMap(c => c.AccessControl).SetIgnoreIfNull(true);
                    cm.GetMemberMap(c => c.Insulation).SetIgnoreIfNull(true);
                    cm.GetMemberMap(c => c.PatientStatus).SetIgnoreIfNull(true);
                    cm.GetMemberMap(c => c.Mobility).SetIgnoreIfNull(true);
                    cm.GetMemberMap(c => c.TherapeuticCeiling).SetIgnoreIfNull(true);
                    cm.GetMemberMap(c => c.Procedures).SetIgnoreIfNull(true);
                    cm.GetMemberMap(c => c.Tests).SetIgnoreIfNull(true);
                    cm.GetMemberMap(c => c.Treatment).SetIgnoreIfNull(true);
                    cm.GetMemberMap(c => c.Doctors).SetIgnoreIfNull(true);
                    cm.GetMemberMap(c => c.Allergies).SetIgnoreIfNull(true);
                    cm.GetMemberMap(c => c.LanguageBarrier).SetIgnoreIfNull(true);
                    cm.GetMemberMap(c => c.PassiveSitting).SetIgnoreIfNull(true);
                    cm.GetMemberMap(c => c.DisTime).SetIgnoreIfNull(true);
                    cm.GetMemberMap(c => c.Person).SetIgnoreIfNull(true);
                    cm.GetMemberMap(c => c.AttendingDoctor).SetIgnoreIfNull(true);
                    cm.GetMemberMap(c => c.LastObservationDate).SetIgnoreIfNull(true);
                    cm.GetMemberMap(c => c.CreationDate).SetIgnoreIfNull(true);
                    cm.GetMemberMap(c => c.UpdateDate).SetIgnoreIfNull(true);
                    cm.GetMemberMap(c => c.ArchiveDate).SetIgnoreIfNull(true);
                    cm.GetMemberMap(c => c.PointOfCareId).SetIgnoreIfNull(true);
                    cm.GetMemberMap(c => c.UnitId).SetIgnoreIfNull(true);
                    cm.GetMemberMap(c => c.HistoricalLocations).SetIgnoreIfNull(true);
    
                    // No mapear estos campos
                    cm.UnmapMember(c => c.Bed);
                    cm.UnmapMember(c => c.UnitString);
                    cm.UnmapMember(c => c.Room);
                    cm.UnmapMember(c => c.PointOfCare);
                    cm.UnmapMember(c => c.Location);
                });
    
            if (!BsonClassMap.IsClassMapRegistered(typeof(Person)))
            {
                BsonClassMap.RegisterClassMap<Person>(cm =>
                {
                    cm.AutoMap();
                    cm.MapMember(c => c.LastName).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.FirstName).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.SecondName).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.BirthDate).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.Language).SetIgnoreIfNull(true);
    
                    cm.MapMember(c => c.Gender)
                        .SetDefaultValue(PatientEnum.Gender.Unknown)
                        .SetSerializer(new EnumSerializer<PatientEnum.Gender>(BsonType.String));
    
                    cm.MapMember(c => c.Ids).SetIgnoreIfNull(true);
    
                    cm.MapMember(c => c.HistoricalIds)
                        .SetIgnoreIfNull(true);
                });
    
                BsonClassMap.RegisterClassMap<HistoricalId>(cm =>
                {
                    cm.AutoMap();
                    cm.MapMember(c => c.Time).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.PatientIds)
                        .SetSerializer(
                            new DictionaryInterfaceImplementerSerializer<Dictionary<string, string>, string, string>(
                                DictionaryRepresentation.Document))
                        .SetIgnoreIfNull(true);
                });
            }
    
    
            if (!BsonClassMap.IsClassMapRegistered(typeof(PatientLocation)))
                BsonClassMap.RegisterClassMap<PatientLocation>(cm =>
                {
                    cm.AutoMap();
                    cm.MapMember(c => c.UnitName).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.Bed).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.Room).SetIgnoreIfNull(true);
                });
    
    
            if (!BsonClassMap.IsClassMapRegistered(typeof(PatientLocationAction)))
                BsonClassMap.RegisterClassMap<PatientLocationAction>(cm =>
                {
                    cm.AutoMap();
                    cm.MapMember(c => c.Location).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.Action)
                        .SetIgnoreIfNull(true)
                        .SetSerializer(
                            new NullableSerializer<ActionsEnum.ResourceAction>(
                                new EnumSerializer<ActionsEnum.ResourceAction>(BsonType.String)));
                });
    
    
            if (!BsonClassMap.IsClassMapRegistered(typeof(PatientIncomeData)))
                BsonClassMap.RegisterClassMap<PatientIncomeData>(cm =>
                {
                    cm.AutoMap();
                    cm.MapMember(c => c.Diagnosis).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.DiagnosisAux).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.Origin).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.OriginAux).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.AdmTime).SetIgnoreIfNull(true);
                });
    
            if (!BsonClassMap.IsClassMapRegistered(typeof(PatientIcca)))
                BsonClassMap.RegisterClassMap<PatientIcca>(cm =>
                {
                    cm.AutoMap();
                    cm.MapMember(c => c.Location).SetDefaultValue(new PatientLocation(string.Empty, string.Empty));
                    cm.MapMember(c => c.PatientNumber).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.PatientId).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.AdmitTime).SetIgnoreIfNull(true);
                });
    
            if (!BsonClassMap.IsClassMapRegistered(typeof(PatientAllergiesValue)))
                BsonClassMap.RegisterClassMap<PatientAllergiesValue>(cm =>
                {
                    cm.AutoMap();
                    cm.MapMember(c => c.Notes).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.Type).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.Value).SetIgnoreIfNull(true);
                });
    
            if (!BsonClassMap.IsClassMapRegistered(typeof(PatientIntravenousLinesValue)))
                BsonClassMap.RegisterClassMap<PatientIntravenousLinesValue>(cm =>
                {
                    cm.AutoMap();
                    cm.MapMember(c => c.Type).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.Duration).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.Action).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.Location).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.InsertTime).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.RemoveTime).SetIgnoreIfNull(true);
                });
    
            if (!BsonClassMap.IsClassMapRegistered(typeof(PatientDiagnosis)))
                BsonClassMap.RegisterClassMap<PatientDiagnosis>(cm =>
                {
                    cm.AutoMap();
                    cm.SetIgnoreExtraElements(true);
    
                    cm.MapIdMember(c => c.Id).SetElementName("_id");
                    cm.MapMember(c => c.PatientId);
                    cm.MapMember(c => c.Time);
                    cm.MapMember(c => c.UpdateDate).SetIgnoreIfNull(true);
                    cm.UnmapMember(c => c.MessageTime);
                    cm.MapMember(c => c.CodingSystem).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.Description).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.Label).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.Code).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.State).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.Category).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.StartTime).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.EndTime).SetIgnoreIfNull(true);
                    cm.UnmapMember(c => c.DiagnosisCode);
                    cm.UnmapMember(c => c.DiagnosisSystem);
                });
    
            if (!BsonClassMap.IsClassMapRegistered(typeof(PatientDrainagesValue)))
                BsonClassMap.RegisterClassMap<PatientDrainagesValue>(cm =>
                {
                    cm.AutoMap();
                    cm.MapMember(c => c.Type).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.Location).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.Volume).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.Height).SetIgnoreIfNull(true);
                });
    
            if (!BsonClassMap.IsClassMapRegistered(typeof(PatientCarePlan)))
                BsonClassMap.RegisterClassMap<PatientCarePlan>(cm =>
                {
                    cm.AutoMap();
                    cm.MapIdMember(c => c.Id).SetElementName("_id");
                    cm.MapMember(c => c.PatientId);
                    cm.MapMember(c => c.PointOfCareId).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.PatientNumber).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.UserId).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.CarePlan).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.Description).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.Time).SetIgnoreIfNull(true);
    
                    cm.MapMember(c => c.Action)
                        .SetIgnoreIfNull(true)
                        .SetSerializer(
                            new NullableSerializer<ActionsEnum.CrudAction>(
                                new EnumSerializer<ActionsEnum.CrudAction>(BsonType.String)));
                });
    
            if (!BsonClassMap.IsClassMapRegistered(typeof(Admission)))
                BsonClassMap.RegisterClassMap<Admission>(cm =>
                {
                    cm.AutoMap();
                    cm.MapIdMember(c => c.Id).SetElementName("_id");
                    cm.UnmapMember(c => c.PatientLocation);
                });
    
            if (!BsonClassMap.IsClassMapRegistered(typeof(Discharge)))
                BsonClassMap.RegisterClassMap<Discharge>(cm =>
                {
                    cm.AutoMap();
                    cm.MapIdMember(c => c.Id).SetElementName("_id");
                    cm.UnmapMember(c => c.Patient);
                    cm.UnmapMember(c => c.PatientLocation);
                    cm.MapMember(c => c.MedicalDischarge).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.AdminDischarge).SetIgnoreIfNull(true);
                    cm.MapMember(c => c.NurseDischarge).SetIgnoreIfNull(true);
                });
        }
}