using Microsoft.Extensions.Logging;
using Repository.BackendRepository.Implement;
using Repository.BackendRepository.Interface;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Threading.Tasks;
using NCrontab;
using static NCrontab.CrontabSchedule;

namespace BackendWorkerService.Quartz
{
    /// <summary>
    /// Job調度中間對象
    /// </summary>
    public class JobSchedule
    {
        public JobSchedule(Type jobType, string cronExpression)
        {
            this.JobType = jobType ?? throw new ArgumentNullException(nameof(jobType));
            CronExpression = cronExpression ?? throw new ArgumentNullException(nameof(cronExpression));
        }
        /// <summary>
        /// Job類型
        /// </summary>
        public Type JobType { get; private set; }
        /// <summary>
        /// Cron表達式
        /// </summary>
        public string CronExpression { get; private set; }
        /// <summary>
        /// Job狀態
        /// </summary>
        public JobStatus JobStatu { get; set; } = JobStatus.Init;
    }
    /// <summary>
    /// Job運行狀態
    /// </summary>
    public enum JobStatus : byte
    {
        [Description("初始化")]
        Init = 0,
        [Description("運行中")]
        Running = 1,
        [Description("調度中")]
        Scheduling = 2,
        [Description("已停止")]
        Stopped = 3,
    }

    public class Task_Detail
    {
        private readonly IBackendRepository backendRepository;
        private readonly ILogger<Task_Detail> logger;
        public Task_Detail(ILogger<Task_Detail> logger, IBackendRepository backendRepository)
        {
            this.logger = logger;
            this.backendRepository = backendRepository;
        }
        /// <summary>
        /// 取得時間規則
        /// </summary>
        /// <param name="task"></param>
        /// <param name="task_item"></param>
        /// <returns></returns>
        private async Task<string> GetWorkRule(string task,string task_item)
        {
            string Times = null;
            try
            {
                var sql = $@"select b.system_value from task_detail a
                                join variable b on a.variable_id = b.id
                                where a.task = '{task}' and a.task_item = '{task_item}'";
                Times = await backendRepository.GetOneAsync<string>(sql);
            }
            catch(Exception exception)
            {
                logger.LogError("【Task_Detail】【任務時間獲取失敗】");
                logger.LogError("【Task_Detail】【任務時間獲取失敗】[Exception]:{0},Task:{1},task_item:{2}", exception.ToString(),task,task_item);
            }
            return Times;
        }
        /// <summary>
        /// 是否執行任務
        /// </summary>
        /// <param name="task"></param>
        /// <param name="task_item"></param>
        /// <returns></returns>
        public async Task<bool> GetNeedWorkTask(string task, string task_item)
        {
            try
            {
                var sql = $@"select a.lastwork_time from task_detail a
                            where a.task = '{task}' and a.task_item = '{task_item}'";

                var lastworkTime = await backendRepository.GetOneAsync<string>(sql);



                DateTime dateTime = lastworkTime != null ? Convert.ToDateTime(lastworkTime) : Convert.ToDateTime("1970-01-01 00:00:01");

                var nextTime = CrontabSchedule.Parse(await GetWorkRule(task, task_item), new ParseOptions { IncludingSeconds = true } ).GetNextOccurrence(dateTime);
                if (DateTime.Now >= nextTime)
                {
                    return true;
                }
            }
            catch(Exception exception)
            {
                logger.LogError("【Task_Detail】【時間解析失敗】[Exception]:{0},Task:{1},task_item:{2}", exception.ToString(), task, task_item);
            }
            return false;
        }
        /// <summary>
        /// 紀錄任務開始執行時間
        /// </summary>
        /// <param name="task"></param>
        /// <param name="task_item"></param>
        /// <returns></returns>
        public async Task InsertWorkTime(string task, string task_item ,string LoggerWord = null)
        {
            try
            {
                Dictionary<string, object> worktime = new Dictionary<string, object>()
                {
                    { "@lastwork_time", DateTime.Now},
                    { "@success", 2},
                    { "@updated_at", DateTime.Now},
                };
                await backendRepository.UpdateOneByCustomTable(worktime, "task_detail", $" task = '{task}' and task_item = '{task_item}'");

                if(LoggerWord == null)
                {
                    logger.LogInformation($"【Task_Detail】【開始{task},{task_item}任務】");
                }
                logger.LogInformation($"【Task_Detail】【{LoggerWord}】");
            }
            catch (Exception exception)
            {
                logger.LogError("【Task_Detail】【任務輸入開始時間】[Exception]:{0},Task:{1},task_item:{2}", exception.ToString(), task, task_item);
            }
        }
        /// <summary>
        /// 紀錄任務結束時間
        /// </summary>
        /// <param name="task"></param>
        /// <param name="task_item"></param>
        /// <returns></returns>
        public async Task InsertWorkTime_End(string task, string task_item,string LoggerWord = null)
        {
            try
            {
                Dictionary<string, object> worktime = new Dictionary<string, object>()
                {
                    { "@success", 0},
                    { "@lastwork_end_time", DateTime.Now},
                    { "@updated_at", DateTime.Now},
                };
                await backendRepository.UpdateOneByCustomTable(worktime, "task_detail", $" task = '{task}' and task_item = '{task_item}'");
                if (LoggerWord == null)
                {
                    logger.LogInformation($"【Task_Detail】【結束{task},{task_item}任務】");
                }
                logger.LogInformation($"【Task_Detail】【{LoggerWord}】");
            }
            catch (Exception exception)
            {
                logger.LogError("【Task_Detail】【任務輸入結束時間】[Exception]:{0},Task:{1},task_item:{2}", exception.ToString(), task, task_item);
            }
        }
        /// <summary>
        /// 執行失敗紀錄
        /// </summary>
        /// <param name="task"></param>
        /// <param name="task_item"></param>
        /// <returns></returns>
        public async Task WorkFail(string task, string task_item,string reason = "")
        {
            try
            {
                Dictionary<string, object> worktime = new Dictionary<string, object>()
                {
                    { "@success", 1},
                    { "@updated_at", DateTime.Now},
                };
                await backendRepository.UpdateOneByCustomTable(worktime, "task_detail", $" task = '{task}' and task_item = '{task_item}'");
                logger.LogError("【Task_Detail】【任務執行失敗】[Exception]:{0},Task:{1},task_item:{2}", reason, task, task_item);
            }
            catch (Exception exception)
            {
                logger.LogError("【Task_Detail】【任務執行失敗】[Exception]:{0},Task:{1},task_item:{2}", exception.ToString(), task, task_item);
            }
        }

    }

}