using Hotline.Ai.Quality;
using Hotline.Application.CallCenter;
using Hotline.Caching.Interfaces;
using Hotline.CallCenter.Calls;
using Hotline.CallCenter.Configs;
using Hotline.EventBus;
using Hotline.FlowEngine.Notifications;
using Hotline.Orders;
using Hotline.Quality;
using Hotline.Settings;
using Hotline.Share.Dtos.Quality;
using Hotline.Share.Enums.Quality;
using MapsterMapper;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using StackExchange.Redis;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Unicode;
using Hotline.Quality.Notifications;
using XF.Domain.Authentications;
using XF.Domain.Constants;
using XF.Domain.Dependency;
using XF.Domain.Exceptions;
using XF.Domain.Repository;
using Hotline.Share.Enums.CallCenter;
using Hotline.Configurations;
using Hotline.Tools;
using Hotline.Share.Dtos;
using MathNet.Numerics;
using Microsoft.Extensions.DependencyInjection;
using NPOI.HPSF;
using System.Threading;
using Hotline.Share.Requests;
using Hotline.Repository.SqlSugar.TextSearch;
using SqlSugar;
using Hotline.Share.Enums.Order;
using Hotline.Repository.SqlSugar;
using DocumentFormat.OpenXml.Wordprocessing;
using Novacode;
using NPOI.HSSF.Record.Chart;

namespace Hotline.Application.Quality
{
    public class QualityApplication : IQualityApplication, IScopeDependency
    {
        private readonly ISessionContext _sessionContext;
        private readonly IMapper _mapper;
        private readonly IRepository<QualityDetail> _qualiteyDetail;
        private readonly IQualityRepository _qualityRepository;
        private readonly IOrderRepository _orderRepository;
        private readonly IRepository<QualityTemplate> _qualityTemplate;
        private readonly ISystemSettingCacheManager _systemSettingCacheManager;
        private readonly ILogger<Hotline.Quality.Quality> _logger;
        private readonly ICallApplication _callApplication;
        private readonly IOptionsSnapshot<AppConfiguration> _appOptions;
        private readonly Publisher _publisher;
        private readonly IRepository<TrCallRecord> _trCallRecordRepository;
        private readonly IRepository<OrderWord> _orderWordRepository;
		private readonly IServiceProvider _serviceProvider;
		private readonly IRepository<QualityItem> _qualiteyItem;
		private readonly IRepository<QualityTransferRecords> _qualityTransferRecordsRepository;
		protected ISugarUnitOfWork<HotlineDbContext> Uow { get; }
		protected ISqlSugarClient Db { get; }

		public QualityApplication(
            ISessionContext sessionContext,
            IMapper mapper,
            IRepository<QualityDetail> qualiteyDetail,
            IQualityRepository qualityRepository,
            IRepository<QualityTemplate> qualityTemplate,
            IOrderRepository orderRepository,
            ISystemSettingCacheManager systemSettingCacheManager,
            ICallApplication callApplication,
            IOptionsSnapshot<AppConfiguration> appOptions,
            ILogger<Hotline.Quality.Quality> logger,
            Publisher publisher,
            IRepository<TrCallRecord> trCallRecordRepository,
			IServiceProvider serviceProvider,
			IRepository<QualityItem> qualiteyItem,
			IRepository<OrderWord> orderWordRepository,
			IRepository<QualityTransferRecords> qualityTransferRecordsRepository,
			ISugarUnitOfWork<HotlineDbContext> uow)
        {
            _sessionContext = sessionContext;
            _mapper = mapper;
            _qualiteyDetail = qualiteyDetail;
            _qualityRepository = qualityRepository;
            _qualityTemplate = qualityTemplate;
            _orderRepository = orderRepository;
            _systemSettingCacheManager = systemSettingCacheManager;
            _callApplication = callApplication;
            _appOptions = appOptions;
            _logger = logger;
            _publisher = publisher;
            _trCallRecordRepository = trCallRecordRepository;
            _orderWordRepository = orderWordRepository;
            _serviceProvider = serviceProvider;
			_qualiteyItem = qualiteyItem;
            _qualityTransferRecordsRepository = qualityTransferRecordsRepository;
			Uow = uow;
			Db = uow.Db;
		}

