using adas_core.Application.Repositories.Interfaces; using adas_core.Domain.Enums; using adas_core.Domain.Models.AppSettings; using adas_core.Domain.Models.Pumps; using Microsoft.Extensions.Options; using MongoDB.Bson; using MongoDB.Driver; namespace adas_core.Infrastructure.Repositories; /// /// Represents a MongoDB-based repository for entities, providing concrete data access functionality defined by the contract. /// public class PumpAlarmStateRepository : MongoRepository, IPumpAlarmStateRepository { private readonly ApiSettings _apiSettings; public PumpAlarmStateRepository(IOptions apiSettings, IMongoDatabase database) : base(database) { _apiSettings = apiSettings.Value; } /// /// Gets the collection name for the pump alarm state, returning the value configured in the API settings or the default "pump_alarm_state" when the configuration is not set. /// /// The configured collection name, or the default "pump_alarm_state" if the API setting is null. public override string GetCollectionName() { return _apiSettings.PumpAlarmState ?? "pump_alarm_state"; } public override async Task CreateIndexes() { var indexModels = new List> { // Clave única de alarma activa new( Builders.IndexKeys .Ascending(x => x.DeviceId) .Ascending(x => x.AlarmType) .Ascending(x => x.AlarmCodeMdc), new CreateIndexOptions { Unique = true, Name = "ux_device_alarm" }), // Indexado por DeviceId new( Builders.IndexKeys.Ascending(x => x.DeviceId), new CreateIndexOptions { Name = "ix_device" }), // indexado por PatientId new( Builders.IndexKeys.Ascending(x => x.PatientId), new CreateIndexOptions { Name = "ix_patientId" }) }; await Collection.Indexes.CreateManyAsync(indexModels); } /// /// Retrieves the first active matching the specified device and optional alarm criteria. /// The filter is always constrained by , and additionally by and when those values are provided. /// Returns null when no matching alarm state is found. /// /// The identifier of the device whose alarm state should be retrieved. Always applied to the query filter. /// The optional alarm type used to further narrow the filter. When null, the alarm type is not applied. /// The optional alarm code (MDC) used to further narrow the filter. Ignored when null, empty, or whitespace. /// A instance if a matching record is found; otherwise, null. public async Task FindActiveAsync(string deviceId, PumpEnum.AlarmType? alarmType, string? alarmCodeMdc = null) { var filter = Builders.Filter.Eq(x => x.DeviceId, deviceId); if (alarmType.HasValue) filter &= Builders.Filter.Eq(x => x.AlarmType, alarmType); if (!string.IsNullOrWhiteSpace(alarmCodeMdc)) filter &= Builders.Filter.Eq(x => x.AlarmCodeMdc, alarmCodeMdc); return await Collection.Find(filter).FirstOrDefaultAsync(); } public async Task UpsertActiveAsync(PumpAlarmState state) { var filter = Builders.Filter.Eq(x => x.DeviceId, state.DeviceId) & Builders.Filter.Eq(x => x.AlarmType, state.AlarmType) & Builders.Filter.Eq(x => x.AlarmCodeMdc, state.AlarmCodeMdc); // Revisar si ya existe un documento activo con esa combinación var existing = await Collection.Find(filter).FirstOrDefaultAsync(); if (existing != null) state.Id = existing.Id; else if (state.Id == ObjectId.Empty) state.Id = ObjectId.GenerateNewId(); await Collection.ReplaceOneAsync( filter, state, new ReplaceOptions { IsUpsert = true }); } /// /// Removes pump alarm state records from the collection that match the specified device identifier, optionally narrowed by alarm type and/or alarm code MDC. /// /// The identifier of the device whose alarm state records should be removed. Used as a mandatory filter criterion. /// The optional alarm type to further restrict which records are deleted. When , records of any alarm type for the device are removed. /// The optional alarm code MDC used to further narrow the deletion. Blank or whitespace values are ignored. public async Task RemoveAsync(string? deviceId, PumpEnum.AlarmType? alarmType, string? alarmCodeMdc = null) { var filter = Builders.Filter.Eq(x => x.DeviceId, deviceId); if (alarmType.HasValue) filter &= Builders.Filter.Eq(x => x.AlarmType, alarmType); if (!string.IsNullOrWhiteSpace(alarmCodeMdc)) filter &= Builders.Filter.Eq(x => x.AlarmCodeMdc, alarmCodeMdc); await Collection.DeleteManyAsync(filter); } /// /// Asynchronously deletes all records associated with the specified patient identifier by removing every document whose PatientId matches the supplied value. /// /// The unique identifier of the patient whose associated records should be removed. public async Task DeleteByPatientId(ObjectId patientId) { await Collection.DeleteManyAsync(p => p.PatientId == patientId); } /// /// Asynchronously retrieves all pump alarm states associated with the specified device identifier. /// /// The unique identifier of the device whose pump alarm states are being queried. /// A task that represents the asynchronous operation. The task result contains an with the pump alarm states matching the provided device identifier. public async Task> FindAllActiveByDeviceAsync(string deviceId) { return await Collection.Find(x => x.DeviceId == deviceId).ToListAsync(); } /// /// Asynchronously updates all documents that match the specified on the given , replacing the value with . Used to bulk rewire references stored on a dynamic field. /// /// Name of the document field to filter and update. /// The new value to assign to the field. /// The existing value used to locate matching documents. /// The number of documents that were modified by the update operation. public async Task UpdateManyObjectIdByFieldNameAsync(string fieldName, ObjectId newId, ObjectId oldId) { var filter = Builders.Filter.Eq(fieldName, oldId); var update = Builders.Update.Set(fieldName, newId); var result = await Collection.UpdateManyAsync(filter, update); return result.ModifiedCount; } }