using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Infrastructure;
using Infrastructure.Const;
using Infrastructure.Extensions;
using Microsoft.Extensions.Logging;
using OpenAuth.App.Base;
using OpenAuth.App.BaseApp.Base;
using OpenAuth.App.Extensions;
using OpenAuth.App.Interface;
using OpenAuth.App.Request;
using OpenAuth.App.Response;
using OpenAuth.Repository;
using OpenAuth.Repository.Domain;
using Quartz;
using SqlSugar;

namespace OpenAuth.App
{
    /// <summary>
    /// 系统定时任务管理
    /// </summary>
    public class OpenJobApp : SqlSugarBaseApp<SysOpenJob, SugarDbContext>
    {
        private SysLogApp _sysLogApp;
        private IScheduler _scheduler;
        private ILogger<OpenJobApp> _logger;

        public OpenJobApp(
           ISugarUnitOfWork<SugarDbContext> unitWork,
           ISimpleClient<SysOpenJob> repository,
           IAuth auth,
           SysLogApp sysLogApp,
           IScheduler scheduler,
           ILogger<OpenJobApp> logger) : base(unitWork, repository, auth)
        {
            _sysLogApp = sysLogApp;
            _scheduler = scheduler;
            _logger = logger;
        }

        /// <summary>
        /// 加载列表
        /// </summary>
        public async Task<TableData> Load(QueryOpenJobListReq request)
        {
            int totalCount = 0;
            var result = new TableData();
            var objs = Repository.AsQueryable()
                .WhereIF(!string.IsNullOrEmpty(request.key), u => u.JobName.Contains(request.key));

            result.data = await objs.OrderBy(u => u.Id).ToPageListAsync(request.page, request.limit, totalCount);
            result.count = totalCount;

            return result;
        }

        /// <summary>
        /// 启动所有状态为正在运行的任务
        /// <para>通常应用在系统加载的时候</para>
        /// </summary>
        /// <returns></returns>
        public async Task StartAll()
        {
            var jobs = await Repository.GetListAsync(u => u.Status == (int)JobStatus.Running);
            foreach (var job in jobs)
            {
                job.Start(_scheduler);
            }
            _logger.LogInformation("所有状态为正在运行的任务已启动");
        }

        public void Add(AddOrUpdateOpenJobReq req)
        {
            var obj = req.MapTo<SysOpenJob>();
            obj.Id = Guid.NewGuid().ToString();
            obj.CreateTime = DateTime.Now;
            var user = _auth.GetCurrentUser().User;
            obj.CreateUserId = user.Id.ToString();
            obj.CreateUserName = user.Name;
            Repository.Insert(obj);
        }

        public void AddStart(AddOrUpdateOpenJobReq req)
        {
            var obj = req.MapTo<SysOpenJob>();
            obj.Id = Guid.NewGuid().ToString();
            obj.CreateTime = DateTime.Now;
            obj.CreateUserId = "-1";
            obj.CreateUserName = "System";
            var flag=Repository.Insert(obj);
            if (flag == true)
            {
                var job =  Repository.GetFirst(r=>r.Id==obj.Id);
                job.Start(_scheduler);
            }
        }

        public void Update(AddOrUpdateOpenJobReq obj)
        {
            var user = _auth.GetCurrentUser().User;
            base.Repository.Update(u => new SysOpenJob
            {
                JobName = obj.JobName,
                JobType = obj.JobType,
                JobCall = obj.JobCall,
                JobCallParams = obj.JobCallParams,
                Cron = obj.Cron,
                Status = obj.Status,
                Remark = obj.Remark,
                UpdateTime = DateTime.Now,
                UpdateUserId = user.Id.ToString(),
                UpdateUserName = user.Name
            }, u => u.Id == obj.Id);
        }

        #region 定时任务运行相关操作

        /// <summary>
        /// 返回系统的job接口
        /// </summary>
        /// <returns></returns>
        public List<string> QueryLocalHandlers()
        {
            var types = AppDomain.CurrentDomain.GetAssemblies()
                .SelectMany(a => a.GetTypes().Where(t => t.GetInterfaces()
                    .Contains(typeof(IJob))))
                .ToArray();
            return types.Select(u => u.FullName).ToList();
        }

        public void ChangeJobStatus(ChangeJobStatusReq req)
        {
            var job = Repository.GetFirst(u => u.Id == req.Id);
            if (job == null)
            {
                throw new Exception("任务不存在");
            }


            if (req.Status == (int)JobStatus.NotRun) //停止
            {
                job.Stop(_scheduler);
            }
            else //启动
            {
                job.Start(_scheduler);
            }


            var user = _auth.GetCurrentUser().User;

            job.Status = req.Status;
            job.UpdateTime = DateTime.Now;
            job.UpdateUserId = user.Id.ToString();
            job.UpdateUserName = user.Name;
            Repository.Update(job);
        }

        public void ChangeJobStatus1(ChangeJobStatusReq req)
        {
            var job = Repository.GetFirst(u => u.Id == req.Id);
            if (job == null)
            {
                throw new Exception("任务不存在");
            }


            if (req.Status == (int)JobStatus.NotRun) //停止
            {
                job.Stop(_scheduler);
            }
            else //启动
            {
                job.Start(_scheduler);
            }

            job.Status = req.Status;
            job.UpdateTime = DateTime.Now;
            job.UpdateUserId = "-1";
            job.UpdateUserName = "System";
            Repository.Update(job);
        }
        /// <summary>
        /// 记录任务运行结果
        /// </summary>
        /// <param name="jobId"></param>
        public void RecordRun(string jobId)
        {
            var job = Repository.GetFirst(u => u.Id == jobId);
            if (job == null)
            {
                _sysLogApp.Add(new SysLog
                {
                    TypeName = "定时任务",
                    TypeId = "AUTOJOB",
                    Content = $"未能找到定时任务：{jobId}"
                });
                return;
            }

            job.RunCount++;
            job.LastRunTime = DateTime.Now;
            Repository.Update(job);

            _sysLogApp.Add(new SysLog
            {
                CreateName = "Quartz",
                CreateId = -1,
                TypeName = "定时任务",
                TypeId = "AUTOJOB",
                Content = $"运行了自动任务：{job.JobName}"
            });
            _logger.LogInformation($"运行了自动任务：{job.JobName}");
        }

        /// <summary>
        /// 按id批量删除
        /// </summary>
        /// <param name="ids"></param>
        public virtual void Delete(string[] ids)
        {
            Repository.Delete(u => ids.Contains(u.Id));
        }

        public  void DeleteEntity(SysOpenJob job)
        {
            Repository.Delete(job);
            JobKey jbk = new JobKey(job.Id);

            _scheduler.DeleteJob(jbk);
        }
        public SysOpenJob Get(string id)
        {
            return Repository.GetFirst(u => u.Id == id);
        }
        #endregion
    }
}