#nullable enable
using Baya.Application.Contracts.Common;
using Baya.Application.Contracts.Persistence;
using Baya.Application.Models.Common;
using Baya.Application.Models.Patients;
using Baya.Domain.Entities.Identity;
using Mediator;

namespace Baya.Application.Features.PatientCareRecords.Commands.UpsertCarePlan;

internal sealed class UpsertCarePlanCommandHandler(
    ICurrentUser currentUser,
    IUnitOfWork unitOfWork)
    : IRequestHandler<UpsertCarePlanCommand, OperationResult<CarePlanDto>>
{
    public async ValueTask<OperationResult<CarePlanDto>> Handle(UpsertCarePlanCommand request, CancellationToken cancellationToken)
    {
        if (currentUser.UserId is null)
            return OperationResult<CarePlanDto>.UnauthorizedResult("Not authenticated.");

        var (owner, access) = await PatientAccess.ResolveAsync(currentUser, unitOfWork, request.PatientId, cancellationToken);
        if (owner is null)
            return OperationResult<CarePlanDto>.NotFoundResult("Patient not found.");
        if (!access.CanEdit)
            return OperationResult<CarePlanDto>.ForbiddenResult("Only the owning customer can edit the care plan.");

        var (medsJson, meds) = CarePlanSerialization.AssignMedications(request.Medications);
        var (routineJson, routine) = CarePlanSerialization.AssignRoutine(request.Routine);
        var (tasksJson, tasks) = CarePlanSerialization.AssignTasks(request.Tasks);

        var plan = await unitOfWork.PatientCareRecordRepository.GetCarePlanAsync(request.PatientId, cancellationToken);
        if (plan is null)
        {
            plan = new PatientCarePlan { PatientId = request.PatientId };
            plan.MedicationsJson = medsJson;
            plan.RoutineJson = routineJson;
            plan.TasksJson = tasksJson;
            await unitOfWork.PatientCareRecordRepository.AddCarePlanAsync(plan, cancellationToken);
        }
        else
        {
            plan.MedicationsJson = medsJson;
            plan.RoutineJson = routineJson;
            plan.TasksJson = tasksJson;
        }

        await unitOfWork.CommitAsync();

        return OperationResult<CarePlanDto>.SuccessResult(new CarePlanDto(request.PatientId, meds, routine, tasks));
    }
}
