using BCrypt.Net;
using Knot.Contracts.Auth.Application.Abstractions;
using Knot.Contracts.Auth.Application.Auth.DTOs;
using Knot.Shared.Kernel;

namespace Knot.Modules.Auth.Application.Users.Login;

public sealed record LoginUserCommand(string Username, string Password) : ICommand<AuthResponseDto>;

public sealed class LoginUserCommandHandler : ICommandHandler<LoginUserCommand, AuthResponseDto>
{
    private readonly IUserRepository _userRepository;
    private readonly IJwtTokenProvider _tokenProvider;

    public LoginUserCommandHandler(IUserRepository userRepository, IJwtTokenProvider tokenProvider)
    {
        _userRepository = userRepository;
        _tokenProvider = tokenProvider;
    }

    public async Task<Result<AuthResponseDto>> Handle(LoginUserCommand request, CancellationToken cancellationToken)
    {
        var user = await _userRepository.GetByUsernameAsync(request.Username, cancellationToken);

        if (user is null || !BCrypt.Net.BCrypt.Verify(request.Password, user.PasswordHash))
        {
            return Result.Failure<AuthResponseDto>(AuthErrors.IdentityInvalidCredentials);
        }

        string token = _tokenProvider.Generate(user.Id, user.Username, user.DisplayName, user.Avatar);
        string refreshToken = _tokenProvider.GenerateRefreshToken();
        DateTime refreshExpiry = _tokenProvider.GetRefreshTokenExpiry();

        // Save refresh token to database
        user.SetRefreshToken(refreshToken, refreshExpiry);
        await _userRepository.UpdateAsync(user, cancellationToken);

        return Result.Success(new AuthResponseDto
        {
            AccessToken = token,
            RefreshToken = refreshToken,
            UserId = user.Id,
            Username = user.Username,
            DisplayName = user.DisplayName
        });
    }
}