        /// <summary>
        /// 新增质检
        /// </summary>
        /// <param name="Source"></param>
        /// <param name="OrderId"></param>
        /// <param name="VisitId"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task AddQualityAsync(EQualitySource Source, string OrderId, string VisitId, CancellationToken cancellationToken)
        {
            QualityAddDto quality = new QualityAddDto
            {
                Source = Source,
                OrderId = OrderId,
                VisitId = VisitId
            };
            var count = await _qualityRepository.CountAsync(x => x.OrderId == OrderId && x.Source == Source, cancellationToken);
            if (count <= 0)
                await AddQualityAsync(quality, cancellationToken);
            else
            {
                if (Source == EQualitySource.Visit) await _qualityRepository.Updateable().SetColumns(x => x.VisitId == VisitId).Where(x => x.OrderId == OrderId && x.Source == Source).ExecuteCommandAsync();
            }
        }

        /// <summary>
        /// 新增质检
        /// </summary>
        /// <param name="Source"></param>
        /// <param name="OrderId"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task AddQualityAsync(EQualitySource Source, string OrderId, CancellationToken cancellationToken)
        {
            QualityAddDto quality = new QualityAddDto
            {
                Source = Source,
                OrderId = OrderId
            };
            var count = await _qualityRepository.CountAsync(x => x.OrderId == OrderId && x.Source == Source, cancellationToken);
            if (count <= 0)
                await AddQualityAsync(quality, cancellationToken);
        }

        /// <summary>
        /// 新增质检实现
        /// </summary>
        /// <param name="model"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task AddQualityAsync(QualityAddDto model, CancellationToken cancellationToken)
        {
            var quality = _mapper.Map<Hotline.Quality.Quality>(model);
            quality.InitId();

            if (model.QualityDetails.Any())
            {
                foreach (var item in model.QualityDetails)
                {
                    item.QualityId = quality.Id;
                }
                List<QualityDetail> details = _mapper.Map<List<QualityDetail>>(model.QualityDetails);
                await _qualiteyDetail.AddRangeAsync(details, cancellationToken);
            }
            var order = await _orderRepository.GetAsync(model.OrderId);
			//受理智能质检
			if (model.Source == EQualitySource.Accepted)
            {
                var teAny = await _qualityTemplate.Queryable()
                    .LeftJoin<QualityTemplateDetail>((x, d) => x.Id == d.TemplateId)
                    .LeftJoin<QualityItem>((x, d, i) => d.ItemId == i.Id)
                    .Where((x, d, i) => i.IsIntelligent == 1).AnyAsync();
                if (teAny)
                {
                    if (order != null && !string.IsNullOrEmpty(order.CallId))
                    {
                        quality.AiQuality = true;
                        quality.Mode = "智能质检";
                    }
                }
            }
            await _qualityRepository.AddAsync(quality, cancellationToken);
            ///调用智能质检 捷通
			if (quality.AiQuality is true)
            {
                try
                {
                    var audioFile = string.Empty;
                    var fromNo = string.Empty;
                    DateTime? callStartTime = null;
                    if (_appOptions.Value.GetDefaultAppScopeConfiguration().CallCenterType == AppDefaults.CallCenterType.TianRun && !string.IsNullOrEmpty(order.CallId))
                    {
                        var call = await _callApplication.GetTianrunCallAsync(order.CallId, cancellationToken);
                        audioFile = call.RecordingAbsolutePath;
                        fromNo = call.CPN;
                        callStartTime = call.CreatedTime;
                    }
                    else if (_appOptions.Value.GetDefaultAppScopeConfiguration().CallCenterType == AppDefaults.CallCenterType.XingTang && !string.IsNullOrEmpty(order.CallId))
                    {
                        var call = await _callApplication.GetCallAsync(order.CallId, cancellationToken);
                        audioFile = call.AudioFile;
                        fromNo = call.FromNo;
                        callStartTime = call.BeginIvrTime;
                    }

                    var setting = _systemSettingCacheManager.GetSetting(SettingConstants.ViteRecordPrefix);
                    var handler = new AiQualityHandler() 
                    {
                        Id = quality.Id,
                        AudioFile =audioFile,
                        FromNo = fromNo,
                        CallStartTime = callStartTime,
                        ViteRecordPrefix = setting?.SettingValue[0],
                        Source = quality.Source.ToString(),
					};
                   await  _publisher.PublishAsync(new AiOrderQualityNotify(handler),PublishStrategy.ParallelNoWait,cancellationToken);
                }
                catch (Exception e)
                {
                    _logger.LogError($"写入智能质检异常1！, \r\n{e.Message}");
                }
            }

            _logger.LogInformation($"质检对象：{System.Text.Json.JsonSerializer.Serialize(quality, new JsonSerializerOptions { Encoder = JavaScriptEncoder.Create(UnicodeRanges.BasicLatin, UnicodeRanges.CjkUnifiedIdeographs) })}");
        }

