using System.Text;
using System.Text.Json;
using e_suite.API.Common.extensions;
using Microsoft.Extensions.Configuration;
using RabbitMQ.Client;

namespace e_suite.Messaging.Common;

public abstract class MessageSenderBase : IDisposable
{
    private readonly IConfiguration _configuration;
    private readonly IRabbitMqConnectionFactory _connectionFactory;
    private IConnection? _connection = null;
    private IChannel? _channel = null;
    private readonly string _messageQueueName;

    public async Task<IChannel> GetChannel()
    {
        if (_channel == null)
        {
            _connectionFactory.HostName = _configuration.GetConfigValue("RABBITMQ_HOSTNAME", "RabbitMQ:hostname", "localhost")!;

            if (!string.Equals(_connectionFactory.HostName, "localhost", StringComparison.InvariantCultureIgnoreCase)
                && !string.Equals(_connectionFactory.HostName, "host.docker.internal", StringComparison.InvariantCultureIgnoreCase))
            {
                _connectionFactory.VirtualHost = _configuration.GetConfigValue("RABBITMQ_VHOST", "RabbitMQ:vhost", "")!;
                _connectionFactory.UserName = _configuration.GetConfigValue("RABBITMQ_USER", "RabbitMQ:user", "")!;
                _connectionFactory.Password = _configuration.GetConfigValue("RABBITMQ_PASSWORD", "RabbitMQ:password", "")!;
            }

            _connection = _connectionFactory.CreateConnection();
            _channel = await _connection.CreateChannelAsync();

            await _channel.QueueDeclareAsync(queue: _messageQueueName,
                durable: false,
                exclusive: false,
                autoDelete: false,
                arguments: null);
        }

        return _channel;
    }

    protected MessageSenderBase(IConfiguration configuration, IRabbitMqConnectionFactory connectionFactory, string messageQueueName)
    {
        ArgumentNullException.ThrowIfNull(configuration, nameof(configuration));
        _configuration = configuration;
        _connectionFactory = connectionFactory;
        _messageQueueName = messageQueueName;
    }

    public virtual void Dispose()
    {
        GC.SuppressFinalize(this);
        if (_channel != null)
        {
            _channel.Dispose();
            _connection!.Dispose();
        }
    }

    protected async Task PostMessage<T>(T message)
    {
        var json = JsonSerializer.Serialize(message);
        var body = Encoding.UTF8.GetBytes(json);

        var channel = await GetChannel();
        await channel.BasicPublishAsync(
            exchange: string.Empty,
            routingKey: _messageQueueName,
            mandatory: false,
            basicProperties: new BasicProperties(),
            body: body);
    }
}