using qdr.fnd.core.pqueue.Storages;
using Quadarax.Foundation.Core.Data;

namespace qdr.fnd.core.pqueue.Configuration
{
    /// <summary>
    /// Main PSQueue configuration object.
    /// </summary>
    public class PsQueueConfiguration
    {
        #region *** Properties ***
        /// <summary>
        /// Unique name of the queue, locally based on the application.
        /// </summary>
        public string QueueName { get; set; }
        /// <summary>
        /// Declare storage configuration for the queue.
        /// </summary>
        public PsQueueStorageConfiguration Storage { get; set; }
        /// <summary>
        /// Maximum number of concurrent processes that can be executed at once (How many threads uses).
        /// </summary>
        public int MaxConcurrentProcesses { get; set; }
        /// <summary>
        /// Defines the interval to check the queue for new items to process. If not specified, uses continuous strategy
        /// </summary>
        public TimeSpan? CycleInterval { get; set; }
        /// <summary>
        /// Default initial attempts for the queue items if not defined.
        /// </summary>
        public int? DefaultInitialAttempts { get; set; }
        /// <summary>
        /// Default process (one attempt) timeout for the queue items.
        /// </summary>
        public TimeSpan DefaultProcessTimeout { get; set; }
        /// <summary>
        /// Default attempt to postpone for the queue items when attempt failed. If not specified new attempt will be executed instantly
        /// </summary>
        public TimeSpan? DefaultAttemptPostpone { get; set; }
        /// <summary>
        /// Defines retention configuration for the queue.
        /// </summary>
        public PsQueueRetentionConfiguration? Retention { get; set; }
        #endregion

        #region *** Constructors ***

        public PsQueueConfiguration() : this(string.Empty)
        {
        }
        public PsQueueConfiguration(string queueName)
        {
            QueueName = queueName;
            Storage = new PsQueueStorageConfiguration();
        }
        #endregion

        #region *** Operations ***

        /// <summary>
        /// Create default configuration for the queue.
        /// </summary>
        /// <param name="queueName">Local unique queue name.</param>
        /// <returns></returns>
        public static PsQueueConfiguration Default(string queueName)
        {
            var config = new PsQueueConfiguration(queueName)
            {
                MaxConcurrentProcesses = 4,
                CycleInterval = TimeSpan.FromSeconds(10),
                DefaultInitialAttempts = 3,
                DefaultProcessTimeout = TimeSpan.FromSeconds(30),
                DefaultAttemptPostpone = TimeSpan.FromSeconds(30)
            };

            var storageProviderClass = typeof(MemoryStorageProvider).FullName;
            if (storageProviderClass != null)
                config.Storage.ProviderClass = storageProviderClass;

            config.Retention = new PsQueueRetentionConfiguration
            {
                Enabled = true,
                RetentionDoneOlder = TimeSpan.FromDays(7),
                RetentionDoneMaxCount = 1000,
                RetentionFailedOlder = TimeSpan.FromDays(7),
                RetentionFailedMaxCount = 1000
            };
            return config;
        }
        #endregion
    }

    /// <summary>
    /// Storage configuration for the queue.
    /// </summary>
    public class PsQueueStorageConfiguration
    {
        /// <summary>
        /// Qualified class name of the storage provider.
        /// </summary>
        public string ProviderClass { get; set; } = string.Empty;
        /// <summary>
        /// Storage source (path or connection string).
        /// </summary>
        public string Source { get; set; } = string.Empty;
        /// <summary>
        /// User identity for the storage provider or impersonation account.
        /// </summary>
        public string? UserName { get; set; }
        /// <summary>
        /// User password hashed by concat <see cref="PsQueueConfiguration.QueueName"/> and <see cref="UserName"/>.
        /// </summary>
        public string? UserPasswordHashed { get; set; }
        /// <summary>
        /// Provider specific configuration.
        /// </summary>
        public IList<TypedArgument>? Arguments { get; set; }
        
    }

    /// <summary>
    /// Retention configuration for the queue.
    /// </summary>
    public class PsQueueRetentionConfiguration
    {
        /// <summary>
        /// Flag to enable retention configuration.
        /// </summary>
        public bool Enabled { get; set; }
        /// <summary>
        /// Maximum time to keep the queue item that are Done in the queue.
        /// </summary>
        public TimeSpan? RetentionDoneOlder { get; set; }
        /// <summary>
        /// Maximum queue items that are Done in the queue.
        /// </summary>
        public int? RetentionDoneMaxCount { get; set; }
        /// <summary>
        /// Maximum time to keep the queue item that are Failed in the queue.
        /// </summary>
        public TimeSpan? RetentionFailedOlder { get; set; }
        /// <summary>
        /// Maximum queue items that are Failed in the queue.
        /// </summary>
        public int? RetentionFailedMaxCount { get; set; }
    }

}
