﻿// Copyright (c) Microsoft.  All rights reserved. 
// Licensed under the MIT license.  See LICENSE file in the project root for full license information. 

using System;
using System. Collections. Generic;
using System. Threading. Tasks;
using Microsoft. Azure. Devices. Shared;
using Microsoft. Azure. Devices. Client. Transport. AmqpIoT;

namespace Microsoft. Azure. Devices. Client. Transport. Amqp
{
    internal class AmqpUnitManager : IAmqpUnitManager
    {
        private static readonly AmqpUnitManager s_instance = new AmqpUnitManager();

        private IDictionary<string, IAmqpUnitManager> _amqpConnectionPools;
        private readonly object _lock = new object();

        internal AmqpUnitManager()
        {
            _amqpConnectionPools = new Dictionary<string, IAmqpUnitManager>();
        }

        internal static AmqpUnitManager GetInstance()
        {
            return s_instance;
        }

        public AmqpUnit CreateAmqpUnit(
            DeviceIdentity deviceIdentity,
            Func<MethodRequestInternal, Task> methodHandler,
            Action<Twin, string, TwinCollection> twinMessageListener,
            Func<string, Message, Task> eventListener,
            Action onUnitDisconnected)
        {
            IAmqpUnitManager amqpConnectionPool = ResolveConnectionPool(deviceIdentity. IotHubConnectionString. HostName);
            return amqpConnectionPool. CreateAmqpUnit(
                deviceIdentity,
                methodHandler,
                twinMessageListener,
                eventListener,
                onUnitDisconnected);
        }

        public void RemoveAmqpUnit(AmqpUnit amqpUnit)
        {
            amqpUnit. Dispose();
            IAmqpUnitManager amqpConnectionPool = ResolveConnectionPool(amqpUnit. GetDeviceIdentity().IotHubConnectionString. HostName);
            amqpConnectionPool. RemoveAmqpUnit(amqpUnit);
        }

        private IAmqpUnitManager ResolveConnectionPool(string host)
        {
            lock (_lock)
            {
                _amqpConnectionPools. TryGetValue(host, out IAmqpUnitManager amqpConnectionPool);
                if (amqpConnectionPool == null)
                {
                    amqpConnectionPool = new AmqpConnectionPool();
                    _amqpConnectionPools. Add(host, amqpConnectionPool);
                }

                if (Logging. IsEnabled) Logging. Associate(this, amqpConnectionPool, $"{nameof(ResolveConnectionPool)}");
                return amqpConnectionPool;
            }
        }
    }
}
