#nullable enable
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.UpsertCustomerProfile;

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

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

        var phone = IranianPhone.Normalize(request.DefaultEmergencyContactPhone) ?? request.DefaultEmergencyContactPhone;

        var profile = await unitOfWork.CustomerProfileRepository.GetByUserIdAsync(userId, cancellationToken);
        if (profile is null)
        {
            profile = new CustomerProfile
            {
                UserId = userId,
                DefaultEmergencyContactName = request.DefaultEmergencyContactName,
                DefaultEmergencyContactPhone = phone,
                PreferredLanguage = request.PreferredLanguage
            };
            await unitOfWork.CustomerProfileRepository.AddAsync(profile, cancellationToken);
        }
        else
        {
            profile.DefaultEmergencyContactName = request.DefaultEmergencyContactName;
            profile.DefaultEmergencyContactPhone = phone;
            if (request.PreferredLanguage is not null)
                profile.PreferredLanguage = request.PreferredLanguage;
        }

        // The customer's display name lives on the base identity row, not the profile — update it in the
        // same unit of work when supplied.
        if (request.FirstName is not null || request.LastName is not null)
        {
            var user = await unitOfWork.UserAccountRepository.GetTrackedByIdAsync(userId, cancellationToken);
            if (user is not null)
            {
                if (request.FirstName is not null)
                    user.Name = request.FirstName;
                if (request.LastName is not null)
                    user.FamilyName = request.LastName;
            }
        }

        await unitOfWork.CommitAsync();

        var dto = await unitOfWork.CustomerProfileRepository.GetMineAsync(userId, cancellationToken);
        return OperationResult<CustomerProfileDto>.SuccessResult(dto!);
    }
}
