﻿using Grpc.Core;
using Microsoft.Extensions.Logging;
using System;

namespace Wicture.DbRESTFul.Rpc.Client
{
    public class RpcChannel
    {
        private object locker = new object();
        private Channel channel;
        public RpcClientConfig Config { get; private set; }

        public RpcChannel(RpcClientConfig config)
        {
            Config = config;
        }

        public Channel GetOrOpen()
        {
            if (!Healthy)
            {
                try
                {
                    lock (locker)
                    {
                        if (!Healthy)
                        {
                            channel?.ShutdownAsync().Wait();
                            channel = null;
                        }

                        if (channel == null)
                        {
                            LoggerManager.Logger.LogInformation($"New RPC channel was created for service : `{Config.ServiceName}` with `{Config.ServerAddress}`");
                            channel = new Channel(Config.ServerAddress, ChannelCredentials.Insecure);
                        }
                    }
                }
                catch (Exception ex)
                {
                    channel?.ShutdownAsync().Wait();
                    channel = null;
                    LoggerManager.Logger.LogError(ex, $"Failed to get available channel for service : `{Config.ServiceName}` with `{Config.ServerAddress}`");
                    throw ex;
                }
            }

            return channel;
        }

        public bool Healthy { get { return !(channel == null || channel.State == ChannelState.Shutdown || channel.State == ChannelState.TransientFailure); } }

        public void Close()
        {
            lock (locker)
            {
                if (channel == null) return;

                if (channel.State != ChannelState.Shutdown || channel.State == ChannelState.TransientFailure)
                {
                    try
                    {
                        channel.ShutdownAsync().Wait();
                    }
                    catch (Exception ex)
                    {
                        LoggerManager.Logger.LogError(ex, $"Failed to shutdown channel for service : `{Config.ServiceName}` with `{Config.ServerAddress}`");
                    }
                }

                channel = null;
            }
        }
    }
}
