using System.Diagnostics; using adas_core.Application.Repositories.Interfaces; using adas_core.Domain.Models; using adas_core.Domain.Models.AppSettings; using Microsoft.Extensions.Options; using MongoDB.Bson; using MongoDB.Driver; using Serilog; namespace adas_core.Infrastructure.Repositories; public class ObservationArchiveRepository : MongoRepository, IObservationArchiveRepository { private readonly ApiSettings _apiSettings; public ObservationArchiveRepository(IOptions apiSettings, IMongoDatabase database) : base(database) { if (apiSettings == null) throw new ArgumentNullException(nameof(apiSettings)); _apiSettings = apiSettings.Value; } //For testing public async Task> AggregatedPatientLastObservations(ObjectId patientId, int num, DateTime lastDate, List? filterObservations = null) { filterObservations = await AggregatePatientObservations(patientId, filterObservations); var results = new List(); foreach (var obs in filterObservations) { var filter = Builders.Filter.And( Builders.Filter.Eq(o => o.PatientId, patientId), Builders.Filter.Eq(o => o.Name, obs), Builders.Filter.Lte(o => o.Time, lastDate) ); var sort = Builders.Sort.Descending(o => o.Time); results.AddRange(Collection.Find(filter).Sort(sort).Limit(num).ToEnumerable()); } return results; } public override string GetCollectionName() { return _apiSettings.ArchivePatientsObservations ?? "archive_patients_observations"; } public new async Task InsertOneAsync(PatientObservation patientObservation) { const int maxRetries = 2; // Número máximo de reintentos var retryCount = 0; while (true) try { await Collection.InsertOneAsync(patientObservation); return; } catch (MongoWriteException ex) when (ex.WriteError.Category == ServerErrorCategory.DuplicateKey) { retryCount++; Log.Warning( "Duplicate key error encountered. Retrying with new ObjectId. Attempt {attempt} of {maxRetries}", retryCount, maxRetries); patientObservation.Id = new ObjectId(); Log.Information("Generated ObjectId: {objectId}", patientObservation.Id); if (retryCount >= maxRetries) { Log.Error("Maximum retry attempts reached. Could not insert document due to duplicate key error."); throw; // Re-lanzar la excepción después de alcanzar el número máximo de reintentos } } catch (Exception ex) { Log.Error("Error inserting patient observation: {exMessage}", ex.Message); throw; } } public async Task DeleteBeforeDate(DateTime date) { var filter = Builders.Filter.Lt(po => po.Time, date); await Collection.DeleteManyAsync(filter); } public async Task InsertBatch(IEnumerable observations) { var writes = new List>(); writes.AddRange(observations.Select(d => new InsertOneModel(d))); var bulkInsert = await Collection.BulkWriteAsync(writes); return bulkInsert.InsertedCount; } public async Task> FindAllFromPatient(ObjectId patientId) { var filter = Builders.Filter.Eq(p => p.PatientId, patientId); var result = await Collection.FindAsync(filter); return await result.ToListAsync(); } private async Task> AggregatePatientObservations(ObjectId patientId, List? filterObservations = null) { var matchPatient = new BsonDocument { { "patientid", patientId }, { "name", new BsonDocument { { "$ne", BsonNull.Value } } } }; if (filterObservations == null || !filterObservations.Any()) { // GET DISTINCT OBSERVATIONS var distinctObs = new BsonDocument { { "$group", new BsonDocument { { "_id", "1" }, { "obs", new BsonDocument { { "$addToSet", "$name" } } } } } }; var distinctPipeline = new[] { new() { { "$match", matchPatient } }, distinctObs }; Debug.WriteLine("AggregatedArchivedPatientLastObservations distinct obs: \n" + distinctPipeline.ToJson()); var resultList = await Collection.AggregateAsync(distinctPipeline, new AggregateOptions { AllowDiskUse = true }); var result = resultList.ToList().FirstOrDefault(); if (result != null && result.Any()) filterObservations = result.GetValue("obs").AsBsonArray.Select(it => it.AsString).ToList(); } return filterObservations ?? []; } }