using Dapper;
using SIGCM2.Infrastructure.Persistence;
using SIGCM2.TestSupport;

namespace SIGCM2.Application.Tests.Integration;

[Collection("Database")]
public class UsuarioRepositoryTests : IAsyncLifetime
{
    private readonly SqlTestFixture _db;
    private UsuarioRepository _repository = null!;

    public UsuarioRepositoryTests(SqlTestFixture db)
    {
        _db = db;
    }

    public async Task InitializeAsync()
    {
        await _db.ResetAndSeedAsync();

        var factory = new SqlConnectionFactory(TestConnectionStrings.AppTestDb);
        _repository = new UsuarioRepository(factory);
    }

    public Task DisposeAsync() => Task.CompletedTask;

    // Scenario: GetByUsername returns correct entity when user exists
    [Fact]
    public async Task GetByUsernameAsync_ExistingUser_ReturnsUsuario()
    {
        var usuario = await _repository.GetByUsernameAsync("admin");

        Assert.NotNull(usuario);
        Assert.Equal("admin", usuario.Username);
        Assert.Equal("admin", usuario.Rol);
        Assert.True(usuario.Activo);
        Assert.False(string.IsNullOrWhiteSpace(usuario.PasswordHash));
    }

    // Triangulation: GetByUsername returns null when user does not exist
    [Fact]
    public async Task GetByUsernameAsync_NonExistentUser_ReturnsNull()
    {
        var usuario = await _repository.GetByUsernameAsync("noexiste");
        Assert.Null(usuario);
    }

    // Triangulation: case-sensitive username lookup (SQL Server UNIQUE constraint is case-insensitive by default)
    [Fact]
    public async Task GetByUsernameAsync_DifferentUser_ReturnsCorrectUser_Cajero()
    {
        // Insert a second user with canonical rol 'cajero' (post-UDT-004 FK requires Rol.Codigo to exist).
        await _db.Connection.ExecuteAsync(
            "INSERT INTO dbo.Usuario (Username, PasswordHash, Nombre, Apellido, Rol, PermisosJson) " +
            "VALUES ('cajero1', '$2a$12$hash2', 'Juan', 'Pérez', 'cajero', '[]')");

        var admin = await _repository.GetByUsernameAsync("admin");
        var cajero = await _repository.GetByUsernameAsync("cajero1");

        Assert.NotNull(admin);
        Assert.NotNull(cajero);
        Assert.NotEqual(admin.Id, cajero.Id);
        Assert.Equal("admin", admin.Rol);
        Assert.Equal("cajero", cajero.Rol);
    }
}
