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

namespace GestionIntegral.Api.Services.Suscripciones
{
    public class PromocionService : IPromocionService
    {
        private readonly IPromocionRepository _promocionRepository;
        private readonly DbConnectionFactory _connectionFactory;
        private readonly ILogger<PromocionService> _logger;

        public PromocionService(
            IPromocionRepository promocionRepository,
            DbConnectionFactory connectionFactory,
            ILogger<PromocionService> logger)
        {
            _promocionRepository = promocionRepository;
            _connectionFactory = connectionFactory;
            _logger = logger;
        }

        private PromocionDto MapToDto(Promocion promo)
        {
            return new PromocionDto
            {
                IdPromocion = promo.IdPromocion,
                Descripcion = promo.Descripcion,
                TipoEfecto = promo.TipoEfecto,
                ValorEfecto = promo.ValorEfecto,
                TipoCondicion = promo.TipoCondicion,
                ValorCondicion = promo.ValorCondicion,
                FechaInicio = promo.FechaInicio.ToString("yyyy-MM-dd"),
                FechaFin = promo.FechaFin?.ToString("yyyy-MM-dd"),
                Activa = promo.Activa
            };
        }

        public async Task<IEnumerable<PromocionDto>> ObtenerTodas(bool soloActivas)
        {
            var promociones = await _promocionRepository.GetAllAsync(soloActivas);
            return promociones.Select(MapToDto);
        }

        public async Task<PromocionDto?> ObtenerPorId(int id)
        {
            var promocion = await _promocionRepository.GetByIdAsync(id);
            return promocion != null ? MapToDto(promocion) : null;
        }

        public async Task<(PromocionDto? Promocion, string? Error)> Crear(CreatePromocionDto createDto, int idUsuario)
        {
            if (createDto.FechaFin.HasValue && createDto.FechaFin.Value < createDto.FechaInicio)
            {
                return (null, "La fecha de fin no puede ser anterior a la fecha de inicio.");
            }

            var nuevaPromocion = new Promocion
            {
                Descripcion = createDto.Descripcion,
                TipoEfecto = createDto.TipoEfecto,
                ValorEfecto = createDto.ValorEfecto,
                TipoCondicion = createDto.TipoCondicion,
                ValorCondicion = createDto.ValorCondicion,
                FechaInicio = createDto.FechaInicio,
                FechaFin = createDto.FechaFin,
                Activa = createDto.Activa,
                IdUsuarioAlta = idUsuario
            };

            using var connection = _connectionFactory.CreateConnection();
            await (connection as System.Data.Common.DbConnection)!.OpenAsync();
            using var transaction = connection.BeginTransaction();
            try
            {
                var promocionCreada = await _promocionRepository.CreateAsync(nuevaPromocion, transaction);
                if (promocionCreada == null) throw new DataException("Error al crear la promoción.");

                transaction.Commit();
                _logger.LogInformation("Promoción ID {Id} creada por Usuario ID {UserId}.", promocionCreada.IdPromocion, idUsuario);
                return (MapToDto(promocionCreada), null);
            }
            catch (Exception ex)
            {
                try { transaction.Rollback(); } catch { }
                _logger.LogError(ex, "Error al crear promoción: {Descripcion}", createDto.Descripcion);
                return (null, $"Error interno al crear la promoción: {ex.Message}");
            }
        }

        public async Task<(bool Exito, string? Error)> Actualizar(int id, UpdatePromocionDto updateDto, int idUsuario)
        {
            var existente = await _promocionRepository.GetByIdAsync(id);
            if (existente == null) return (false, "Promoción no encontrada.");

            if (updateDto.FechaFin.HasValue && updateDto.FechaFin.Value < updateDto.FechaInicio)
            {
                return (false, "La fecha de fin no puede ser anterior a la fecha de inicio.");
            }

            existente.Descripcion = updateDto.Descripcion;
            existente.TipoEfecto = updateDto.TipoEfecto;
            existente.ValorEfecto = updateDto.ValorEfecto;
            existente.TipoCondicion = updateDto.TipoCondicion;
            existente.ValorCondicion = updateDto.ValorCondicion;
            existente.FechaInicio = updateDto.FechaInicio;
            existente.FechaFin = updateDto.FechaFin;
            existente.Activa = updateDto.Activa;

            using var connection = _connectionFactory.CreateConnection();
            await (connection as System.Data.Common.DbConnection)!.OpenAsync();
            using var transaction = connection.BeginTransaction();
            try
            {
                var actualizado = await _promocionRepository.UpdateAsync(existente, transaction);
                if (!actualizado) throw new DataException("Error al actualizar la promoción.");

                transaction.Commit();
                _logger.LogInformation("Promoción ID {Id} actualizada por Usuario ID {UserId}.", id, idUsuario);
                return (true, null);
            }
            catch (Exception ex)
            {
                try { transaction.Rollback(); } catch { }
                _logger.LogError(ex, "Error al actualizar promoción ID: {Id}", id);
                return (false, $"Error interno al actualizar: {ex.Message}");
            }
        }
    }
}