using System.ComponentModel.DataAnnotations;
using Asp.Versioning;
using Baya.Application.Features.PatientCareRecords.Commands.UpsertCarePlan;
using Baya.Application.Features.PatientCareRecords.Commands.WritePatientCareRecord;
using Baya.Application.Features.PatientCareRecords.Queries.GetCarePlan;
using Baya.Application.Features.PatientCareRecords.Queries.GetPatientHistory;
using Baya.Application.Features.PatientCareRecords.Queries.GetRecordAccess;
using Baya.Application.Models.Common;
using Baya.Application.Models.Patients;
using Baya.Application.Models.Reviews;
using Baya.WebFramework.Attributes;
using Baya.WebFramework.BaseController;
using Mediator;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace Baya.Web.Api.Controllers.V1;

/// <summary>
/// Patient-scoped clinical care records. Writing is nurse-only (with a confirmed booking for that patient);
/// reading is restricted to the owning customer, a nurse with a confirmed booking, or admin — the strict
/// clinical access rule is enforced in the handler (not just this route policy). Clinical bodies are encrypted
/// at rest and decrypted only after the access check passes.
/// </summary>
[ApiVersion("1")]
[ApiController]
[Route("api/v{version:apiVersion}/patients")]
[Authorize]
[Display(Description = "Patient-scoped, encrypted clinical care records (write: nurse; read: owner/nurse/admin)")]
public sealed class PatientCareRecordsController(ISender sender) : BaseController
{
    [HttpPost("{patientId}/care_records")]
    [ProducesOkApiResponseType<WriteCareRecordResult>]
    public async Task<IActionResult> Write(long patientId, WriteCareRecordBody body, CancellationToken cancellationToken)
        => OperationResult(await sender.Send(
            new WritePatientCareRecordCommand(patientId, body.BookingId, body.Body, body.TaskResults), cancellationToken));

    [HttpGet("{patientId}/care_records")]
    [ProducesOkApiResponseType<PagedResult<CareRecordDto>>]
    public async Task<IActionResult> History(long patientId, [FromQuery] int page = 1, [FromQuery] int pageSize = 20, CancellationToken cancellationToken = default)
        => OperationResult(await sender.Send(new GetPatientHistoryQuery(patientId, page, pageSize), cancellationToken));

    // The family-owned care plan (medications/routine/tasks) — read (owner/nurse/admin), REQ-027.
    [HttpGet("{patientId}/care_record")]
    [ProducesOkApiResponseType<CarePlanDto>]
    public async Task<IActionResult> CarePlan(long patientId, CancellationToken cancellationToken)
        => OperationResult(await sender.Send(new GetCarePlanQuery(patientId), cancellationToken));

    // Replace the family-owned care plan (owning customer only), REQ-027.
    [HttpPut("{patientId}/care_record")]
    [ProducesOkApiResponseType<CarePlanDto>]
    public async Task<IActionResult> UpsertCarePlan(long patientId, UpsertCarePlanBody body, CancellationToken cancellationToken)
        => OperationResult(await sender.Send(
            new UpsertCarePlanCommand(patientId, body.Medications, body.Routine, body.Tasks), cancellationToken));

    // The caller's access to this patient's records (view/edit/append-note + non-leaking denied), REQ-027.
    [HttpGet("{patientId}/record_access")]
    [ProducesOkApiResponseType<RecordAccessDto>]
    public async Task<IActionResult> RecordAccess(long patientId, CancellationToken cancellationToken)
        => OperationResult(await sender.Send(new GetRecordAccessQuery(patientId), cancellationToken));

    /// <summary>The care-record body (the patient id comes from the route).</summary>
    public record WriteCareRecordBody(long? BookingId, string Body, IReadOnlyList<TaskResultDto>? TaskResults);

    /// <summary>The family care-plan body (the patient id comes from the route).</summary>
    public record UpsertCarePlanBody(
        IReadOnlyList<MedicationDto>? Medications,
        IReadOnlyList<RoutineItemDto>? Routine,
        IReadOnlyList<CareTaskDto>? Tasks);
}