        /// <summary>
        /// 修改质检信息
        /// </summary>
        /// <param name="model"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task UpdateQualityAsync(UpdateQualityDto model, CancellationToken cancellationToken)
        {
            //验证工单是否可以申请
            var quality = await _qualityRepository.GetAsync(model.Id, cancellationToken);
            if (quality is null)
                throw UserFriendlyException.SameMessage("无效质检");
            _mapper.Map(model, quality);
            quality.State = EQualityState.End;
            quality.UserName = _sessionContext.UserName;
            quality.QualityTime = DateTime.Now;
            await _qualityRepository.UpdateAsync(quality, cancellationToken);
            List<QualityDetail> deleteDetails = await _qualiteyDetail.Queryable().Where(x => x.QualityId == model.Id).ToListAsync(cancellationToken);
            await _qualiteyDetail.RemoveRangeAsync(deleteDetails, cancellationToken);
            if (model.QualityDetails.Any())
            {
                foreach (var item in model.QualityDetails)
                {
                    item.QualityId = model.Id;
                }
                List<QualityDetail> details = _mapper.Map<List<QualityDetail>>(model.QualityDetails);
                await _qualiteyDetail.AddRangeAsync(details, cancellationToken);
            }
        }

        /// <summary>
        /// 智能质检数据返回
        /// </summary>
        /// <returns></returns>
        public async Task AiResultAsync(List<AiQualityResultDto> model, CancellationToken cancellationToken) 
        {
            foreach(var item in model)
            {
                if (item.extended_field.field11 == "AiAnswered")
                {
                    await AiAnsweredDisposeAsync(item, cancellationToken);
				}
                if (item.extended_field.field11 == "Accepted")
                {
	                await AiQualityDisposeAsync(item, cancellationToken);
				}
			}
        }
        /// <summary>
        /// 智能质检数据处理
        /// </summary>
        /// <returns></returns>
		public async Task AiQualityDisposeAsync(AiQualityResultDto model, CancellationToken cancellationToken)
        {
			var quality = await _qualityRepository.GetAsync(model.record_id,cancellationToken);
			if (quality is { State: EQualityState.Apply } && model.score_items != null && model.score_items.Any())
			{
				List<QualityDetail> details = new List<QualityDetail>();
				foreach (var item2 in model.score_items)
				{
					if (item2.score > 0)
					{
						var detailsSentence = new List<QualityDetail>();
						QualityDetail detail = new QualityDetail
						{
							QualityId = quality.Id,
							Second = 0,
							EndSecond = 0,
							Name = item2.name,
							Content = item2.description,
							Intelligent = true,
							Grade = item2.score,
							Check = true,
						};
						if (item2?.qualityModels?.Count > 0)
						{
							foreach (var models in item2.qualityModels)
							{
								if (models?.sentenceResults?.Count > 0)
								{
									for (int i = 0; i < models.sentenceResults.Count; i++)
									{
										var newDetail = new QualityDetail();
										_mapper.Map(detail, newDetail);
										var sentenceList = model.trans_data.sentence_list.First(x => x.index == models.sentenceResults[i].index);
										newDetail.Second = sentenceList.start;
										newDetail.EndSecond = sentenceList.end == null ? 0 : sentenceList.end;
										newDetail.Content = sentenceList.text;
                                        if (newDetail.Second >= 1000)
											detailsSentence.Add(newDetail);
									}
								}
							}
						}
						if (item2?.audioAttributes?.Count > 0)
						{
							foreach (var audio in item2.audioAttributes)
							{
								if (audio?.sentenceResults?.Count > 0)
								{
									for (int i = 0; i < audio.sentenceResults.Count; i++)
									{
										var newDetail = new QualityDetail();
										_mapper.Map(detail, newDetail);
										var sentenceList = model.trans_data.sentence_list.First(x => x.index == audio.sentenceResults[i].index);
										newDetail.Second = sentenceList.start;
										newDetail.EndSecond = sentenceList.end == null ? 0 : sentenceList.end;
										newDetail.Content = sentenceList.text;
										if (newDetail.Second >= 1000)
											detailsSentence.Add(newDetail);
									}
								}

							}
						}
						if (detailsSentence.Count == 0)
						{
							if (detail.Second > 0)
								details.Add(detail);
						}
						else
						{
							details.AddRange(detailsSentence);
						}
					}
				}
				await _qualiteyDetail.AddRangeAsync(details,cancellationToken);
			}
		}
        /// <summary>
        /// 智能应答数据处理  暂时只支持天润  
        /// </summary>
        /// <returns></returns>
        public async Task AiAnsweredDisposeAsync(AiQualityResultDto model, CancellationToken cancellationToken)
        {
			var call = await _callApplication.GetTianrunCallTransliterationAsync(model.record_id, cancellationToken);
            if (call != null)
            {
                var transliterationContent = string.Empty;
				foreach (var item in model.trans_data.sentence_list)
	            {
                    var text = "user".Equals(item.role) ? item.text + "\n" : string.Empty;
                    transliterationContent += text;
				}
                transliterationContent = transliterationContent.Length > 7500 ? transliterationContent.Substring(0, 7500) : transliterationContent;
				var state = !string.IsNullOrEmpty(transliterationContent)? ECallTransliterationState.Succeed : ECallTransliterationState.Fail;
                List<string>? intersect = new List<string>();
                //处理敏感词
                if (!string.IsNullOrEmpty(transliterationContent))
                {
                    try
                    {
                        var words = await _orderWordRepository.Queryable().Where(x => x.IsEnable == 1 && x.Classify.Contains("敏感标签")).Select(x => x.Tag).ToListAsync(cancellationToken);
                        var res = new List<string>();
                        if (words.Any()) res = ParticipleTool.SegMMDouble(transliterationContent, ref words);
                        if (res.Any())
                        {
                            intersect = words.Intersect(res).ToList();
                        }
                    }
                    catch { }
                }
				await _trCallRecordRepository.Updateable().SetColumns(o => new TrCallRecord { TransliterationState = state, TransliterationContent = transliterationContent, Sensitive = intersect })
					.Where(o => o.Id == call.Id).ExecuteCommandAsync(cancellationToken);
			}
		}

