using GestionIntegral.Api.Data;
using GestionIntegral.Api.Data.Repositories.Suscripciones;
using GestionIntegral.Api.Data.Repositories.Usuarios;
using GestionIntegral.Api.Dtos.Suscripciones;
using GestionIntegral.Api.Models.Suscripciones;
using System.Data;

namespace GestionIntegral.Api.Services.Suscripciones
{
    public class PagoService : IPagoService
    {
        private readonly IPagoRepository _pagoRepository;
        private readonly IFacturaRepository _facturaRepository;
        private readonly IFormaPagoRepository _formaPagoRepository;
        private readonly IUsuarioRepository _usuarioRepository;
        private readonly DbConnectionFactory _connectionFactory;
        private readonly ILogger<PagoService> _logger;

        public PagoService(
            IPagoRepository pagoRepository,
            IFacturaRepository facturaRepository,
            IFormaPagoRepository formaPagoRepository,
            IUsuarioRepository usuarioRepository,
            DbConnectionFactory connectionFactory,
            ILogger<PagoService> logger)
        {
            _pagoRepository = pagoRepository;
            _facturaRepository = facturaRepository;
            _formaPagoRepository = formaPagoRepository;
            _usuarioRepository = usuarioRepository;
            _connectionFactory = connectionFactory;
            _logger = logger;
        }

        private async Task<PagoDto?> MapToDto(Pago pago)
        {
            if (pago == null) return null;
            var formaPago = await _formaPagoRepository.GetByIdAsync(pago.IdFormaPago);
            var usuario = await _usuarioRepository.GetByIdAsync(pago.IdUsuarioRegistro);
            return new PagoDto
            {
                IdPago = pago.IdPago,
                IdFactura = pago.IdFactura,
                FechaPago = pago.FechaPago.ToString("yyyy-MM-dd"),
                IdFormaPago = pago.IdFormaPago,
                NombreFormaPago = formaPago?.Nombre ?? "Desconocida",
                Monto = pago.Monto,
                Estado = pago.Estado,
                Referencia = pago.Referencia,
                Observaciones = pago.Observaciones,
                IdUsuarioRegistro = pago.IdUsuarioRegistro,
                NombreUsuarioRegistro = usuario != null ? $"{usuario.Nombre} {usuario.Apellido}" : "Usuario Desconocido"
            };
        }

        public async Task<IEnumerable<PagoDto>> ObtenerPagosPorFacturaId(int idFactura)
        {
            var pagos = await _pagoRepository.GetByFacturaIdAsync(idFactura);
            var dtosTasks = pagos.Select(p => MapToDto(p));
            var dtos = await Task.WhenAll(dtosTasks);
            return dtos.Where(dto => dto != null)!;
        }

        public async Task<(PagoDto? Pago, string? Error)> RegistrarPagoManual(CreatePagoDto createDto, int idUsuario)
        {
            using var connection = _connectionFactory.CreateConnection();
            await (connection as System.Data.Common.DbConnection)!.OpenAsync();
            using var transaction = connection.BeginTransaction();
            try
            {
                var factura = await _facturaRepository.GetByIdAsync(createDto.IdFactura);
                if (factura == null) return (null, "La factura especificada no existe.");
                if (factura.EstadoPago == "Anulada") return (null, "No se puede registrar un pago sobre una factura anulada.");

                var formaPago = await _formaPagoRepository.GetByIdAsync(createDto.IdFormaPago);
                if (formaPago == null || !formaPago.Activo) return (null, "La forma de pago no es válida.");

                var totalPagadoAnteriormente = await _pagoRepository.GetTotalPagadoAprobadoAsync(createDto.IdFactura, transaction);

                var nuevoPago = new Pago
                {
                    IdFactura = createDto.IdFactura,
                    FechaPago = createDto.FechaPago,
                    IdFormaPago = createDto.IdFormaPago,
                    Monto = createDto.Monto,
                    Estado = "Aprobado",
                    Referencia = createDto.Referencia,
                    Observaciones = createDto.Observaciones,
                    IdUsuarioRegistro = idUsuario
                };

                // Creamos el nuevo pago
                var pagoCreado = await _pagoRepository.CreateAsync(nuevoPago, transaction);
                if (pagoCreado == null) throw new DataException("No se pudo registrar el pago.");

                var nuevoTotalPagado = totalPagadoAnteriormente + pagoCreado.Monto;

                // Nueva lógica para manejar todos los estados de pago
                string nuevoEstadoPago = factura.EstadoPago;
                if (nuevoTotalPagado >= factura.ImporteFinal)
                {
                    nuevoEstadoPago = "Pagada";
                }
                else if (nuevoTotalPagado > 0)
                {
                    nuevoEstadoPago = "Pagada Parcialmente";
                }
                // Si nuevoTotalPagado es 0, el estado no cambia.

                // Solo actualizamos si el estado calculado es diferente al actual.
                if (nuevoEstadoPago != factura.EstadoPago)
                {
                    bool actualizado = await _facturaRepository.UpdateEstadoPagoAsync(factura.IdFactura, nuevoEstadoPago, transaction);
                    if (!actualizado) throw new DataException($"No se pudo actualizar el estado de la factura a '{nuevoEstadoPago}'.");
                }

                transaction.Commit();
                _logger.LogInformation("Pago manual ID {IdPago} registrado para Factura ID {IdFactura} por Usuario ID {IdUsuario}", pagoCreado.IdPago, pagoCreado.IdFactura, idUsuario);

                var dto = await MapToDto(pagoCreado); // MapToDto ahora es más simple
                return (dto, null);
            }
            catch (Exception ex)
            {
                try { transaction.Rollback(); } catch { }
                _logger.LogError(ex, "Error al registrar pago manual para Factura ID {IdFactura}", createDto.IdFactura);
                return (null, $"Error interno al registrar el pago: {ex.Message}");
            }
        }
    }
}