using Microsoft.AspNetCore.Mvc; /// /// Encounter retrieval, status transitions, and clinical timeline. /// [ApiController] [Route("api/v1/encounters")] [Produces("application/json")] public class EncountersController : ControllerBase { private readonly IEncounterService _encounters; public EncountersController(IEncounterService encounters) => _encounters = encounters; /// /// Lists encounters for ward dashboards with denormalized clinical summary fields. /// /// Optional status filter (DB literal, e.g. ACTIVE). /// Optional department filter (DB literal, e.g. ICU). /// Page number (1-based). /// Results per page. [HttpGet] [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)] [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status400BadRequest)] public async Task List( [FromQuery] string? status, [FromQuery] string? department, [FromQuery] int page = 1, [FromQuery] int pageSize = 20) { EncounterStatus? parsedStatus = null; if (!string.IsNullOrEmpty(status)) { try { parsedStatus = EncounterStatusExtensions.FromDbString(status); } catch (ArgumentOutOfRangeException) { return BadRequest(ApiResponse.Fail(400, "Invalid status filter.", "INVALID_STATUS")); } } Department? parsedDepartment = null; if (!string.IsNullOrEmpty(department)) { try { parsedDepartment = DepartmentExtensions.FromDbString(department); } catch (ArgumentOutOfRangeException) { return BadRequest(ApiResponse.Fail(400, "Invalid department filter.", "INVALID_DEPARTMENT")); } } var result = await _encounters.ListAsync(parsedStatus, parsedDepartment, page, pageSize); return Ok(ApiResponse.Ok(new { items = result.Items, page = result.Page, pageSize = result.PageSize, totalCount = result.TotalCount, totalPages = result.TotalPages })); } /// /// Gets an encounter with patient, recent observations, and open alerts. /// /// Encounter id. /// The encounter with related data. [HttpGet("{id:guid}")] [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)] [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status404NotFound)] public async Task Get(Guid id) { var encounter = await _encounters.GetByIdAsync(id); return Ok(ApiResponse.Ok(encounter)); } /// /// Transitions an encounter to a new status via the encounter state machine. /// /// Encounter id. /// Target status. /// The encounter id and new status. [HttpPatch("{id:guid}/status")] [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)] [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status404NotFound)] [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status409Conflict)] public async Task TransitionStatus(Guid id, [FromBody] TransitionStatusRequest req) { var result = await _encounters.TransitionStatusAsync(id, req.Status, req.DischargeDiagnosis); return Ok(ApiResponse.Ok(new { encounterId = result.EncounterId, newStatus = result.NewStatus, dischargeDiagnosis = req.DischargeDiagnosis })); } /// /// Returns a merged chronological timeline of observations and alerts for an encounter. /// /// Encounter id. /// Ordered timeline events. [HttpGet("{id:guid}/timeline")] [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)] [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status404NotFound)] public async Task Timeline(Guid id) { var timeline = await _encounters.GetTimelineAsync(id); return Ok(ApiResponse.Ok(timeline)); } }