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

namespace Baya.Application.Features.Identity.Commands.CreatePatient;

internal sealed class CreatePatientCommandHandler(ICurrentUser currentUser, IUnitOfWork unitOfWork)
    : IRequestHandler<CreatePatientCommand, OperationResult<PatientDto>>
{
    public async ValueTask<OperationResult<PatientDto>> Handle(CreatePatientCommand request, CancellationToken cancellationToken)
    {
        if (currentUser.UserId is not { } userId)
            return OperationResult<PatientDto>.UnauthorizedResult("Not authenticated.");

        if (currentUser.Roles?.Contains(RoleNames.Customer) != true)
            return OperationResult<PatientDto>.ForbiddenResult("Only a customer can register a patient.");

        var patient = new Patient
        {
            DisplayName = request.DisplayName,
            FirstName = request.FirstName,
            LastName = request.LastName,
            BirthDate = request.BirthDate,
            Gender = request.Gender,
            BloodType = request.BloodType,
            InitialMedicalNotes = request.InitialMedicalNotes,
            Relation = request.Relation,
            ConditionsJson = JsonCodeList.Serialize(request.Conditions),
            IsActive = true
        };

        var customerId = await unitOfWork.CustomerProfileRepository.GetProfileIdByUserIdAsync(userId, cancellationToken);
        if (customerId is { } existingCustomerId)
        {
            patient.CustomerId = existingCustomerId;
        }
        else
        {
            // First patient before any customer-profile save — provision the thin payer row so the
            // customer/patient split works without a separate profile step. The FK is fixed up on commit.
            var profile = new CustomerProfile { UserId = userId };
            await unitOfWork.CustomerProfileRepository.AddAsync(profile, cancellationToken);
            patient.Customer = profile;
        }

        await unitOfWork.PatientRepository.AddAsync(patient, cancellationToken);
        await unitOfWork.CommitAsync();

        return OperationResult<PatientDto>.SuccessResult(new PatientDto(
            patient.Id,
            patient.DisplayName,
            patient.FirstName,
            patient.LastName,
            patient.BirthDate,
            patient.Gender,
            patient.BloodType,
            patient.InitialMedicalNotes,
            patient.IsActive,
            patient.Relation,
            JsonCodeList.Parse(patient.ConditionsJson)));
    }
}
