using GestionIntegral.Api.Data;
using GestionIntegral.Api.Data.Repositories.Distribucion;
using GestionIntegral.Api.Data.Repositories.Usuarios;
using GestionIntegral.Api.Dtos.Distribucion;
using GestionIntegral.Api.Models.Distribucion;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using System.Security.Claims;
using GestionIntegral.Api.Dtos.Auditoria;

namespace GestionIntegral.Api.Services.Distribucion
{
    public class EntradaSalidaCanillaService : IEntradaSalidaCanillaService
    {
        private readonly IEntradaSalidaCanillaRepository _esCanillaRepository;
        private readonly IPublicacionRepository _publicacionRepository;
        private readonly ICanillaRepository _canillaRepository;
        private readonly IPrecioRepository _precioRepository;
        private readonly IRecargoZonaRepository _recargoZonaRepository;
        private readonly IPorcMonCanillaRepository _porcMonCanillaRepository;
        private readonly IUsuarioRepository _usuarioRepository;
        private readonly DbConnectionFactory _connectionFactory;
        private readonly ILogger<EntradaSalidaCanillaService> _logger;

        public EntradaSalidaCanillaService(
            IEntradaSalidaCanillaRepository esCanillaRepository,
            IPublicacionRepository publicacionRepository,
            ICanillaRepository canillaRepository,
            IPrecioRepository precioRepository,
            IRecargoZonaRepository recargoZonaRepository,
            IPorcMonCanillaRepository porcMonCanillaRepository,
            IUsuarioRepository usuarioRepository,
            DbConnectionFactory connectionFactory,
            ILogger<EntradaSalidaCanillaService> logger)
        {
            _esCanillaRepository = esCanillaRepository;
            _publicacionRepository = publicacionRepository;
            _canillaRepository = canillaRepository;
            _precioRepository = precioRepository;
            _recargoZonaRepository = recargoZonaRepository;
            _porcMonCanillaRepository = porcMonCanillaRepository;
            _usuarioRepository = usuarioRepository;
            _connectionFactory = connectionFactory;
            _logger = logger;
        }

        private async Task<EntradaSalidaCanillaDto?> MapToDto(EntradaSalidaCanilla? es)
        {
            if (es == null) return null;

            var publicacionDataResult = await _publicacionRepository.GetByIdAsync(es.IdPublicacion);
            var canillaDataResult = await _canillaRepository.GetByIdAsync(es.IdCanilla); // Devuelve tupla

            Publicacion? publicacionEntity = publicacionDataResult.Publicacion; // Componente nullable de la tupla
            Canilla? canillaEntity = canillaDataResult.Canilla; // Componente nullable de la tupla

            var usuarioLiq = es.UserLiq.HasValue ? await _usuarioRepository.GetByIdAsync(es.UserLiq.Value) : null;

            decimal montoARendir = await CalcularMontoARendir(es, canillaEntity, publicacionEntity);

            return new EntradaSalidaCanillaDto
            {
                IdParte = es.IdParte,
                IdPublicacion = es.IdPublicacion,
                NombrePublicacion = publicacionEntity?.Nombre ?? "Pub. Desconocida",
                IdCanilla = es.IdCanilla,
                NomApeCanilla = canillaEntity?.NomApe ?? "Can. Desconocido",
                CanillaEsAccionista = canillaEntity?.Accionista ?? false,
                Fecha = es.Fecha.ToString("yyyy-MM-dd"),
                CantSalida = es.CantSalida,
                CantEntrada = es.CantEntrada,
                Vendidos = es.CantSalida - es.CantEntrada,
                Observacion = es.Observacion,
                Liquidado = es.Liquidado,
                FechaLiquidado = es.FechaLiquidado?.ToString("yyyy-MM-dd"),
                UserLiq = es.UserLiq,
                NombreUserLiq = usuarioLiq != null ? $"{usuarioLiq.Nombre} {usuarioLiq.Apellido}" : null,
                MontoARendir = montoARendir,
                PrecioUnitarioAplicado = (await _precioRepository.GetByIdAsync(es.IdPrecio))?.Lunes ?? 0,
                RecargoAplicado = es.IdRecargo > 0 ? (await _recargoZonaRepository.GetByIdAsync(es.IdRecargo))?.Valor ?? 0 : 0,
                PorcentajeOMontoCanillaAplicado = es.IdPorcMon > 0 ? (await _porcMonCanillaRepository.GetByIdAsync(es.IdPorcMon))?.PorcMon ?? 0 : 0,
                EsPorcentajeCanilla = es.IdPorcMon > 0 ? (await _porcMonCanillaRepository.GetByIdAsync(es.IdPorcMon))?.EsPorcentaje ?? false : false
            };
        }

