using GestionIntegral.Api.Data; using GestionIntegral.Api.Data.Repositories.Distribucion; using GestionIntegral.Api.Dtos.Distribucion; using GestionIntegral.Api.Models.Distribucion; using Microsoft.Extensions.Logging; using System.Collections.Generic; using System.Data; using System.Linq; using System.Threading.Tasks; namespace GestionIntegral.Api.Services.Distribucion { public class PubliSeccionService : IPubliSeccionService { private readonly IPubliSeccionRepository _publiSeccionRepository; private readonly IPublicacionRepository _publicacionRepository; // Para validar IdPublicacion private readonly DbConnectionFactory _connectionFactory; private readonly ILogger _logger; public PubliSeccionService( IPubliSeccionRepository publiSeccionRepository, IPublicacionRepository publicacionRepository, DbConnectionFactory connectionFactory, ILogger logger) { _publiSeccionRepository = publiSeccionRepository; _publicacionRepository = publicacionRepository; _connectionFactory = connectionFactory; _logger = logger; } private PubliSeccionDto MapToDto(PubliSeccion seccion) => new PubliSeccionDto { IdSeccion = seccion.IdSeccion, IdPublicacion = seccion.IdPublicacion, Nombre = seccion.Nombre, Estado = seccion.Estado }; public async Task> ObtenerPorPublicacionIdAsync(int idPublicacion, bool? soloActivas = null) { var secciones = await _publiSeccionRepository.GetByPublicacionIdAsync(idPublicacion, soloActivas); return secciones.Select(MapToDto); } public async Task ObtenerPorIdAsync(int idSeccion) { var seccion = await _publiSeccionRepository.GetByIdAsync(idSeccion); return seccion == null ? null : MapToDto(seccion); } public async Task<(PubliSeccionDto? Seccion, string? Error)> CrearAsync(CreatePubliSeccionDto createDto, int idUsuario) { if (await _publicacionRepository.GetByIdSimpleAsync(createDto.IdPublicacion) == null) return (null, "La publicación especificada no existe."); if (await _publiSeccionRepository.ExistsByNameInPublicacionAsync(createDto.Nombre, createDto.IdPublicacion)) return (null, "Ya existe una sección con ese nombre para esta publicación."); var nuevaSeccion = new PubliSeccion { IdPublicacion = createDto.IdPublicacion, Nombre = createDto.Nombre, Estado = createDto.Estado }; 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 { var seccionCreada = await _publiSeccionRepository.CreateAsync(nuevaSeccion, idUsuario, transaction); if (seccionCreada == null) throw new DataException("Error al crear la sección."); transaction.Commit(); _logger.LogInformation("Sección ID {Id} creada por Usuario ID {UserId}.", seccionCreada.IdSeccion, idUsuario); return (MapToDto(seccionCreada), null); } catch (Exception ex) { try { transaction.Rollback(); } catch { } _logger.LogError(ex, "Error CrearAsync PubliSeccion para Pub ID {IdPub}, Nombre: {Nombre}", createDto.IdPublicacion, createDto.Nombre); return (null, $"Error interno: {ex.Message}"); } } public async Task<(bool Exito, string? Error)> ActualizarAsync(int idSeccion, UpdatePubliSeccionDto updateDto, int idUsuario) { 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 { var seccionExistente = await _publiSeccionRepository.GetByIdAsync(idSeccion); // Obtener dentro de TX if (seccionExistente == null) return (false, "Sección no encontrada."); // Validar unicidad de nombre solo si el nombre ha cambiado if (seccionExistente.Nombre != updateDto.Nombre && await _publiSeccionRepository.ExistsByNameInPublicacionAsync(updateDto.Nombre, seccionExistente.IdPublicacion, idSeccion)) { return (false, "Ya existe otra sección con ese nombre para esta publicación."); } seccionExistente.Nombre = updateDto.Nombre; seccionExistente.Estado = updateDto.Estado; var actualizado = await _publiSeccionRepository.UpdateAsync(seccionExistente, idUsuario, transaction); if (!actualizado) throw new DataException("Error al actualizar la sección."); transaction.Commit(); _logger.LogInformation("Sección ID {Id} actualizada por Usuario ID {UserId}.", idSeccion, idUsuario); return (true, null); } catch (KeyNotFoundException) { try { transaction.Rollback(); } catch { } return (false, "Sección no encontrada."); } catch (Exception ex) { try { transaction.Rollback(); } catch { } _logger.LogError(ex, "Error ActualizarAsync PubliSeccion ID: {Id}", idSeccion); return (false, $"Error interno: {ex.Message}"); } } public async Task<(bool Exito, string? Error)> EliminarAsync(int idSeccion, int idUsuario) { 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 { var seccionExistente = await _publiSeccionRepository.GetByIdAsync(idSeccion); // Obtener dentro de TX if (seccionExistente == null) return (false, "Sección no encontrada."); if (await _publiSeccionRepository.IsInUseAsync(idSeccion)) { return (false, "No se puede eliminar. La sección está siendo utilizada en registros de tiradas o stock de bobinas."); } var eliminado = await _publiSeccionRepository.DeleteAsync(idSeccion, idUsuario, transaction); if (!eliminado) throw new DataException("Error al eliminar la sección."); transaction.Commit(); _logger.LogInformation("Sección ID {Id} eliminada por Usuario ID {UserId}.", idSeccion, idUsuario); return (true, null); } catch (KeyNotFoundException) { try { transaction.Rollback(); } catch { } return (false, "Sección no encontrada."); } catch (Exception ex) { try { transaction.Rollback(); } catch { } _logger.LogError(ex, "Error EliminarAsync PubliSeccion ID: {Id}", idSeccion); return (false, $"Error interno: {ex.Message}"); } } } }