using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using System.Threading;

namespace Apewer
{

    /// <summary>Cron 特性,默认间隔为 60000 毫秒。</summary>
    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
    public sealed class CronAttribute : Attribute
    {

        internal const int DefaultInterval = 60000;

        private int _interval;

        /// <summary>两次 Cron 执行的间隔毫秒数。</summary>
        public int Interval { get { return _interval; } }

        /// <summary>创建 Cron 特性,可指定两次 Cron 执行的间隔毫秒数。</summary>
        public CronAttribute(int interval = DefaultInterval) { _interval = interval; }

        #region Payload

        // 传入。
        Type _type = null;
        Logger _logger = null;

        // 实时。
        Thread _thread = null;
        bool _alive = false;

        void Run()
        {
            _alive = true;
            _thread = new Thread(Payload);
            _thread.IsBackground = false;
            _thread.Start();
        }

        void Payload()
        {
            var moment = 500;
            var delay = 0;
            var sender = $"Cron-{_type.Name}";
            while (true)
            {
                if (_break) break;
                if (delay <= 0)
                {
                    delay = _interval;
                    _logger.Text(sender, "Beginning");
                    try
                    {
                        var instance = Activator.CreateInstance(_type);
                        RuntimeUtility.Dispose(instance);
                        _logger.Text(sender, "Ended");
                    }
                    catch (Exception ex)
                    {
                        _logger.Exception(sender, ex);
                    }
                }
                else
                {
                    Thread.Sleep(moment);
                    delay = delay - moment;
                }
            }
            _alive = false;
        }

        #endregion

        #region CronInvoker

        static object _start = new object();
        static CronAttribute[] _crons = null;
        static bool _break = false;

        static CronAttribute[] Init(IEnumerable<Assembly> assemblies = null, Logger logger = null)
        {
            var attributes = new List<CronAttribute>();
            var added = new List<string>();
            if (assemblies == null) assemblies = AppDomain.CurrentDomain.GetAssemblies();
            foreach (var assembly in assemblies)
            {
                var types = assembly.GetTypes();
                foreach (var type in types)
                {
                    var attribute = RuntimeUtility.GetAttribute<CronAttribute>(type);
                    if (attribute == null) continue;
                    if (added.Contains(type.FullName)) continue;
                    if (!RuntimeUtility.CanNew(type)) continue;
                    attribute._type = type;
                    attribute._logger = logger;
                    attributes.Add(attribute);
                }
            }
            return attributes.ToArray();
        }

        /// <summary>开始 Cron 调用(阻塞当前线程)。</summary>
        /// <remarks>
        /// 参数<br />
        /// - assemblies: 包含 Cron 的程序集,不指定此参数时将在 AppDomain 中搜索;<br />
        /// - logger: 日志记录程序,不指定此参数时将使用 Logger.Default。<br />
        /// </remarks>
        public static void Start(IEnumerable<Assembly> assemblies = null, Logger logger = null)
        {
            if (logger == null) logger = Logger.Default;
            lock (_start)
            {
                // 初始化。
                _crons = Init(assemblies, logger);
                if (_crons.Length < 1)
                {
                    logger.Error(nameof(CronAttribute), "没有找到带有 Cron 特性的类型。");
                    return;
                }

                // 启动线程。
                Console.CancelKeyPress += (s, e) =>
                {
                    _break = true;
                    e.Cancel = true;
                };
                logger.Text(nameof(CronAttribute), $"启动 {_crons.Length} 个 Cron 线程。");
                foreach (var cron in _crons) cron.Run();

                // 监视退出状态。
                while (true)
                {
                    Thread.Sleep(300);
                    var alive = 0;
                    for (var i = 0; i < _crons.Length; i++) if (_crons[i]._alive) alive += 1;
                    if (alive < 1) break;
                }
                logger.Text(nameof(CronAttribute), "所有 Cron 已结束。");
            }
        }

        /// <summary>打断 Cron 循环,不打断正在执行的 Cron。</summary>
        public static void Break()
        {
            _break = true;
        }

        #endregion

    }

}