        private async Task<decimal> CalcularMontoARendir(EntradaSalidaCanilla es, Canilla? canilla, Publicacion? publicacion) // Acepta nullable Canilla y Publicacion
        {
            if (es.CantSalida - es.CantEntrada <= 0) return 0;

            var precioConfig = await _precioRepository.GetByIdAsync(es.IdPrecio);
            if (precioConfig == null)
            {
                _logger.LogError("Configuración de precio ID {IdPrecio} no encontrada para movimiento ID {IdParte}.", es.IdPrecio, es.IdParte);
                throw new InvalidOperationException($"Configuración de precio ID {es.IdPrecio} no encontrada para el movimiento.");
            }

            decimal precioDia = 0;
            DayOfWeek diaSemana = es.Fecha.DayOfWeek;
            switch (diaSemana)
            {
                case DayOfWeek.Monday: precioDia = precioConfig.Lunes ?? 0; break;
                case DayOfWeek.Tuesday: precioDia = precioConfig.Martes ?? 0; break;
                case DayOfWeek.Wednesday: precioDia = precioConfig.Miercoles ?? 0; break;
                case DayOfWeek.Thursday: precioDia = precioConfig.Jueves ?? 0; break;
                case DayOfWeek.Friday: precioDia = precioConfig.Viernes ?? 0; break;
                case DayOfWeek.Saturday: precioDia = precioConfig.Sabado ?? 0; break;
                case DayOfWeek.Sunday: precioDia = precioConfig.Domingo ?? 0; break;
            }

            decimal valorRecargo = 0;
            if (es.IdRecargo > 0)
            {
                var recargoConfig = await _recargoZonaRepository.GetByIdAsync(es.IdRecargo);
                if (recargoConfig != null) valorRecargo = recargoConfig.Valor;
            }

            decimal precioFinalUnitario = precioDia + valorRecargo;
            int cantidadVendida = es.CantSalida - es.CantEntrada;

            if (canilla != null && canilla.Accionista && es.IdPorcMon > 0) // Check null para canilla
            {
                var porcMonConfig = await _porcMonCanillaRepository.GetByIdAsync(es.IdPorcMon);
                if (porcMonConfig != null)
                {
                    if (porcMonConfig.EsPorcentaje)
                    {
                        return Math.Round((precioFinalUnitario * cantidadVendida * porcMonConfig.PorcMon) / 100, 2);
                    }
                    else
                    {
                        return Math.Round(cantidadVendida * porcMonConfig.PorcMon, 2);
                    }
                }
            }
            return Math.Round(precioFinalUnitario * cantidadVendida, 2);
        }

        public async Task<IEnumerable<EntradaSalidaCanillaDto>> ObtenerTodosAsync(
            DateTime? fechaDesde, DateTime? fechaHasta,
            int? idPublicacion, int? idCanilla, bool? liquidados, bool? incluirNoLiquidados)
        {
            bool? filtroLiquidadoFinal = null;
            if (liquidados.HasValue)
            {
                filtroLiquidadoFinal = liquidados.Value;
            }
            else
            {
                if (incluirNoLiquidados.HasValue && !incluirNoLiquidados.Value)
                {
                    filtroLiquidadoFinal = true;
                }
            }

            var movimientos = await _esCanillaRepository.GetAllAsync(fechaDesde, fechaHasta, idPublicacion, idCanilla, filtroLiquidadoFinal);
            var dtos = new List<EntradaSalidaCanillaDto>();
            foreach (var mov in movimientos)
            {
                var dto = await MapToDto(mov);
                if (dto != null) dtos.Add(dto);
            }
            return dtos;
        }

        public async Task<EntradaSalidaCanillaDto?> ObtenerPorIdAsync(int idParte)
        {
            var movimiento = await _esCanillaRepository.GetByIdAsync(idParte);
            return await MapToDto(movimiento);
        }

