using ClinicalInsightsPro.API.Data; using ClinicalInsightsPro.API.DTOs; using ClinicalInsightsPro.API.Models; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using ClinicalInsightsPro.API.Services.Interfaces; namespace ClinicalInsightsPro.API.Controllers; [ApiController] [Route("api/patients/{patientId}/[controller]")] [Authorize] public class ConditionsController : ControllerBase { private readonly ApplicationDbContext _db; private readonly IMedplumFhirService _medplumFhirService; public ConditionsController( ApplicationDbContext db, IMedplumFhirService medplumFhirService) { _db = db; _medplumFhirService = medplumFhirService; } private async Task PatientExists(string patientId) { return await _db.Patient.AnyAsync(x => x.Id == patientId); } [HttpGet("/api/conditions")] public async Task GetAll() { var conditions = await _db.Condition .Include(x => x.Patient) .Select(condition => new ConditionListDto { Id = condition.Id, PatientId = condition.PatientId, PatientName = condition.Patient != null ? $"{condition.Patient.GivenName} {condition.Patient.FamilyName}" : string.Empty, ConditionCode = condition.ConditionCode, ConditionDisplay = condition.ConditionDisplay, ClinicalStatusDisplay = condition.ClinicalStatusDisplay, VerificationStatusDisplay = condition.VerificationStatusDisplay, SeverityDisplay = condition.SeverityDisplay, RecordedDate = condition.RecordedDate }) .ToListAsync(); return Ok(conditions); } [HttpGet] public async Task GetByPatient(string patientId) { if (!await PatientExists(patientId)) return NotFound(new { error = $"Patient '{patientId}' was not found." }); var conditions = await _db.Condition .Where(x => x.PatientId == patientId) .AsNoTracking() .ToListAsync(); return Ok(conditions); } [HttpGet("{id}")] public async Task Get( string patientId, string id) { var condition = await _db.Condition .AsNoTracking() .FirstOrDefaultAsync(x => x.Id == id && x.PatientId == patientId); if (condition == null) return NotFound(new { error = $"Condition '{id}' was not found." }); return Ok(condition); } [HttpPost] public async Task Create( string patientId, [FromBody] ConditionRequestDto request) { if (!await PatientExists(patientId)) return NotFound(new { error = $"Patient '{patientId}' was not found." }); var condition = new Condition { ConditionId = Guid.NewGuid().ToString(), ResourceType = "Condition", PatientId = patientId, ClinicalStatusCode = request.ClinicalStatusCode, ClinicalStatusDisplay = request.ClinicalStatusDisplay, VerificationStatusCode = request.VerificationStatusCode, VerificationStatusDisplay = request.VerificationStatusDisplay, SeverityCode = request.SeverityCode, SeverityDisplay = request.SeverityDisplay, ConditionCode = request.ConditionCode, ConditionDisplay = request.ConditionDisplay, OnsetDateTime = request.OnsetDateTime, AbatementDateTime = request.AbatementDateTime, RecordedDate = request.RecordedDate, RecorderId = request.RecorderId, AsserterId = request.AsserterId, CreatedBy = "System", CreatedDate = DateTime.UtcNow, VersionId = Guid.NewGuid().ToString(), LastUpdated = DateTime.UtcNow }; _db.Condition.Add(condition); await _db.SaveChangesAsync(); return CreatedAtAction( nameof(Get), new { patientId, id = condition.Id }, condition); } [HttpPut("{id}")] public async Task Update( string patientId, string id, [FromBody] ConditionRequestDto request) { var condition = await _db.Condition .FirstOrDefaultAsync(x => x.Id == id && x.PatientId == patientId); if (condition == null) return NotFound(new { error = $"Condition '{id}' was not found." }); condition.ClinicalStatusCode = request.ClinicalStatusCode; condition.ClinicalStatusDisplay = request.ClinicalStatusDisplay; condition.VerificationStatusCode = request.VerificationStatusCode; condition.VerificationStatusDisplay = request.VerificationStatusDisplay; condition.SeverityCode = request.SeverityCode; condition.SeverityDisplay = request.SeverityDisplay; condition.ConditionCode = request.ConditionCode; condition.ConditionDisplay = request.ConditionDisplay; condition.OnsetDateTime = request.OnsetDateTime; condition.AbatementDateTime = request.AbatementDateTime; condition.RecordedDate = request.RecordedDate; condition.RecorderId = request.RecorderId; condition.AsserterId = request.AsserterId; condition.UpdatedBy = "System"; condition.UpdatedDate = DateTime.UtcNow; condition.LastUpdated = DateTime.UtcNow; await _db.SaveChangesAsync(); return Ok(condition); } [HttpDelete("{id}")] public async Task Delete( string patientId, string id) { var condition = await _db.Condition .FirstOrDefaultAsync(x => x.Id == id && x.PatientId == patientId); if (condition == null) return NotFound(new { error = $"Condition '{id}' was not found." }); _db.Condition.Remove(condition); await _db.SaveChangesAsync(); return NoContent(); } [HttpPost("/api/conditions/sync-from-medplum")] public async Task SyncFromMedplum() { var conditions = await _medplumFhirService.PullAllConditionsFromMedplumAsync(); int imported = 0; foreach (var condition in conditions) { // Medplum Patient Id -> Local Patient Id mapping. Falls back to // matching the local Patient's own Id too — a patient that was // seeded locally (or pulled from Medplum without MedplumId being // set for some reason) but whose id happens to equal the Medplum // patient id would otherwise be silently skipped here. var localPatient = await _db.Patient .FirstOrDefaultAsync(p => p.MedplumId == condition.PatientId || p.Id == condition.PatientId); if (localPatient == null) { continue; } // Local Patient Id save karo condition.PatientId = localPatient.Id; var exists = await _db.Condition .AnyAsync(x => x.MedplumId == condition.MedplumId); if (!exists) { condition.Id = Guid.NewGuid().ToString(); if (string.IsNullOrWhiteSpace(condition.ConditionId)) { condition.ConditionId = Guid.NewGuid().ToString(); } condition.CreatedDate = DateTime.UtcNow; condition.LastUpdated = DateTime.UtcNow; condition.VersionId = Guid.NewGuid().ToString(); _db.Condition.Add(condition); imported++; } } await _db.SaveChangesAsync(); return Ok(new { Imported = imported }); } }