using Dapper;
using SIGCM2.Application.Abstractions.Persistence;
using SIGCM2.Domain.Entities;

namespace SIGCM2.Infrastructure.Persistence;

public sealed class PermisoRepository : IPermisoRepository
{
    private readonly SqlConnectionFactory _connectionFactory;

    public PermisoRepository(SqlConnectionFactory connectionFactory)
    {
        _connectionFactory = connectionFactory;
    }

    public async Task<IReadOnlyList<Permiso>> ListAsync(CancellationToken ct = default)
    {
        const string sql = """
            SELECT Id, Codigo, Nombre, Descripcion, Modulo, Activo, FechaCreacion
            FROM dbo.Permiso
            ORDER BY Id
            """;

        await using var connection = _connectionFactory.CreateConnection();
        await connection.OpenAsync(ct);

        var rows = await connection.QueryAsync<PermisoRow>(sql);
        return rows.Select(MapRow).ToList();
    }

    public async Task<Permiso?> GetByCodigoAsync(string codigo, CancellationToken ct = default)
    {
        const string sql = """
            SELECT Id, Codigo, Nombre, Descripcion, Modulo, Activo, FechaCreacion
            FROM dbo.Permiso
            WHERE Codigo = @Codigo
            """;

        await using var connection = _connectionFactory.CreateConnection();
        await connection.OpenAsync(ct);

        var row = await connection.QuerySingleOrDefaultAsync<PermisoRow>(sql, new { Codigo = codigo });
        return row is null ? null : MapRow(row);
    }

    public async Task<IReadOnlyList<Permiso>> GetByCodigosAsync(
        IEnumerable<string> codigos,
        CancellationToken ct = default)
    {
        var codigosList = codigos.ToList();
        if (codigosList.Count == 0)
            return Array.Empty<Permiso>();

        const string sql = """
            SELECT Id, Codigo, Nombre, Descripcion, Modulo, Activo, FechaCreacion
            FROM dbo.Permiso
            WHERE Codigo IN @Codigos
            """;

        await using var connection = _connectionFactory.CreateConnection();
        await connection.OpenAsync(ct);

        var rows = await connection.QueryAsync<PermisoRow>(sql, new { Codigos = codigosList });
        return rows.Select(MapRow).ToList();
    }

    private static Permiso MapRow(PermisoRow row)
        => Permiso.ForRead(
            id: row.Id,
            codigo: row.Codigo,
            nombre: row.Nombre,
            descripcion: row.Descripcion,
            modulo: row.Modulo,
            activo: row.Activo,
            fechaCreacion: row.FechaCreacion);

    private sealed record PermisoRow(
        int Id,
        string Codigo,
        string Nombre,
        string? Descripcion,
        string Modulo,
        bool Activo,
        DateTime FechaCreacion);
}