        public async Task<(bool Exito, string? Error)> ActualizarMovimientoAsync(int idParte, UpdateEntradaSalidaCanillaDto updateDto, int idUsuario)
        {
            using var connection = _connectionFactory.CreateConnection();
            if (connection is System.Data.Common.DbConnection dbConnOpen && connection.State == ConnectionState.Closed) await dbConnOpen.OpenAsync(); else if (connection.State == ConnectionState.Closed) connection.Open();
            using var transaction = connection.BeginTransaction();
            try
            {
                var esExistente = await _esCanillaRepository.GetByIdAsync(idParte);
                if (esExistente == null) return (false, "Movimiento no encontrado.");
                if (esExistente.Liquidado) return (false, "No se puede modificar un movimiento ya liquidado.");

                esExistente.CantSalida = updateDto.CantSalida;
                esExistente.CantEntrada = updateDto.CantEntrada;
                esExistente.Observacion = updateDto.Observacion;

                var actualizado = await _esCanillaRepository.UpdateAsync(esExistente, idUsuario, transaction);
                if (!actualizado) throw new DataException("Error al actualizar el movimiento.");

                transaction.Commit();
                _logger.LogInformation("Movimiento Canillita ID {Id} actualizado por Usuario ID {UserId}.", idParte, idUsuario);
                return (true, null);
            }
            catch (KeyNotFoundException) { if (transaction.Connection != null) try { transaction.Rollback(); } catch { } return (false, "Movimiento no encontrado."); }
            catch (Exception ex)
            {
                if (transaction.Connection != null) try { transaction.Rollback(); } catch { }
                _logger.LogError(ex, "Error ActualizarMovimientoAsync Canillita ID: {Id}", idParte);
                return (false, $"Error interno: {ex.Message}");
            }
            finally
            {
                if (connection?.State == ConnectionState.Open)
                {
                    if (connection is System.Data.Common.DbConnection dbConnClose) await dbConnClose.CloseAsync(); else connection.Close();
                }
            }
        }

        public async Task<(bool Exito, string? Error)> EliminarMovimientoAsync(int idParte, int idUsuario, ClaimsPrincipal userPrincipal)
        {
            // Helper interno para verificar permisos desde el ClaimsPrincipal proporcionado
            bool TienePermisoEspecifico(string codAcc) => userPrincipal.IsInRole("SuperAdmin") || userPrincipal.HasClaim(c => c.Type == "permission" && c.Value == codAcc);

            using var connection = _connectionFactory.CreateConnection();
            IDbTransaction? transaction = null;

            try
            {
                if (connection is System.Data.Common.DbConnection dbConnOpen && connection.State == ConnectionState.Closed) await dbConnOpen.OpenAsync();
                else if (connection.State == ConnectionState.Closed) connection.Open();

                transaction = connection.BeginTransaction();

                var esExistente = await _esCanillaRepository.GetByIdAsync(idParte); // Obtener el estado actual
                if (esExistente == null)
                {
                    if (transaction?.Connection != null) transaction.Rollback();
                    return (false, "Movimiento no encontrado.");
                }

                if (esExistente.Liquidado)
                {
                    if (!TienePermisoEspecifico("MC006")) // <--- AQUÍ ESTÁ LA VERIFICACIÓN
                    {
                        if (transaction?.Connection != null) transaction.Rollback();
                        return (false, "No tiene permiso para eliminar movimientos ya liquidados. Se requiere permiso especial (MC006) o ser SuperAdmin.");
                    }
                    _logger.LogWarning("Usuario ID {IdUsuario} está eliminando un movimiento LIQUIDADO (IDParte: {IdParte}). Permiso MC006 verificado.", idUsuario, idParte);
                }
                // Si no está liquidado, el permiso MC004 ya fue verificado en el controlador (o debería serlo).

                var eliminado = await _esCanillaRepository.DeleteAsync(idParte, idUsuario, transaction); // Ahora esto no lanzará la excepción por liquidado
                if (!eliminado)
                {
                    // No es necesario hacer rollback aquí si DeleteAsync lanza una excepción,
                    // ya que el bloque catch lo manejará. Si DeleteAsync devuelve false sin lanzar,
                    // entonces sí sería necesario un rollback.
                    if (transaction?.Connection != null) transaction.Rollback();
                    throw new DataException("Error al eliminar el movimiento desde el repositorio.");
                }

                if (transaction?.Connection != null) transaction.Commit();
                _logger.LogInformation("Movimiento Canillita ID {IdParte} eliminado por Usuario ID {IdUsuario}.", idParte, idUsuario);
                return (true, null);
            }
            catch (KeyNotFoundException)
            {
                if (transaction?.Connection != null) try { transaction.Rollback(); } catch (Exception exR) { _logger.LogError(exR, "Rollback fallido KeyNotFoundException."); }
                return (false, "Movimiento no encontrado.");
            }
            catch (Exception ex)
            {
                if (transaction?.Connection != null) { try { transaction.Rollback(); } catch (Exception exRollback) { _logger.LogError(exRollback, "Error durante rollback de transacción."); } }
                _logger.LogError(ex, "Error EliminarMovimientoAsync Canillita ID: {IdParte}", idParte);
                return (false, $"Error interno: {ex.Message}");
            }
            finally
            {
                if (transaction != null) transaction.Dispose();
                if (connection?.State == ConnectionState.Open)
                {
                    if (connection is System.Data.Common.DbConnection dbConnClose) await dbConnClose.CloseAsync(); else connection.Close();
                }
            }
        }

