﻿using System;

using System.Threading.Tasks;
using Microsoft.ServiceBus.Messaging;
using Zombus.Configuration.Settings;

namespace Zombus.Infrastructure.MessageSendersAndReceivers
{
    internal class OnReceiveMessageReceiver : IEventBasedReceiver
    {
        private readonly IQueueManager _queueManager;
        private readonly string _queuePath;
        private readonly ConcurrentHandlerLimitSetting _concurrentHandlerLimit;
        private readonly PrefetchCountSetting _prefetchCount;

        private readonly IZombusLogger _logger;
        private MessageReceiver _messageReceiver;
        private IMessageDispatcher _messageDispatcher;

        public OnReceiveMessageReceiver(IQueueManager queueManager, string queuePath,
            ConcurrentHandlerLimitSetting concurrentHandlerLimit, PrefetchCountSetting prefetchCount, IZombusLogger logger)
        {
            _queueManager = queueManager;
            _queuePath = queuePath;
            _concurrentHandlerLimit = concurrentHandlerLimit;
            _prefetchCount = prefetchCount;
            _logger = logger;
        }

        public override string ToString()
        {
            return _queuePath;
        }
        
        public async Task SubscribeToQueue()
        {
            if (_messageDispatcher == null) throw new Exception("No dispatcher registered");

            var options = new OnMessageOptions {MaxConcurrentCalls = _concurrentHandlerLimit};
            var receiver = await GetMessageReceiver();
          
            receiver.OnMessageAsync(async (message) =>
            {
                try
                {
                    await _messageDispatcher.DispatchAsync(message);
                   // await message.CompleteAsync();
                }
                catch (Exception e)
                {
                    message.Abandon();
                    _logger.Error(e, "OnReceiveMessageReceiver Error handling message {0}. Exception: {1}", message.MessageId, e.Message);
                }

            }, options);
        }

        //this is here for now, should be passed in ctor or GetMessageReceiver
        public void RegisterDispatcher(IMessageDispatcher dispatcher)
        {
            _messageDispatcher = dispatcher;
        }

        private async Task<MessageReceiver> GetMessageReceiver()
        {
            if (_messageReceiver != null) return _messageReceiver;

            _messageReceiver = await _queueManager.CreateMessageReceiver(_queuePath);
            _messageReceiver.PrefetchCount = _prefetchCount;
       
            return _messageReceiver;
        }

        private void DiscardMessageReceiver()
        {
            var messageReceiver = _messageReceiver;
            _messageReceiver = null;

            if (messageReceiver == null) return;
            if (messageReceiver.IsClosed) return;

            messageReceiver.Close();
        }
    

        public void Dispose()
        {
            try
            {
                DiscardMessageReceiver();
            }
            catch (MessagingEntityNotFoundException)
            {
            }
            catch (ObjectDisposedException)
            {
            }
        }
    }
}