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

namespace Baya.Application.Features.PatientCareRecords;

/// <summary>
/// The single resolver for a caller's access to a patient's records: <b>edit</b> = the owning customer,
/// <b>append-note</b> = a nurse with a confirmed booking for the patient, <b>view</b> = either of those or an
/// admin. Centralized so the family care-plan get/put, the visit-note write/history, and the explicit
/// <c>record_access</c> read all apply the exact same rule.
/// </summary>
internal static class PatientAccess
{
    private static readonly string[] AdminRoles = [RoleNames.Admin, RoleNames.SuperAdmin];

    public const string DeniedNotFound = "not_found";
    public const string DeniedNotAuthorized = "not_authorized";

    /// <summary>Resolves access. <c>OwnerCustomerId</c> is null when the patient does not exist (a
    /// <see cref="DeniedNotFound"/> access with everything false).</summary>
    public static async Task<(long? OwnerCustomerId, RecordAccessDto Access)> ResolveAsync(
        ICurrentUser currentUser, IUnitOfWork unitOfWork, long patientId, CancellationToken cancellationToken)
    {
        var ownerCustomerId = await unitOfWork.PatientCareRecordRepository.GetPatientOwnerCustomerIdAsync(patientId, cancellationToken);
        if (ownerCustomerId is null)
            return (null, new RecordAccessDto(false, false, false, DeniedNotFound));

        var isAdmin = currentUser.Roles?.Any(AdminRoles.Contains) == true;

        var userId = currentUser.UserId;
        var customerProfileId = userId is null
            ? null
            : await unitOfWork.CustomerProfileRepository.GetProfileIdByUserIdAsync(userId.Value, cancellationToken);
        var canEdit = customerProfileId is { } cid && cid == ownerCustomerId;

        var canAppendNote = false;
        if (userId is not null)
        {
            var nurseProfileId = await unitOfWork.NurseProfileRepository.GetProfileIdByUserIdAsync(userId.Value, cancellationToken);
            if (nurseProfileId is { } nurseId)
                canAppendNote = await unitOfWork.PatientCareRecordRepository
                    .NurseHasQualifyingBookingForPatientAsync(nurseId, patientId, cancellationToken);
        }

        var canView = canEdit || canAppendNote || isAdmin;
        return (ownerCustomerId, new RecordAccessDto(canView, canEdit, canAppendNote, canView ? null : DeniedNotAuthorized));
    }
}