        public async Task<(bool Exito, string? Error)> LiquidarMovimientosAsync(LiquidarMovimientosCanillaRequestDto liquidarDto, int idUsuarioLiquidador)
        {
            if (liquidarDto.IdsPartesALiquidar == null || !liquidarDto.IdsPartesALiquidar.Any())
                return (false, "No se especificaron movimientos para liquidar.");

            using var connection = _connectionFactory.CreateConnection();
            if (connection is System.Data.Common.DbConnection dbConnOpen && connection.State == ConnectionState.Closed) await dbConnOpen.OpenAsync(); else if (connection.State == ConnectionState.Closed) connection.Open();
            using var transaction = connection.BeginTransaction();
            try
            {
                bool liquidacionExitosa = await _esCanillaRepository.LiquidarAsync(liquidarDto.IdsPartesALiquidar, liquidarDto.FechaLiquidacion.Date, idUsuarioLiquidador, transaction);

                if (!liquidacionExitosa)
                {
                    _logger.LogWarning("Liquidación de movimientos de canillita pudo no haber afectado a todos los IDs solicitados. IDs: {Ids}", string.Join(",", liquidarDto.IdsPartesALiquidar));
                }

                if (transaction.Connection != null) transaction.Commit();
                _logger.LogInformation("Movimientos de Canillita liquidados. Ids: {Ids} por Usuario ID {UserId}.", string.Join(",", liquidarDto.IdsPartesALiquidar), idUsuarioLiquidador);
                return (true, null);
            }
            catch (Exception ex)
            {
                if (transaction.Connection != null) { try { transaction.Rollback(); } catch (Exception exRollback) { _logger.LogError(exRollback, "Error durante rollback de transacción."); } }
                _logger.LogError(ex, "Error al liquidar movimientos de canillita.");
                return (false, $"Error interno al liquidar movimientos: {ex.Message}");
            }
            finally
            {
                if (connection?.State == ConnectionState.Open)
                {
                    if (connection is System.Data.Common.DbConnection dbConnClose) await dbConnClose.CloseAsync(); else connection.Close();
                }
            }
        }

