using Dapper; using GestionIntegral.Api.Models.Radios; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.Data; using System.Linq; using System.Text; using System.Threading.Tasks; namespace GestionIntegral.Api.Data.Repositories.Radios { public class CancionRepository : ICancionRepository { private readonly DbConnectionFactory _cf; private readonly ILogger _log; public CancionRepository(DbConnectionFactory cf, ILogger log) { _cf = cf; _log = log; } private string SelectWithAlias() => @" SELECT Id, Tema, CompositorAutor, Interprete, Sello, Placa, Pista, Introduccion, Ritmo AS IdRitmo, -- Mapear columna Ritmo a propiedad IdRitmo del modelo Cancion Formato, Album FROM dbo.rad_dtCanciones"; public async Task> GetAllAsync(string? temaFilter, string? interpreteFilter, int? idRitmoFilter) { var sqlBuilder = new StringBuilder(SelectWithAlias()); sqlBuilder.Append(" WHERE 1=1"); var parameters = new DynamicParameters(); if (!string.IsNullOrWhiteSpace(temaFilter)) { sqlBuilder.Append(" AND Tema LIKE @TemaParam"); parameters.Add("TemaParam", $"%{temaFilter}%"); } if (!string.IsNullOrWhiteSpace(interpreteFilter)) { sqlBuilder.Append(" AND Interprete LIKE @InterpreteParam"); parameters.Add("InterpreteParam", $"%{interpreteFilter}%"); } if (idRitmoFilter.HasValue) { sqlBuilder.Append(" AND Ritmo = @IdRitmoParam"); // La columna en DB es "Ritmo" parameters.Add("IdRitmoParam", idRitmoFilter.Value); } sqlBuilder.Append(" ORDER BY Tema, Interprete;"); try { using var connection = _cf.CreateConnection(); return await connection.QueryAsync(sqlBuilder.ToString(), parameters); } catch (Exception ex) { _log.LogError(ex, "Error al obtener todas las Canciones."); return Enumerable.Empty(); } } public async Task GetByIdAsync(int id) { var sql = SelectWithAlias() + " WHERE Id = @IdParam"; try { using var connection = _cf.CreateConnection(); return await connection.QuerySingleOrDefaultAsync(sql, new { IdParam = id }); } catch (Exception ex) { _log.LogError(ex, "Error al obtener Canción por ID: {IdCancion}", id); return null; } } public async Task ExistsByTemaAndInterpreteAsync(string tema, string interprete, int? excludeId = null) { // La unicidad puede ser más compleja si se consideran otros campos como Álbum. // Por ahora, un ejemplo simple. var sqlBuilder = new StringBuilder("SELECT COUNT(1) FROM dbo.rad_dtCanciones WHERE Tema = @TemaParam AND Interprete = @InterpreteParam"); var parameters = new DynamicParameters(); parameters.Add("TemaParam", tema); parameters.Add("InterpreteParam", interprete); if (excludeId.HasValue) { sqlBuilder.Append(" AND Id != @ExcludeIdParam"); parameters.Add("ExcludeIdParam", excludeId.Value); } try { using var connection = _cf.CreateConnection(); return await connection.ExecuteScalarAsync(sqlBuilder.ToString(), parameters); } catch (Exception ex) { _log.LogError(ex, "Error en ExistsByTemaAndInterpreteAsync. Tema: {Tema}, Interprete: {Interprete}", tema, interprete); return true; // Asumir que existe en caso de error } } public async Task CreateAsync(Cancion nuevaCancion /*, int idUsuario, IDbTransaction transaction */) { // El modelo Cancion usa IdRitmo, pero la tabla rad_dtCanciones usa la columna "Ritmo" para el FK a rad_dtRitmos.Id const string sqlInsert = @" INSERT INTO dbo.rad_dtCanciones (Tema, CompositorAutor, Interprete, Sello, Placa, Pista, Introduccion, Ritmo, Formato, Album) OUTPUT INSERTED.Id, INSERTED.Tema, INSERTED.CompositorAutor, INSERTED.Interprete, INSERTED.Sello, INSERTED.Placa, INSERTED.Pista, INSERTED.Introduccion, INSERTED.Ritmo AS IdRitmo, INSERTED.Formato, INSERTED.Album VALUES (@Tema, @CompositorAutor, @Interprete, @Sello, @Placa, @Pista, @Introduccion, @IdRitmo, @Formato, @Album);"; try { using var connection = _cf.CreateConnection(); // El objeto nuevaCancion tiene la propiedad IdRitmo, que Dapper mapeará al parámetro @IdRitmo return await connection.QuerySingleAsync(sqlInsert, nuevaCancion); } catch (Exception ex) { _log.LogError(ex, "Error al crear Canción: {Tema} por {Interprete}", nuevaCancion.Tema, nuevaCancion.Interprete); return null; } } public async Task UpdateAsync(Cancion cancionAActualizar /*, int idUsuario, IDbTransaction transaction */) { // Similar a Create, la columna en DB es "Ritmo" const string sqlUpdate = @" UPDATE dbo.rad_dtCanciones SET Tema = @Tema, CompositorAutor = @CompositorAutor, Interprete = @Interprete, Sello = @Sello, Placa = @Placa, Pista = @Pista, Introduccion = @Introduccion, Ritmo = @IdRitmo, Formato = @Formato, Album = @Album WHERE Id = @Id;"; try { using var connection = _cf.CreateConnection(); var rowsAffected = await connection.ExecuteAsync(sqlUpdate, cancionAActualizar); return rowsAffected == 1; } catch (Exception ex) { _log.LogError(ex, "Error al actualizar Canción ID: {IdCancion}", cancionAActualizar.Id); return false; } } public async Task DeleteAsync(int id /*, int idUsuario, IDbTransaction transaction */) { // IsInUseAsync no se implementó porque no hay dependencias directas obvias que impidan borrar una canción // (a menos que las listas generadas se guarden y referencien IDs de canciones). const string sqlDelete = "DELETE FROM dbo.rad_dtCanciones WHERE Id = @IdParam"; try { using var connection = _cf.CreateConnection(); var rowsAffected = await connection.ExecuteAsync(sqlDelete, new { IdParam = id }); return rowsAffected == 1; } catch (Exception ex) { _log.LogError(ex, "Error al eliminar Canción ID: {IdCancion}", id); return false; } } // IsInUseAsync podría ser relevante si las listas generadas referencian el Id de la canción // Por ahora, lo omitimos. public Task IsInUseAsync(int id) { _log.LogWarning("IsInUseAsync no implementado para CancionRepository."); return Task.FromResult(false); // Asumir que no está en uso por ahora } public async Task> GetRandomCancionesAsync(int count) { // El modelo Cancion tiene la propiedad "Ritmo" que es el IdRitmo. // El SelectWithAlias no es necesario aquí si solo tomamos las columnas que ya tiene Cancion. // Si el modelo Cancion no tuviera la propiedad Ritmo (IdRitmo), entonces necesitarías el alias. // Por simplicidad, y dado que el modelo Cancion sí tiene Ritmo (que es IdRitmo), no necesitamos un alias específico aquí. var sql = $"SELECT TOP ({count}) Id, Tema, CompositorAutor, Interprete, Sello, Placa, Pista, Introduccion, Ritmo, Formato, Album FROM dbo.rad_dtCanciones ORDER BY NEWID()"; try { using var connection = _cf.CreateConnection(); // Dapper mapeará la columna "Ritmo" de la BD a la propiedad "Ritmo" del modelo Cancion. return await connection.QueryAsync(sql); } catch (Exception ex) { _log.LogError(ex, "Error al obtener {Count} canciones aleatorias.", count); return Enumerable.Empty(); } } } }