using GestionIntegral.Api.Data; using GestionIntegral.Api.Data.Repositories.Distribucion; using GestionIntegral.Api.Data.Repositories.Impresion; using GestionIntegral.Api.Dtos.Impresion; using GestionIntegral.Api.Models.Distribucion; // Para Publicacion, PubliSeccion using GestionIntegral.Api.Models.Impresion; // Para RegTirada, RegPublicacionSeccion using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.Data; using System.Linq; using System.Threading.Tasks; namespace GestionIntegral.Api.Services.Impresion { public class TiradaService : ITiradaService { private readonly IRegTiradaRepository _regTiradaRepository; private readonly IRegPublicacionSeccionRepository _regPublicacionSeccionRepository; private readonly IPublicacionRepository _publicacionRepository; private readonly IPlantaRepository _plantaRepository; private readonly IPubliSeccionRepository _publiSeccionRepository; // Para validar IDs de sección private readonly DbConnectionFactory _connectionFactory; private readonly ILogger _logger; public TiradaService( IRegTiradaRepository regTiradaRepository, IRegPublicacionSeccionRepository regPublicacionSeccionRepository, IPublicacionRepository publicacionRepository, IPlantaRepository plantaRepository, IPubliSeccionRepository publiSeccionRepository, DbConnectionFactory connectionFactory, ILogger logger) { _regTiradaRepository = regTiradaRepository; _regPublicacionSeccionRepository = regPublicacionSeccionRepository; _publicacionRepository = publicacionRepository; _plantaRepository = plantaRepository; _publiSeccionRepository = publiSeccionRepository; _connectionFactory = connectionFactory; _logger = logger; } public async Task> ObtenerTiradasAsync(DateTime? fecha, int? idPublicacion, int? idPlanta) { var tiradasPrincipales = await _regTiradaRepository.GetByCriteriaAsync(fecha, idPublicacion, idPlanta); var resultado = new List(); foreach (var tiradaP in tiradasPrincipales) { var publicacion = await _publicacionRepository.GetByIdSimpleAsync(tiradaP.IdPublicacion); var planta = await _plantaRepository.GetByIdAsync(tiradaP.IdPlanta); var seccionesImpresas = await _regPublicacionSeccionRepository.GetByFechaPublicacionPlantaAsync(tiradaP.Fecha, tiradaP.IdPublicacion, tiradaP.IdPlanta); var detallesSeccionDto = new List(); int totalPaginas = 0; foreach (var seccionImp in seccionesImpresas) { var seccionInfo = await _publiSeccionRepository.GetByIdAsync(seccionImp.IdSeccion); detallesSeccionDto.Add(new DetalleSeccionEnListadoDto { IdSeccion = seccionImp.IdSeccion, NombreSeccion = seccionInfo?.Nombre ?? "Sección Desconocida", CantPag = seccionImp.CantPag, IdRegPublicacionSeccion = seccionImp.IdTirada // Este es el PK de bob_RegPublicaciones }); totalPaginas += seccionImp.CantPag; } resultado.Add(new TiradaDto { IdRegistroTirada = tiradaP.IdRegistro, IdPublicacion = tiradaP.IdPublicacion, NombrePublicacion = publicacion?.Nombre ?? "Publicación Desconocida", Fecha = tiradaP.Fecha.ToString("yyyy-MM-dd"), IdPlanta = tiradaP.IdPlanta, NombrePlanta = planta?.Nombre ?? "Planta Desconocida", Ejemplares = tiradaP.Ejemplares, SeccionesImpresas = detallesSeccionDto, TotalPaginasSumadas = totalPaginas }); } return resultado; } public async Task<(TiradaDto? TiradaCreada, string? Error)> RegistrarTiradaCompletaAsync(CreateTiradaRequestDto createDto, int idUsuario) { // Validaciones previas var publicacion = await _publicacionRepository.GetByIdSimpleAsync(createDto.IdPublicacion); if (publicacion == null) return (null, "La publicación especificada no existe."); var planta = await _plantaRepository.GetByIdAsync(createDto.IdPlanta); if (planta == null) return (null, "La planta especificada no existe."); // Validar que no exista ya una tirada para esa Publicación, Fecha y Planta // (bob_RegTiradas debería ser único por estos campos) if (await _regTiradaRepository.GetByFechaPublicacionPlantaAsync(createDto.Fecha.Date, createDto.IdPublicacion, createDto.IdPlanta) != null) { return (null, $"Ya existe una tirada registrada para la publicación '{publicacion.Nombre}' en la planta '{planta.Nombre}' para la fecha {createDto.Fecha:dd/MM/yyyy}."); } // Validar secciones foreach (var seccionDto in createDto.Secciones) { var seccionDb = await _publiSeccionRepository.GetByIdAsync(seccionDto.IdSeccion); if (seccionDb == null || seccionDb.IdPublicacion != createDto.IdPublicacion) return (null, $"La sección con ID {seccionDto.IdSeccion} no es válida o no pertenece a la publicación seleccionada."); if (!seccionDb.Estado) // Asumiendo que solo se pueden tirar secciones activas return (null, $"La sección '{seccionDb.Nombre}' no está activa y no puede incluirse en la tirada."); } using var connection = _connectionFactory.CreateConnection(); if (connection is System.Data.Common.DbConnection dbConn) await dbConn.OpenAsync(); else connection.Open(); using var transaction = connection.BeginTransaction(); try { // 1. Crear registro en bob_RegTiradas (total de ejemplares) var nuevaRegTirada = new RegTirada { IdPublicacion = createDto.IdPublicacion, Fecha = createDto.Fecha.Date, IdPlanta = createDto.IdPlanta, Ejemplares = createDto.Ejemplares }; var regTiradaCreada = await _regTiradaRepository.CreateAsync(nuevaRegTirada, idUsuario, transaction); if (regTiradaCreada == null) throw new DataException("Error al registrar el total de la tirada."); // 2. Crear registros en bob_RegPublicaciones (detalle de secciones y páginas) var seccionesImpresasDto = new List(); int totalPaginasSumadas = 0; foreach (var seccionDto in createDto.Secciones) { var nuevaRegPubSeccion = new RegPublicacionSeccion { IdPublicacion = createDto.IdPublicacion, IdSeccion = seccionDto.IdSeccion, CantPag = seccionDto.CantPag, Fecha = createDto.Fecha.Date, IdPlanta = createDto.IdPlanta }; var seccionCreadaEnTirada = await _regPublicacionSeccionRepository.CreateAsync(nuevaRegPubSeccion, idUsuario, transaction); if (seccionCreadaEnTirada == null) throw new DataException($"Error al registrar la sección ID {seccionDto.IdSeccion} en la tirada."); var seccionInfo = await _publiSeccionRepository.GetByIdAsync(seccionDto.IdSeccion); // Para obtener nombre seccionesImpresasDto.Add(new DetalleSeccionEnListadoDto{ IdSeccion = seccionCreadaEnTirada.IdSeccion, NombreSeccion = seccionInfo?.Nombre ?? "N/A", CantPag = seccionCreadaEnTirada.CantPag, IdRegPublicacionSeccion = seccionCreadaEnTirada.IdTirada }); totalPaginasSumadas += seccionCreadaEnTirada.CantPag; } transaction.Commit(); _logger.LogInformation("Tirada completa registrada para Pub ID {IdPub}, Fecha {Fecha}, Planta ID {IdPlanta} por Usuario ID {UserId}.", createDto.IdPublicacion, createDto.Fecha.Date, createDto.IdPlanta, idUsuario); return (new TiradaDto { IdRegistroTirada = regTiradaCreada.IdRegistro, IdPublicacion = regTiradaCreada.IdPublicacion, NombrePublicacion = publicacion.Nombre, Fecha = regTiradaCreada.Fecha.ToString("yyyy-MM-dd"), IdPlanta = regTiradaCreada.IdPlanta, NombrePlanta = planta.Nombre, Ejemplares = regTiradaCreada.Ejemplares, SeccionesImpresas = seccionesImpresasDto, TotalPaginasSumadas = totalPaginasSumadas }, null); } catch (Exception ex) { try { transaction.Rollback(); } catch { } _logger.LogError(ex, "Error RegistrarTiradaCompletaAsync para Pub ID {IdPub}, Fecha {Fecha}", createDto.IdPublicacion, createDto.Fecha); return (null, $"Error interno: {ex.Message}"); } } public async Task<(bool Exito, string? Error)> EliminarTiradaCompletaAsync(DateTime fecha, int idPublicacion, int idPlanta, int idUsuario) { // Verificar que la tirada principal exista var tiradaPrincipal = await _regTiradaRepository.GetByFechaPublicacionPlantaAsync(fecha.Date, idPublicacion, idPlanta); if (tiradaPrincipal == null) { return (false, "No se encontró una tirada principal para los criterios especificados."); } using var connection = _connectionFactory.CreateConnection(); if (connection is System.Data.Common.DbConnection dbConn) await dbConn.OpenAsync(); else connection.Open(); using var transaction = connection.BeginTransaction(); try { // 1. Eliminar detalles de secciones de bob_RegPublicaciones // El método ya guarda en historial await _regPublicacionSeccionRepository.DeleteByFechaPublicacionPlantaAsync(fecha.Date, idPublicacion, idPlanta, idUsuario, transaction); _logger.LogInformation("Secciones de tirada eliminadas para Fecha: {Fecha}, PubID: {IdPublicacion}, PlantaID: {IdPlanta}", fecha.Date, idPublicacion, idPlanta); // 2. Eliminar el registro principal de bob_RegTiradas // El método ya guarda en historial bool principalEliminado = await _regTiradaRepository.DeleteByFechaPublicacionPlantaAsync(fecha.Date, idPublicacion, idPlanta, idUsuario, transaction); // bool principalEliminado = await _regTiradaRepository.DeleteAsync(tiradaPrincipal.IdRegistro, idUsuario, transaction); // Alternativa si ya tienes el IdRegistro if (!principalEliminado && tiradaPrincipal != null) // Si DeleteByFechaPublicacionPlantaAsync devuelve false porque no encontró nada (raro si pasó la validación) { _logger.LogWarning("No se eliminó el registro principal de tirada (bob_RegTiradas) para Fecha: {Fecha}, PubID: {IdPublicacion}, PlantaID: {IdPlanta}. Pudo haber sido eliminado concurrentemente.", fecha.Date, idPublicacion, idPlanta); // Decidir si esto es un error que debe hacer rollback } _logger.LogInformation("Registro principal de tirada eliminado para Fecha: {Fecha}, PubID: {IdPublicacion}, PlantaID: {IdPlanta}", fecha.Date, idPublicacion, idPlanta); transaction.Commit(); return (true, null); } catch (Exception ex) { try { transaction.Rollback(); } catch { } _logger.LogError(ex, "Error EliminarTiradaCompletaAsync para Fecha {Fecha}, PubID {IdPub}, PlantaID {IdPlanta}", fecha.Date, idPublicacion, idPlanta); return (false, $"Error interno al eliminar la tirada: {ex.Message}"); } } } }