        /// <summary>
        /// 异步转写
        /// </summary>
        /// <returns></returns>
        public async Task Transfer_XT(string Id, CancellationToken cancellationToken) {

			var quality = await _qualityRepository.Queryable().Includes(x => x.Order).Where(x => x.Id == Id).FirstAsync();
			var call = await _callApplication.GetCallAsync(quality.Order.CallId, cancellationToken);
			var items = await _qualiteyItem.Queryable().Where(x => x.IsEnable == 1 && x.IsDeleted == false && x.IsIntelligent == 1).ToListAsync(cancellationToken);

			var transfers = new List<Transfer>();
			if (!string.IsNullOrEmpty(call?.AudioFile))
			{
				var filename = call.AudioFile;
				try
				{
					var aiQualityService = _serviceProvider.GetRequiredService<IAiQualityService>();
                    var res = await aiQualityService.CreateAiOrderQualityTask(filename, cancellationToken);
                    //var res = "spk_01:您好，宜宾市12345政务服务便民的线，请问有什么可以帮您？\r\nspk_00:我也想问一下，我们我们是那个宜宾肿瘤医院的集师付。\r\nspk_00:现在肿瘤医院的这个还款情况到底是咋个的？\r\nspk_00:能不能还清我们的那个借资款啊？\r\nspk_01:抱歉先生，没有听明白您是什么集资户是哪个地方呢？\r\nspk_00:定是原来那个肿瘤医院。\r\nspk_01:具体地址是在哪里呢？\r\nspk_00:南岸那个嗯嗯地区公安局那个西对头西对门那个。\r\nspk_01:那个徐州区南岸街道的肿瘤医院是吧？\r\nspk_00:哦，对た。\r\nspk_01:全名叫多少的肿瘤医院呢？\r\nspk_00:是京市中瘤医院嘛。\r\nspk_01:就这边是这个肿瘤医院拖欠您钱吗？\r\nspk_00:嗯，汇下我们的借款。\r\nspk_01:是什么时候发生的呢？\r\nspk_00:好好多年了，大概2020202002年的时候。\r\nspk_01:大概是没样。\r\nspk_00:然后就不。\r\nspk_01:2012年吗？\r\nspk_00:2002年。\r\nspk_01:202002吗？\r\nspk_00:啊。\r\nspk_01:2002年，这个徐州区南安街道肿瘤医院拖欠多少的这个集资款呢？\r\nspk_00:哦，也多，这个人接实付的是几百。\r\nspk_01:建议您反映您个人拖欠了您多少。\r\nspk_00:1多万嘛。\r\nspk_00:现在我就是想问一下这个中瘤医院到底是政府是咋个的？\r\nspk_00:你你你去去年之洲还在跟我们开一个通报会，今年子就没有再没得消息的了，就不晓得。\r\nspk_01:女士抱歉，这边先打断您一下，这个是因为什么原因拖欠您10多万元呢？\r\nspk_00:就是借止嘛，借止以后没还嘛。\r\nspk_01:是这个徐州区南岸街道肿瘤医院集资是吧？\r\nspk_00:哦。\r\nspk_01:是这边是拖欠了您10多万元，就是相当于是您当时是给了他10多万元。\r\nspk_00:哦，我们结资啊等不是我一个人喽，他那个是生育医院的。\r\nspk_01:。\r\nspk_01:嗯。\r\nspk_00:他原来就是用于这个医院里头的发展啊、增加设备啊、资金周转啊这些。\r\nspk_00:我接机去噻等于这个接资多，这个这个人不是我一个人喽，几百人喽。现在我只是作为一个人的名想问一下。\r\nspk_01:万元是吧。\r\nspk_00:啊。\r\nspk_00:但我就想问很多情况，到底这个政府是咋个。\r\nspk_00:咋个来得得解决这个问题，最终还没还完，我们没款，我们没合同租行啊。\r\nspk_01:合同不行啊，有合同吗？\r\nspk_00:我们有那个有有合同，还且还有那个就开的这个呃跟我们的收据，我们截资的收据都还有啊。\r\nspk_01:就是有合同，有收据，这边有负责人电话吗？\r\nspk_00:哦。\r\nspk_00:这个人都已经到判判刑了，判刑了，今年这都已经出来了。\r\nspk_01:负责就是说没有负责，就已经判了刑是吧？\r\nspk_00:现在今年子已经已经刑满了4，谈了4年。\r\nspk_01:就这边就是有负责人电话吗？\r\nspk_00:没得，我们不想打电话。\r\nspk_01:但是3呀。\r\nspk_00:改言改言的反了，我们就是想问一下政府到底对这个接止案是咋个处理的。\r\nspk_00:那么多年了，这么多时间也不会也不给我们，今年是完全就不给我们通气了，去年之都还要通气。\r\nspk_01:这个好。\r\nspk_01:请问一下您贵姓。\r\nspk_00:请高。\r\nspk_01:全名叫什么呢？\r\nspk_00:开行。\r\nspk_01:高薪是吧？\r\nspk_00:嗯。\r\nspk_01:是哪一个星呢？\r\nspk_00:问我的名字没得用的，关键是我们这个借资借资人多的不得了几百人。现在我就是想问一下，因为今年是就完全没有通知我们的任何还款，去年就是还还还了一丁点，一丁点部分是小小部分。\r\nspk_01:是希望这后各医院尽快还款是吧？\r\nspk_00:是啊，政府到底咋个去解决嘛？这个事情我们想问一下政府咋个解决嘛这个事情。\r\nspk_01:您这边就是希望政府给出一个解决方案并。\r\nspk_01:就希望什么希望部门尽快催促他返款吗？还是什么意思？\r\nspk_00:就是这个意思就这个意思啊，原来都有专门的政府分管分管人员来来来负责这个事情。哎，跟我们跟我们这些接职妇妻统气汇报。现在今年子就完全没得这个那种得了，没得这种交流的了。\r\nspk_01:咱们就是先问一下师政费记有了，后续会有部门去核实处理的，可以吗？\r\nspk_00:要么就是想问一下市政府。\r\nspk_00:会呀。\r\nspk_01:请问还需要其他帮助吗？\r\nspk_00:没得我就想问下这个情况，政府是咋个，政府现在是一个啥态度，到底这个事情能不能够我们解决？\r\nspk_00:这因为不只于不是于你一个人嘛。\r\nspk_01:是傅这个谁用的吗？呃部门就是说这边是后续由部门去核实处理这件事情，可以吗？\r\nspk_00:啊，这到底是哪些在核实这个事情嘛，现在是哪些得管嘛，原来是法院都交给法院了的，现在法院也不晓得是咋个的，是的就说。\r\nspk_01:女士这边已经记录了，您这边如果没有其他问题需要反映的话，这边就要去先先听其他事电话了，可以吗？\r\nspk_00:你好久答复我们呢。\r\nspk_00:是不。\r\nspk_01:这边建议你5个工作日以后来电查询办理的进度。\r\nspk_00:啊。\r\nspk_01:这边建议您5个工作日以后来电查询办理的进度。\r\nspk_00:好嘛好好好。\r\nspk_01:提高对我的服建评价，感谢您的来。\r\n\r\n";
                    if (!string.IsNullOrEmpty(res))
					{
						var rowList = res.Split("\n");
						var sort = 0;
						foreach (var row in rowList)
						{
							var model = new Transfer();
							var statement = row.Split(":");
							if (statement.Count() == 2)
							{
								model.Sort = sort;
								model.Type = statement[0].ToString() == "spk_00" ? EQualityTransferType.Seats : EQualityTransferType.Citizen;
								model.Content = statement[1].ToString();
								model.ReviseContent = model.Content;
								if (!string.IsNullOrEmpty(model.Content))
								{
									var hitWord = items.Where(x => model.Content.Contains(x.Name)).ToList();
									List<QualityDetail> details = new List<QualityDetail>();
									foreach (var item in hitWord)
                                    {
										QualityDetail detail = new QualityDetail
										{
											QualityId = quality.Id,
											Second = 0,
											EndSecond = 0,
											Name = item.Name,
											Content = item.Name,
											Intelligent = true,
											Grade = item.Grade,
											Check = true,
										};
                                        details.Add(detail);
									}
									model.Prohibited = string.Join(",", hitWord.Select(x=>x.Name));
                                    await _qualiteyDetail.AddRangeAsync(details);
								}
							}
							transfers.Add(model);
							sort++;
						}
					}
					await _qualityRepository.Updateable().SetColumns(x => new Hotline.Quality.Quality { TransferState = EQualityTransferState.Succeed,Transfer = transfers }).Where(x => x.Id == quality.Id).ExecuteCommandAsync();
					await _qualityTransferRecordsRepository.Updateable().SetColumns(x => new QualityTransferRecords { TransferState = EQualityTransferState.Succeed,IsFinished = true }).Where(x => x.QualityId == quality.Id).ExecuteCommandAsync();
				}
				catch (Exception)
				{
					await _qualityRepository.Updateable().SetColumns(x => new Hotline.Quality.Quality { TransferState = EQualityTransferState.Lose}).Where(x => x.Id == quality.Id).ExecuteCommandAsync();
					await _qualityTransferRecordsRepository.Updateable().SetColumns(x => new QualityTransferRecords { TransferState = EQualityTransferState.Lose, IsFinished = true }).Where(x => x.QualityId == quality.Id).ExecuteCommandAsync();
					throw;
				}
			}
		}


