Files

94 lines
3.7 KiB
C#

using System.Text.Json;
using Microsoft.EntityFrameworkCore;
using VigilCare.ClinicalContracts.Sync;
public class ClinicalSyncService : IClinicalSyncService
{
private readonly AppDbContext _db;
private readonly ILogger<ClinicalSyncService> _logger;
public ClinicalSyncService(AppDbContext db, ILogger<ClinicalSyncService> logger)
{
_db = db;
_logger = logger;
}
public async Task<ClinicalBatchUploadResponse> UploadBatchAsync(
ClinicalSyncBatchRequest request, CancellationToken ct)
{
var existing = await _db.ClinicalSyncBatches
.AsNoTracking()
.FirstOrDefaultAsync(b => b.BatchReference == request.BatchReference, ct);
if (existing is not null)
return new ClinicalBatchUploadResponse(existing.Id, existing.Status.ToDbString());
var gateway = await _db.WardGateways
.FirstOrDefaultAsync(g => g.Id == request.GatewayId && g.SiteId == request.SiteId, ct)
?? throw new NotFoundException("Gateway not found for site.", "GATEWAY_NOT_FOUND");
var payload = JsonSerializer.Serialize(request);
var batch = new ClinicalSyncBatch(gateway.Id, request.SiteId, request.BatchReference, payload);
var batchId = Guid.NewGuid();
_db.Entry(batch).Property(nameof(ClinicalSyncBatch.Id)).CurrentValue = batchId;
await using var tx = await _db.Database.BeginTransactionAsync(ct);
_db.ClinicalSyncBatches.Add(batch);
_db.OutboxEvents.Add(new OutboxEvent
{
Id = Guid.NewGuid(),
Topic = ClinicalSyncOptions.BatchReceivedOutboxTopic,
Payload = JsonSerializer.Serialize(new
{
batchId,
gatewayId = gateway.Id,
siteId = request.SiteId
}),
PartitionKey = gateway.Id.ToString(),
CreatedAt = DateTimeOffset.UtcNow
});
await _db.SaveChangesAsync(ct);
await tx.CommitAsync(ct);
_logger.LogInformation(
"Sync batch {BatchId} received from gateway {GatewayId} — {ObsCount} observations",
batch.Id, gateway.Id, request.Observations.Count);
return new ClinicalBatchUploadResponse(batch.Id, "RECEIVED");
}
public async Task<ClinicalBatchStatusResponse> GetBatchStatusAsync(Guid batchId, CancellationToken ct)
{
var batch = await _db.ClinicalSyncBatches
.AsNoTracking()
.Include(b => b.Conflicts)
.FirstOrDefaultAsync(b => b.Id == batchId, ct)
?? throw new NotFoundException("Sync batch not found.", "BATCH_NOT_FOUND");
var conflicts = batch.Conflicts.Select(c =>
new ClinicalConflictDetail(c.ClientRef, c.ItemType, c.ConflictReason)).ToList();
return new ClinicalBatchStatusResponse(batch.Id, batch.Status.ToDbString(), conflicts);
}
public async Task<IReadOnlyList<ClinicalSyncHistoryItem>> GetSyncHistoryAsync(
Guid siteId, Guid gatewayId, int limit, CancellationToken ct)
{
var gatewayExists = await _db.WardGateways
.AnyAsync(g => g.Id == gatewayId && g.SiteId == siteId, ct);
if (!gatewayExists)
throw new NotFoundException("Gateway not found for site.", "GATEWAY_NOT_FOUND");
return await _db.ClinicalSyncBatches
.AsNoTracking()
.Where(b => b.GatewayId == gatewayId && b.SiteId == siteId)
.OrderByDescending(b => b.SubmittedAt)
.Take(limit)
.Select(b => new ClinicalSyncHistoryItem(
b.Id,
b.BatchReference,
b.Status.ToDbString(),
b.Conflicts.Count,
b.SubmittedAt))
.ToListAsync(ct);
}
}