using CMSMicroservice.Domain.Events;
namespace CMSMicroservice.Application.UserCQ.Commands.SetPasswordForUser;
public class SetPasswordForUserCommandHandler : IRequestHandler<SetPasswordForUserCommand, Unit>
{
    private readonly IApplicationDbContext _context;
    private readonly IHashService _hashService;

    public SetPasswordForUserCommandHandler(IApplicationDbContext context, IHashService hashService)
    {
        _context = context;
        _hashService = hashService;
    }

    public async Task<Unit> Handle(SetPasswordForUserCommand request, CancellationToken cancellationToken)
    {
        // basic validations
        if (!string.Equals(request.NewPassword, request.ConfirmPassword, StringComparison.Ordinal))
        {
            throw new CMSMicroservice.Application.Common.Exceptions.ValidationException(new[]
            {
                new FluentValidation.Results.ValidationFailure(nameof(request.ConfirmPassword), "کلمه عبور و تایید آن یکسان نیستند.")
            });
        }

        var user = await _context.Users.FirstOrDefaultAsync(u => u.Id == request.UserId, cancellationToken)
            ?? throw new NotFoundException(nameof(User), request.UserId);

        var hasExistingPassword = !string.IsNullOrWhiteSpace(user.HashPassword);
        if (hasExistingPassword)
        {
            if (string.IsNullOrWhiteSpace(request.CurrentPassword))
            {
                throw new CMSMicroservice.Application.Common.Exceptions.ValidationException(new[]
                {
                    new FluentValidation.Results.ValidationFailure(nameof(request.CurrentPassword), "کلمه عبور فعلی الزامی است.")
                });
            }
            if (!_hashService.VerifyPassword(request.CurrentPassword, user.HashPassword))
            {
                throw new UnauthorizedAccessException("کلمه عبور فعلی نادرست است.");
            }
        }

        // set new password (PBKDF2)
        user.HashPassword = _hashService.HashPassword(request.NewPassword);
        _context.Users.Update(user);
        user.AddDomainEvent(new CMSMicroservice.Domain.Events.SetPasswordForUserEvent(user));
        await _context.SaveChangesAsync(cancellationToken);

        return Unit.Value;
    }
}
