using Dapper; using SIGCM.Domain.Entities; using SIGCM.Infrastructure.Data; namespace SIGCM.Infrastructure.Repositories; public class ClientRepository { private readonly IDbConnectionFactory _db; public ClientRepository(IDbConnectionFactory db) { _db = db; } // Búsqueda inteligente redireccionada a Users public async Task> SearchAsync(string query) { using var conn = _db.CreateConnection(); var sql = @" SELECT TOP 10 Id, ISNULL(BillingName, Username) as Name, ISNULL(BillingTaxId, '') as DniOrCuit, Email, Phone, BillingAddress as Address, BillingTaxType as TaxType, Username, IsActive, Role FROM Users WHERE BillingName LIKE @Query OR BillingTaxId LIKE @Query OR Username LIKE @Query ORDER BY BillingName"; return await conn.QueryAsync(sql, new { Query = $"%{query}%" }); } // Asegurar existencia (Upsert en la tabla Users) public async Task EnsureClientExistsAsync(string name, string dni) { using var conn = _db.CreateConnection(); var existingId = await conn.ExecuteScalarAsync( "SELECT Id FROM Users WHERE BillingTaxId = @Dni", new { Dni = dni }); if (existingId.HasValue) { await conn.ExecuteAsync("UPDATE Users SET BillingName = @Name WHERE Id = @Id", new { Name = name, Id = existingId }); return existingId.Value; } else { // Si no existe, creamos un usuario con rol Cliente (sin password por ahora, es solo para gestión de mostrador) var sql = @" INSERT INTO Users (Username, Role, BillingName, BillingTaxId, PasswordHash, MustChangePassword) VALUES (@Username, 'Client', @Name, @Dni, 'N/A', 0); SELECT CAST(SCOPE_IDENTITY() as int);"; // El username será el DNI para asegurar unicidad si no hay otro dato return await conn.QuerySingleAsync(sql, new { Username = dni, Name = name, Dni = dni }); } } // Obtener con estadísticas desde Users (con filtro y límite para performance) public async Task> GetAllWithStatsAsync(string? searchTerm = null) { using var conn = _db.CreateConnection(); var sql = @" SELECT TOP 100 u.Id as id, ISNULL(u.BillingName, u.Username) as name, ISNULL(u.BillingTaxId, 'S/D') as dniOrCuit, ISNULL(u.Email, 'Sin correo') as email, ISNULL(u.Phone, 'Sin teléfono') as phone, ISNULL(u.BillingTaxType, 'Consumidor Final') as taxType, u.Username as username, u.IsActive as isActive, u.Role as role, (SELECT COUNT(1) FROM Listings l WHERE l.ClientId = u.Id) as totalAds, ISNULL((SELECT SUM(AdFee) FROM Listings l WHERE l.ClientId = u.Id), 0) as totalSpent FROM Users u WHERE Role IN ('Client', 'User')"; if (!string.IsNullOrWhiteSpace(searchTerm)) { sql += " AND (u.BillingName LIKE @Query OR u.BillingTaxId LIKE @Query OR u.Username LIKE @Query)"; } sql += " ORDER BY name"; return await conn.QueryAsync(sql, new { Query = $"%{searchTerm}%" }); } public async Task UpdateAsync(Client client) { using var conn = _db.CreateConnection(); var sql = @" UPDATE Users SET BillingName = @Name, BillingTaxId = @DniOrCuit, Email = @Email, Phone = @Phone, BillingAddress = @Address, BillingTaxType = @TaxType, Username = @Username, IsActive = @IsActive WHERE Id = @Id"; await conn.ExecuteAsync(sql, client); } public async Task GetClientSummaryAsync(int clientId) { using var conn = _db.CreateConnection(); var sql = @" SELECT u.Id, ISNULL(u.BillingName, u.Username) as Name, u.BillingTaxId as DniOrCuit, u.Email, u.Phone, u.BillingAddress as Address, u.BillingTaxType as TaxType, u.Username, u.IsActive, u.Role, (SELECT COUNT(1) FROM Listings WHERE ClientId = u.Id) as TotalAds, ISNULL((SELECT SUM(AdFee) FROM Listings WHERE ClientId = u.Id), 0) as TotalInvested, (SELECT MAX(CreatedAt) FROM Listings WHERE ClientId = u.Id) as LastAdDate, (SELECT COUNT(1) FROM Listings WHERE ClientId = u.Id AND Status = 'Published') as ActiveAds, ISNULL(( SELECT TOP 1 cat.Name FROM Listings l JOIN Categories cat ON l.CategoryId = cat.Id WHERE l.ClientId = u.Id GROUP BY cat.Name ORDER BY COUNT(l.Id) DESC ), 'N/A') as PreferredCategory FROM Users u WHERE u.Id = @Id"; return await conn.QuerySingleOrDefaultAsync(sql, new { Id = clientId }); } public async Task ResetPasswordAsync(int clientId, string passwordHash) { using var conn = _db.CreateConnection(); var sql = "UPDATE Users SET PasswordHash = @Hash, MustChangePassword = 1 WHERE Id = @Id"; await conn.ExecuteAsync(sql, new { Hash = passwordHash, Id = clientId }); } public async Task CreateFullClientAsync(Client client) { using var conn = _db.CreateConnection(); var sql = @" INSERT INTO Users ( Username, PasswordHash, Role, BillingName, BillingTaxId, Email, Phone, BillingAddress, BillingTaxType, MustChangePassword, IsActive, CreatedAt ) VALUES ( @DniOrCuit, 'N/A', 'Client', @Name, @DniOrCuit, @Email, @Phone, @Address, @TaxType, 0, 1, GETUTCDATE() ); SELECT CAST(SCOPE_IDENTITY() as int);"; // Usamos el CUIT como username por defecto para garantizar unicidad return await conn.QuerySingleAsync(sql, client); } }