using Microsoft.Extensions.Hosting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Wicture.DbRESTFul;
using Wicture.DbRESTFul.Configuration;

namespace JiaZhiQuan
{
    public abstract class AbstractControlledScheduleService : IHostedService, IDisposable
    {
        public int Interval { get; set; }
        public Timer TickTimer { get; private set; }
        public string Name { get; private set; }
        public bool RunImmediately { get; private set; }

        public readonly static Dictionary<string, string> RunStates = new Dictionary<string, string>();

        /// <summary>
        /// 是否忽略appsettings.json中的启用配置（DisabledSchedules/EnabledSchedules）
        /// </summary>
        public bool IgnoreStateConfig { get; set; } = false;

        /// <summary>
        /// ScheduleService基类，默认服务会立即启动
        /// </summary>
        /// <param name="timerInterval">间隔时间：1000 = 1秒</param>
        public AbstractControlledScheduleService(int timerInterval, bool runImmediately = true)
        {
            Name = GetType().Name;
            Interval = timerInterval;
            RunImmediately = runImmediately;

            if (RunStates.ContainsKey(Name))
            {
                RunStates[Name] = "Created";
            }
            else
            {
                RunStates.Add(Name, "Created");
            }
        }

        /// <summary>
        /// 返回 false 时，此次不执行
        /// </summary>
        public virtual bool BeforeRun()
        {
            return true;
        }

        public abstract Task Run();

        private async void TimerRun(object state)
        {
            if (BeforeRun())
            {
                try
                {
                    var stime = DateTime.Now;

                    RunStates[Name] = "Running";
                    await Run();
                    RunStates[Name] = "Completed";

                    var t = (DateTime.Now - stime).TotalSeconds;
                    // 如果大于1秒的任务，则Log记录
                    if (t > 1)
                    {
                        LoggerManager.Logger.Info($"{Name}执行时间：${t.ToString("0.###")}s");
                    }
                }
                catch (Exception ex)
                {
                    LoggerManager.Logger.Error(ex, Name + "执行出错\r\n" + ex.Message);
                    RunStates[Name] = "Error";
                }
            }
            
            TickTimer.Change(Interval, Timeout.Infinite);
        }

        public async Task StartAsync(CancellationToken cancellationToken)
        {
            if (!IgnoreStateConfig)
            {
                // 判断是否要执行
                string disabledSchedules;
                var rst = ConfigurationManager.Settings.Variables.TryGetValue("DisabledSchedules", out disabledSchedules);
                if (rst)
                {
                    if (disabledSchedules.Split(',').Contains(Name))
                    {
                        LoggerManager.Logger.Error($"ScheduleService【{GetType().Name}】被禁用");
                        await Task.CompletedTask;
                        RunStates[Name] = "Stopped";
                        return;
                    }
                }
                string enabledSchedules;
                rst = ConfigurationManager.Settings.Variables.TryGetValue("EnabledSchedules", out enabledSchedules);
                if (rst && !string.IsNullOrEmpty(enabledSchedules))
                {
                    if (!enabledSchedules.Split(',').Contains(Name))
                    {
                        LoggerManager.Logger.Error($"ScheduleService【{GetType().Name}】被禁用");
                        await Task.CompletedTask;
                        RunStates[Name] = "Stopped";
                        return;
                    }
                }
            }
            LoggerManager.Logger.Info($"ScheduleService【{GetType().Name}】已启动");
            TickTimer = new Timer(TimerRun, null, RunImmediately ? 0 : Interval, Timeout.Infinite);
            RunStates[Name] = "Started";
            await Task.CompletedTask;
        }

        public async Task StopAsync(CancellationToken stoppingToken)
        {
            LoggerManager.Logger.Info($"ScheduleService【{GetType().Name}】已停止");
            TickTimer?.Change(Timeout.Infinite, 0);
            await Task.CompletedTask;
        }

        public void Dispose()
        {
            RunStates[Name] = "Stopped";
            TickTimer?.Dispose();
            TickTimer = null;
            GC.SuppressFinalize(this);
        }
    }
}
