using System.Security.Claims;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;


/// <summary>
/// Draft data entry endpoints for digitization batches. A data entry clerk
/// uses these endpoints to transcribe scanned paper charts into structured data.
/// </summary>
[ApiController]
[Route("api/v1/digitization-batches/{batchId:guid}/draft")]
[Produces("application/json")]
[Authorize]
public class DraftController : ControllerBase
{
    private readonly IDraftService _draft;

    public DraftController(IDraftService draft) => _draft = draft;

    /// <summary>
    /// Returns the full draft payload for a batch, including patient demographics,
    /// encounter context, and all observation rows entered so far.
    /// </summary>
    /// <param name="batchId">Digitization batch id.</param>
    /// <returns>Complete draft data for the batch.</returns>
    [HttpGet]
    [ProducesResponseType(typeof(ApiResponse<DraftPayloadResponse>), StatusCodes.Status200OK)]
    [ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status404NotFound)]
    public async Task<IActionResult> GetDraft(Guid batchId)
    {
        var result = await _draft.GetDraftAsync(batchId);
        return Ok(ApiResponse<DraftPayloadResponse>.Ok(result));
    }

    /// <summary>
    /// Upserts draft patient demographics for a batch. Creates the patient record
    /// on the first call; updates it on subsequent calls. Automatically transitions
    /// the batch to IN_ENTRY on first save.
    /// </summary>
    /// <param name="batchId">Digitization batch id.</param>
    /// <param name="req">Patient demographic fields.</param>
    /// <returns>The upserted patient record.</returns>
    [HttpPut("patient")]
    [ProducesResponseType(typeof(ApiResponse<DraftPatientDto>), StatusCodes.Status200OK)]
    [ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status404NotFound)]
    [ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status409Conflict)]
    public async Task<IActionResult> UpsertPatient(
        Guid batchId, [FromBody] UpsertDraftPatientRequest req)
    {
        var actorUserId = GetCurrentUserId();
        var result = await _draft.UpsertPatientAsync(batchId, req, actorUserId);
        return Ok(ApiResponse<DraftPatientDto>.Ok(result));
    }

    /// <summary>
    /// Upserts draft encounter fields for a batch. Creates the encounter record
    /// on the first call; updates it on subsequent calls.
    /// </summary>
    /// <param name="batchId">Digitization batch id.</param>
    /// <param name="req">Encounter context fields.</param>
    /// <returns>The upserted encounter record.</returns>
    [HttpPut("encounter")]
    [ProducesResponseType(typeof(ApiResponse<DraftEncounterDto>), StatusCodes.Status200OK)]
    [ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status404NotFound)]
    [ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status409Conflict)]
    public async Task<IActionResult> UpsertEncounter(
        Guid batchId, [FromBody] UpsertDraftEncounterRequest req)
    {
        var actorUserId = GetCurrentUserId();
        var result = await _draft.UpsertEncounterAsync(batchId, req, actorUserId);
        return Ok(ApiResponse<DraftEncounterDto>.Ok(result));
    }

    /// <summary>
    /// Adds a new observation row to the batch draft. Validates the value against
    /// plausibility ranges before saving.
    /// </summary>
    /// <param name="batchId">Digitization batch id.</param>
    /// <param name="req">Observation data to add.</param>
    /// <returns>The created observation record.</returns>
    [HttpPost("observations")]
    [ProducesResponseType(typeof(ApiResponse<DraftObservationDto>), StatusCodes.Status201Created)]
    [ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status404NotFound)]
    [ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status409Conflict)]
    [ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status422UnprocessableEntity)]
    public async Task<IActionResult> AddObservation(
        Guid batchId, [FromBody] CreateDraftObservationRequest req)
    {
        var actorUserId = GetCurrentUserId();
        var result = await _draft.AddObservationAsync(batchId, req, actorUserId);
        return StatusCode(201, ApiResponse<DraftObservationDto>.Created(result));
    }

    /// <summary>
    /// Updates an existing observation row in the batch draft. Re-validates the
    /// new value against plausibility ranges.
    /// </summary>
    /// <param name="batchId">Digitization batch id.</param>
    /// <param name="obsId">Observation id to update.</param>
    /// <param name="req">Updated observation data.</param>
    /// <returns>The updated observation record.</returns>
    [HttpPut("observations/{obsId:guid}")]
    [ProducesResponseType(typeof(ApiResponse<DraftObservationDto>), StatusCodes.Status200OK)]
    [ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status404NotFound)]
    [ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status409Conflict)]
    [ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status422UnprocessableEntity)]
    public async Task<IActionResult> UpdateObservation(
        Guid batchId, Guid obsId, [FromBody] UpdateDraftObservationRequest req)
    {
        var actorUserId = GetCurrentUserId();
        var result = await _draft.UpdateObservationAsync(batchId, obsId, req, actorUserId);
        return Ok(ApiResponse<DraftObservationDto>.Ok(result));
    }

    /// <summary>
    /// Removes an observation row from the batch draft.
    /// </summary>
    /// <param name="batchId">Digitization batch id.</param>
    /// <param name="obsId">Observation id to delete.</param>
    [HttpDelete("observations/{obsId:guid}")]
    [ProducesResponseType(StatusCodes.Status204NoContent)]
    [ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status404NotFound)]
    [ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status409Conflict)]
    public async Task<IActionResult> DeleteObservation(Guid batchId, Guid obsId)
    {
        var actorUserId = GetCurrentUserId();
        await _draft.DeleteObservationAsync(batchId, obsId, actorUserId);
        return NoContent();
    }

    /// <summary>
    /// Validates completeness per batch type and transitions the batch from
    /// IN_ENTRY to PENDING_VERIFICATION. Returns 422 if required fields are missing.
    /// </summary>
    /// <param name="batchId">Digitization batch id.</param>
    /// <returns>The updated batch record.</returns>
    [HttpPost("~/api/v1/digitization-batches/{batchId:guid}/submit-for-verification")]
    [ProducesResponseType(typeof(ApiResponse<BatchDetailResponse>), StatusCodes.Status200OK)]
    [ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status404NotFound)]
    [ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status409Conflict)]
    [ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status422UnprocessableEntity)]
    public async Task<IActionResult> SubmitForVerification(Guid batchId)
    {
        var actorUserId = GetCurrentUserId();
        var batch = await _draft.SubmitForVerificationAsync(batchId, actorUserId);
        return Ok(ApiResponse<BatchDetailResponse>.Ok(BatchDetailResponse.FromEntity(batch)));
    }

    private Guid GetCurrentUserId() =>
        Guid.Parse(User.FindFirstValue(ClaimTypes.NameIdentifier)!);
}