        /// <summary>
        /// 坐席质检分析
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public ISugarQueryable<Hotline.Quality.Quality> SeatsQualityAnalyse(PagedKeywordRequest dto, CancellationToken cancellationToken) {

            var query = _qualityRepository.Queryable()
                .Includes(x => x.Order)
                .Includes(x => x.QualityDetails)
                .Where(x => x.Source == EQualitySource.Accepted && x.QualityTime >= dto.StartTime && x.QualityTime <= dto.EndTime && x.State == EQualityState.End)
                .OrderByIF(dto is { SortField: "grade", SortRule: 0 }, x => x.Grade, OrderByType.Asc)
                .OrderByIF(dto is { SortField: "grade", SortRule: 1 }, x => x.Grade, OrderByType.Desc); 

			return query;
        }

        /// <summary>
        /// 质检工单概览
        /// </summary>
        /// <returns></returns>
        public  ISugarQueryable<QualityOrderOverviewDto>  QualityOrderOverview(QualityWorkAnalysisRequest dto, int allOrderNum, CancellationToken cancellationToken) {

            var query = _qualiteyDetail.Queryable()
                .Includes(x => x.Quality)
                .Where(x => x.Quality.Source == EQualitySource.Accepted && x.Quality.QualityTime >= dto.StartTime && x.Quality.QualityTime <= dto.EndTime && x.Quality.State == EQualityState.End)
                .GroupBy(x => x.Name)
                .Select(x => new QualityOrderOverviewDto
                {
                    QualityItem = x.Name,
                    AllOrderNum = allOrderNum,
                    OrderNum = SqlFunc.AggregateDistinctCount(x.Quality.OrderId)
                })
                .MergeTable()
                .OrderByIF(dto is { SortField: "orderNum", SortRule: 0 }, x => x.OrderNum, OrderByType.Asc)
                .OrderByIF(dto is { SortField: "orderNum", SortRule: 1 }, x => x.OrderNum, OrderByType.Desc);

			return query;
        }