        public async Task<(IEnumerable<EntradaSalidaCanillaDto>? MovimientosCreados, string? Error)> CrearMovimientosEnLoteAsync(CreateBulkEntradaSalidaCanillaDto createBulkDto, int idUsuario)
        {
            var canillaDataResult = await _canillaRepository.GetByIdAsync(createBulkDto.IdCanilla);
            Canilla? canillaActual = canillaDataResult.Canilla;
            if (canillaActual == null) return (null, "Canillita no válido.");
            if (canillaActual.Baja) return (null, "El canillita está dado de baja.");

            List<EntradaSalidaCanilla> movimientosCreadosEntidades = new List<EntradaSalidaCanilla>();
            List<string> erroresItems = new List<string>();

            using var connection = _connectionFactory.CreateConnection();
            if (connection is System.Data.Common.DbConnection dbConnOpen && connection.State == ConnectionState.Closed) await dbConnOpen.OpenAsync(); else if (connection.State == ConnectionState.Closed) connection.Open();
            using var transaction = connection.BeginTransaction();

            try
            {
                foreach (var itemDto in createBulkDto.Items.Where(i => i.IdPublicacion > 0))
                {
                    if (await _esCanillaRepository.ExistsByPublicacionCanillaFechaAsync(itemDto.IdPublicacion, createBulkDto.IdCanilla, createBulkDto.Fecha.Date, transaction: transaction))
                    {
                        var pubInfo = await _publicacionRepository.GetByIdSimpleAsync(itemDto.IdPublicacion);
                        erroresItems.Add($"Ya existe un registro para la publicación '{pubInfo?.Nombre ?? itemDto.IdPublicacion.ToString()}' para {canillaActual.NomApe} en la fecha {createBulkDto.Fecha:dd/MM/yyyy}.");
                    }
                }
                if (erroresItems.Any())
                {
                    if (transaction.Connection != null) transaction.Rollback();
                    return (null, string.Join(" ", erroresItems));
                }

                foreach (var itemDto in createBulkDto.Items)
                {
                    if (itemDto.IdPublicacion == 0 && itemDto.CantSalida == 0 && itemDto.CantEntrada == 0 && string.IsNullOrWhiteSpace(itemDto.Observacion)) continue;
                    if (itemDto.IdPublicacion == 0)
                    {
                        if (itemDto.CantSalida > 0 || itemDto.CantEntrada > 0 || !string.IsNullOrWhiteSpace(itemDto.Observacion))
                        {
                            erroresItems.Add($"Falta seleccionar la publicación para una de las líneas con cantidades/observación.");
                        }
                        continue;
                    }

                    var publicacionItem = await _publicacionRepository.GetByIdSimpleAsync(itemDto.IdPublicacion);
                    bool noEsValidaONoHabilitada = false;
                    if (publicacionItem == null)
                    {
                        noEsValidaONoHabilitada = true;
                    }
                    else
                    {
                        // Si Habilitada es bool? y NULL significa que toma el DEFAULT 1 (true) de la BD
                        // entonces solo consideramos error si es explícitamente false.
                        if (publicacionItem.Habilitada.HasValue && publicacionItem.Habilitada.Value == false)
                        {
                            noEsValidaONoHabilitada = true;
                        }
                        // Si publicacionItem.Habilitada es null o true, noEsValidaONoHabilitada permanece false.
                    }

                    if (noEsValidaONoHabilitada)
                    {
                        erroresItems.Add($"Publicación ID {itemDto.IdPublicacion} no es válida o no está habilitada.");
                        continue;
                    }

                    var precioActivo = await _precioRepository.GetActiveByPublicacionAndDateAsync(itemDto.IdPublicacion, createBulkDto.Fecha.Date, transaction);
                    if (precioActivo == null)
                    {
                        string nombrePubParaError = publicacionItem?.Nombre ?? $"ID {itemDto.IdPublicacion}";
                        erroresItems.Add($"No hay precio definido para '{nombrePubParaError}' en {createBulkDto.Fecha:dd/MM/yyyy}.");
                        continue;
                    }

                    RecargoZona? recargoActivo = null;
                    // Aquí usamos canillaActual! porque ya verificamos que no es null al inicio del método.
                    if (canillaActual!.IdZona > 0)
                    {
                        recargoActivo = await _recargoZonaRepository.GetActiveByPublicacionZonaAndDateAsync(itemDto.IdPublicacion, canillaActual.IdZona, createBulkDto.Fecha.Date, transaction);
                    }

                    PorcMonCanilla? porcMonActivo = null;
                    // Aquí usamos canillaActual! porque ya verificamos que no es null al inicio del método.
                    if (canillaActual!.Accionista)
                    {
                        porcMonActivo = await _porcMonCanillaRepository.GetActiveByPublicacionCanillaAndDateAsync(itemDto.IdPublicacion, createBulkDto.IdCanilla, createBulkDto.Fecha.Date, transaction);
                        if (porcMonActivo == null)
                        {
                            // Dentro de este bloque, canillaActual.NomApe es seguro porque Accionista era true.
                            string nombreCanParaError = canillaActual.NomApe;
                            string nombrePubParaError = publicacionItem?.Nombre ?? $"Publicación ID {itemDto.IdPublicacion}";
                            erroresItems.Add($"'{nombreCanParaError}' es accionista pero no tiene %/monto para '{nombrePubParaError}' en {createBulkDto.Fecha:dd/MM/yyyy}.");
                            continue;
                        }
                    }

                    var nuevoES = new EntradaSalidaCanilla
                    {
                        IdPublicacion = itemDto.IdPublicacion,
                        IdCanilla = createBulkDto.IdCanilla,
                        Fecha = createBulkDto.Fecha.Date,
                        CantSalida = itemDto.CantSalida,
                        CantEntrada = itemDto.CantEntrada,
                        Observacion = itemDto.Observacion,
                        IdPrecio = precioActivo.IdPrecio,
                        IdRecargo = recargoActivo?.IdRecargo ?? 0,
                        IdPorcMon = porcMonActivo?.IdPorcMon ?? 0,
                        Liquidado = false,
                        FechaLiquidado = null,
                        UserLiq = null
                    };

                    var esCreada = await _esCanillaRepository.CreateAsync(nuevoES, idUsuario, transaction);
                    if (esCreada == null) throw new DataException($"Error al registrar movimiento para Publicación ID {itemDto.IdPublicacion}.");
                    movimientosCreadosEntidades.Add(esCreada);
                }

                if (erroresItems.Any())
                {
                    if (transaction.Connection != null) transaction.Rollback();
                    return (null, string.Join(" ", erroresItems));
                }

                // CORRECCIÓN PARA CS0019 (línea 394 original):
                bool tieneItemsSignificativos = false;
                if (createBulkDto.Items != null) // Checkear si Items es null antes de llamar a Any()
                {
                    tieneItemsSignificativos = createBulkDto.Items.Any(i => i.IdPublicacion > 0 &&
                                                                    (i.CantSalida > 0 || i.CantEntrada > 0 || !string.IsNullOrWhiteSpace(i.Observacion)));
                }

                if (!movimientosCreadosEntidades.Any() && tieneItemsSignificativos)
                {
                    if (transaction.Connection != null) transaction.Rollback();
                    return (null, "No se pudo procesar ningún ítem válido con datos significativos.");
                }

                if (transaction.Connection != null) transaction.Commit();
                _logger.LogInformation("Lote de {Count} movimientos Canillita para Canilla ID {IdCanilla} en Fecha {Fecha} creados por Usuario ID {UserId}.",
                    movimientosCreadosEntidades.Count, createBulkDto.IdCanilla, createBulkDto.Fecha.Date, idUsuario);

                var dtosCreados = new List<EntradaSalidaCanillaDto>();
                foreach (var entidad in movimientosCreadosEntidades)
                {
                    var dto = await MapToDto(entidad);
                    if (dto != null) dtosCreados.Add(dto);
                }
                return (dtosCreados, null);
            }
            catch (Exception ex)
            {
                if (transaction.Connection != null) { try { transaction.Rollback(); } catch (Exception exRollback) { _logger.LogError(exRollback, "Error durante rollback de transacción."); } }
                _logger.LogError(ex, "Error CrearMovimientosEnLoteAsync para Canilla ID {IdCanilla}, Fecha {Fecha}", createBulkDto.IdCanilla, createBulkDto.Fecha);
                return (null, $"Error interno al procesar el lote: {ex.Message}");
            }
            finally
            {
                if (connection?.State == ConnectionState.Open)
                {
                    if (connection is System.Data.Common.DbConnection dbConnClose) await dbConnClose.CloseAsync(); else connection.Close();
                }
            }
        }

