using Microsoft.EntityFrameworkCore; public class PatientService : IPatientService { private readonly AppDbContext _db; public PatientService(AppDbContext db) => _db = db; public async Task RegisterAsync(RegisterPatientRequest req) { var mrn = await GenerateMrnAsync(); var patient = new Patient { Id = Guid.NewGuid(), Mrn = mrn, FirstName = req.FirstName, LastName = req.LastName, DateOfBirth = req.DateOfBirth, Gender = req.Gender, CreatedAt = DateTimeOffset.UtcNow }; _db.Patients.Add(patient); await _db.SaveChangesAsync(); return patient; } public async Task> ListAsync( string? q, int page, int pageSize) { var query = _db.Patients.AsQueryable(); if (!string.IsNullOrWhiteSpace(q)) { query = query.Where(p => p.Mrn == q || EF.Functions.ILike(p.FirstName, $"%{q}%") || EF.Functions.ILike(p.LastName, $"%{q}%")); } var total = await query.CountAsync(); var patients = await query .OrderBy(p => p.LastName).ThenBy(p => p.FirstName) .Skip((page - 1) * pageSize) .Take(pageSize) .ToListAsync(); return new PagedResult(patients, page, pageSize, total); } public async Task GetByIdAsync(Guid id) { var patient = await _db.Patients .Include(p => p.Encounters.Where(e => e.Status == EncounterStatus.Active)) .FirstOrDefaultAsync(p => p.Id == id); if (patient is null) throw new NotFoundException("Patient not found.", "PATIENT_NOT_FOUND"); return patient; } public async Task OpenEncounterAsync(Guid patientId, OpenEncounterRequest req) { var patient = await _db.Patients.FindAsync(patientId); if (patient is null) throw new NotFoundException("Patient not found.", "PATIENT_NOT_FOUND"); var hasActiveOfType = await _db.Encounters.AnyAsync(e => e.PatientId == patientId && e.EncounterType == req.EncounterType && e.Status == EncounterStatus.Active); if (hasActiveOfType) throw new ConflictException( "Patient already has an active encounter of this type.", "DUPLICATE_ACTIVE_ENCOUNTER"); var encounter = new Encounter { Id = Guid.NewGuid(), PatientId = patientId, EncounterType = req.EncounterType, Status = EncounterStatus.Active, Department = req.Department, AttendingPhysician = req.AttendingPhysician, AdmittedAt = DateTimeOffset.UtcNow, CreatedAt = DateTimeOffset.UtcNow }; _db.Encounters.Add(encounter); await _db.SaveChangesAsync(); return encounter; } private async Task GenerateMrnAsync() { var count = await _db.Patients.CountAsync(); return $"MRN-{(count + 1):D6}"; } }