using StackExchange.Redis;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;

namespace IOB_UT_NEXT
{
    /// <summary>
    /// Classe gestione code, a seconda della conf come LIST redis o come concurrent queue in memoria
    /// </summary>
    public class DataQueue : IDisposable
    {
        #region Public Fields

        public long Count { get; set; } = 0;

        #endregion Public Fields

        #region Public Constructors

        public DataQueue(string codIOB, string qName, bool useRedis, RedisIobCache redisCacheMan)
        {
            UseRedis = useRedis;
            CodIOB = codIOB;
            QueueName = qName;
            if (UseRedis)
            {
                redisMan = redisCacheMan;
                KeyName = redisMan.redHash($"IOB:QUEUE:{CodIOB}:{QueueName}");
            }
        }

        #endregion Public Constructors

        #region Public Methods

        public void Dispose()
        {
            redisMan = null;
            KeyName = "";
        }

        /// <summary>
        /// Accodamento elemento
        /// </summary>
        /// <param name="item"></param>
        public void Enqueue(string item)
        {
            if (UseRedis)
            {
                Count = redisMan.redQueuePush(KeyName, item);
            }
            else
            {
                MemQueue.Enqueue(item);
                Count = MemQueue.Count;
            }
        }

        /// <summary>
        /// Lista string degli elementi in coda, svuotando la coda
        /// </summary>
        /// <returns></returns>
        public List<string> ToList()
        {
            List<string> answ = new List<string>();
            if (UseRedis)
            {
                // recupero in blocco...
                answ = redisMan.redQueuePopAll(KeyName)
                                    .Select(x => $"{x}")
                                    .ToList();
            }
            else
            {
                answ = MemQueue.ToList();
                Count = MemQueue.Count;
            }
            return answ;
        }

        /// <summary>
        /// Recupera 1 record dalla coda...
        /// </summary>
        /// <param name="result"></param>
        /// <returns></returns>
        public bool TryDequeue(out string result)
        {
            bool fatto = false;
            if (UseRedis)
            {
                result = redisMan.redQueuePop(KeyName);
                Count = (int)redisMan.redQueueCount(KeyName);
                fatto = true;
            }
            else
            {
                fatto = MemQueue.TryDequeue(out result);
                Count = MemQueue.Count;
            }
            return fatto;
        }

        #endregion Public Methods

        #region Private Fields

        private string CodIOB = "NA";

        private RedisKey KeyName = "NA";

        /// <summary>
        /// Coda modalità memoria locale
        /// </summary>
        private ConcurrentQueue<string> MemQueue = new ConcurrentQueue<string>();

        private string QueueName = "NA";

        /// <summary>
        /// Oggetto connessione REDIS
        /// </summary>
        private RedisIobCache redisMan;

        /// <summary>
        /// Indica se usare redis come datastore vs memoria
        /// </summary>
        private bool UseRedis = false;

        #endregion Private Fields
    }
}