using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SFI.COMM.LIB.Redis
{
    public class RedisChannel : IDisposable
    {
        public string Host { get; set; }
        public int Port { get; set; }
        public string Password { get; set; }
        public string ClientToken { get; set; }
        public string ChannelToken { get; set; }
        public bool IsChannelActive { get; set; }

        public Action<string> IncomingAction { get; set; }


        public RedisChannel(string host, int port, string password, string clientToken, string channelToken, Action<string> incomingAction)
        {
            this.Host = host;
            this.Port = port;
            this.Password = password;
            this.ClientToken = clientToken;
            this.ChannelToken = channelToken;
            this.IncomingAction = incomingAction;
        }








        public RedisSub ChannelSub { get; set; }
        public Redis _Redis { get; set; }
        public Redis Redis
        {
            get
            {
                if (this._Redis == null)
                    this._Redis = new Redis(this.Host, this.Port, this.Password);

                return _Redis;
            }
        }




        public RedisSub PublisherChannelSub { get; set; }
        public Redis _PublisherRedis { get; set; }
        public Redis PublisherRedis
        {
            get
            {
                if (this._PublisherRedis == null)
                    this._PublisherRedis = new Redis(this.Host, this.Port, this.Password);

                return _PublisherRedis;
            }
        }





        public void Start()
        {
            if (this.ChannelSub != null)
                this.ChannelSub.Dispose();

            this.ChannelSub = new RedisSub(this.Redis.Host, this.Redis.Port, this.Redis.Password);
            this.ChannelSub.MessageReceived += (s, e) =>
            {
                try
                {
                    this.IsChannelActive = true;

                    if (this.IncomingAction != null)
                        _ = Task.Run(() => this.IncomingAction(e.message.ToString()));
                }
                catch (Exception ex)
                {

                }
            };
            this.ChannelSub.SubscribeReceived += (s, e) =>
            {
                this.IsChannelActive = true;
            };
            this.ChannelSub.UnsubscribeReceived += (s, e) =>
            {
                this.IsChannelActive = false;
            };
            this.ChannelSub.SendSubCommandFree("client", "setname", "subscriber-" + this.ClientToken);
            this.ChannelSub.Subscribe(this.ChannelToken);


            this.StartPublisher();
        }


        public void StartPublisher()
        {
            if (this.PublisherChannelSub != null)
                this.PublisherChannelSub.Dispose();

            this.PublisherChannelSub = new RedisSub(this.Redis.Host, this.Redis.Port, this.Redis.Password);
            this.PublisherChannelSub.SendSubCommandFree("client", "setname", "publisher-" + this.ClientToken);
        }


        public void SendData(object objectData)
        {
            this.SendData(JsonConvert.SerializeObject(objectData));
        }

        public void SendData(string channelName, object objectData)
        {
            this.SendData(channelName, JsonConvert.SerializeObject(objectData));
        }


        public void SendData(string jsonData)
        {
            this.PublisherChannelSub.SendCommand("PUBLISH", $@"{this.ChannelToken}", $@"{jsonData}");
        }

        public void SendData(string channelName, string jsonData)
        {
            this.PublisherChannelSub.SendCommand("PUBLISH", $@"{channelName}", $@"{jsonData}");
        }

        public void Stop()
        {
            try
            {
                this.ChannelSub.Dispose();
            }
            catch (Exception ex) { }

            try
            {
                this.PublisherChannelSub.Dispose();
            }
            catch (Exception ex) { }
        }

        public void Dispose()
        {
            try
            {
                if (this.ChannelSub != null)
                    this.ChannelSub.Dispose();
            }
            catch (Exception exc) { }

            try
            {
                if (this._Redis != null)
                    this._Redis.Dispose();
            }
            catch (Exception exc) { }

            try
            {
                if (this.PublisherChannelSub != null)
                    this.PublisherChannelSub.Dispose();
            }
            catch (Exception exc) { }

            try
            {
                if (this._PublisherRedis != null)
                    this._PublisherRedis.Dispose();
            }
            catch (Exception exc) { }

            try
            {
                GC.SuppressFinalize(this);
            }
            catch (Exception exc) { }
        }
    }
}