        public async Task<IEnumerable<EntradaSalidaCanillaHistorialDto>> ObtenerHistorialAsync(
        DateTime? fechaDesde, DateTime? fechaHasta,
        int? idUsuarioModifico, string? tipoModificacion,
        int? idParteAfectada)
        {
            // Asumiendo que _esCanillaRepository es tu IEntradaSalidaCanillaRepository
            var historialData = await _esCanillaRepository.GetHistorialAsync(fechaDesde, fechaHasta, idUsuarioModifico, tipoModificacion, idParteAfectada);

            return historialData.Select(h => new EntradaSalidaCanillaHistorialDto
            {
                Id_Parte = h.Historial.Id_Parte,
                Id_Publicacion = h.Historial.Id_Publicacion,
                Id_Canilla = h.Historial.Id_Canilla,
                Fecha = h.Historial.Fecha,
                CantSalida = h.Historial.CantSalida,
                CantEntrada = h.Historial.CantEntrada,
                Id_Precio = h.Historial.Id_Precio,
                Id_Recargo = h.Historial.Id_Recargo,
                Id_PorcMon = h.Historial.Id_PorcMon,
                Observacion = h.Historial.Observacion,
                Id_Usuario = h.Historial.Id_Usuario,
                NombreUsuarioModifico = h.NombreUsuarioModifico,
                FechaMod = h.Historial.FechaMod,
                TipoMod = h.Historial.TipoMod
            }).ToList();
        }
    }
}