using NSubstitute;
using TeleWave.Application.Admin.Roles;
using TeleWave.Application.Admin.Users.CreateUser;
using TeleWave.Application.Common.Interfaces;
using TeleWave.Application.Common.Models;
using Xunit;

namespace TeleWave.Application.Tests.Admin.Users;

public class CreateUserCommandHandlerTests
{
    private readonly IIdentityService _identityService = Substitute.For<IIdentityService>();
    private readonly IRoleService _roleService = Substitute.For<IRoleService>();

    private CreateUserCommandHandler CreateHandler() => new(_identityService, _roleService);

    [Fact]
    public async Task Handle_WithValidRole_CreatesUserAndAssignsRole()
    {
        var roleId = Guid.NewGuid();
        var userId = Guid.NewGuid();
        _roleService
            .ListRolesAsync(Arg.Any<CancellationToken>())
            .Returns(new List<RoleDto> { new(roleId, "user", true) });
        _identityService
            .CreateUserAsync("bob", "Password1", Arg.Any<CancellationToken>())
            .Returns(Result.Success(userId));
        _roleService
            .ChangeUserRoleAsync(userId, roleId, Arg.Any<CancellationToken>())
            .Returns(Result.Success());

        var result = await CreateHandler()
            .Handle(new CreateUserCommand("bob", "Password1", roleId), CancellationToken.None);

        Assert.True(result.IsSuccess);
        Assert.Equal(userId, result.Value);
        await _roleService
            .Received(1)
            .ChangeUserRoleAsync(userId, roleId, Arg.Any<CancellationToken>());
    }

    [Fact]
    public async Task Handle_WithUnknownRole_ReturnsNotFoundAndDoesNotCreate()
    {
        _roleService.ListRolesAsync(Arg.Any<CancellationToken>()).Returns(new List<RoleDto>());

        var result = await CreateHandler()
            .Handle(
                new CreateUserCommand("bob", "Password1", Guid.NewGuid()),
                CancellationToken.None
            );

        Assert.False(result.IsSuccess);
        Assert.Equal(RoleErrors.NotFound, result.Error);
        await _identityService
            .DidNotReceive()
            .CreateUserAsync(Arg.Any<string>(), Arg.Any<string>(), Arg.Any<CancellationToken>());
    }
}