		public ISugarQueryable<SeatsQualityGradeAnalyseDto> SeatsQualityGradeAnalyse(QualityWorkAnalysisRequest dto,CancellationToken cancellationToken)
		{

            var query = _qualityRepository.Queryable()
                .Includes(x => x.Order)
                .Where(x => x.Source == EQualitySource.Accepted && x.QualityTime >= dto.StartTime && x.QualityTime <= dto.EndTime && x.State == EQualityState.End)
                .WhereIF(!string.IsNullOrEmpty(dto.AcceptorId), x => x.Order.AcceptorId == dto.AcceptorId)
                .GroupBy(x => x.Id)
                .Select(x => new SeatsQualityGradeAnalyseDto
                {
                    NinetyGrade = SqlFunc.AggregateSum(SqlFunc.IIF(x.Grade >= 90, 1, 0)),
                    EightyGrade = SqlFunc.AggregateSum(SqlFunc.IIF(x.Grade >= 80 && x.Grade < 90, 1, 0)),
                    SeventyGrade = SqlFunc.AggregateSum(SqlFunc.IIF(x.Grade >= 70 && x.Grade < 80, 1, 0)),
                    SixtyGrade = SqlFunc.AggregateSum(SqlFunc.IIF(x.Grade >= 60 && x.Grade < 70, 1, 0)),
                    FiftyGrade = SqlFunc.AggregateSum(SqlFunc.IIF(x.Grade < 60, 1, 0))
                });
			return query;
		}

		public async Task<List<MonthQualityGradeDto>> MonthQualityGrade(QualityWorkAnalysisRequest dto, CancellationToken cancellationToken)
		{
            var queryList = Db.Reportable(ReportableDateType.MonthsInLast1years).ToQueryable<DateTime>();

            var qualityList = _qualityRepository.Queryable()
                .Where(x => x.Source == EQualitySource.Accepted && x.State == EQualityState.End)
                .WhereIF(dto.MinGrade.HasValue && dto.MaxGrade.HasValue, x => x.Grade >= dto.MinGrade && x.Grade <= dto.MaxGrade)
                .WhereIF(!string.IsNullOrEmpty(dto.AcceptorId), x => x.Order.AcceptorId == dto.AcceptorId);


            var query = await queryList.LeftJoin(qualityList, (x1, x2) => x2.QualityTime.Value.ToString("yyyy-MM") == x1.ColumnName.ToString("yyyy-MM"))
                .GroupBy((x1, x2) => x1.ColumnName)
                .Select((x1, x2) => new MonthQualityGradeDto
				{
					Month = x1.ColumnName.ToString("MM"),
                    Num = SqlFunc.AggregateDistinctCount(x2.OrderId)
				}).ToListAsync();
			return query;
		}

	}
}
