using DotNetCore.CAP;
using Hotline.Application.Quality;
using Hotline.Caching.Interfaces;
using Hotline.File;
using Hotline.FlowEngine.Workflows;
using Hotline.Orders;
using Hotline.Repository.SqlSugar.Extensions;
using Hotline.Repository.SqlSugar.Ts;
using Hotline.Settings.TimeLimits;
using Hotline.Share.Dtos;
using Hotline.Share.Dtos.DataSharing.PusherHotlineDto;
using Hotline.Share.Dtos.File;
using Hotline.Share.Dtos.FlowEngine;
using Hotline.Share.Dtos.FlowEngine.Workflow;
using Hotline.Share.Dtos.Order;
using Hotline.Share.Dtos.Settings;
using Hotline.Share.Enums.Order;
using Hotline.Share.Enums.Quality;
using Hotline.Share.Enums.Settings;
using Hotline.Share.Requests;
using Hotline.Tools;
using MapsterMapper;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
using Novacode;
using SqlSugar;
using System.Data;
using System.Dynamic;
using Hotline.Settings;
using XF.Domain.Authentications;
using XF.Domain.Constants;
using XF.Domain.Dependency;
using XF.Domain.Exceptions;
using XF.Domain.Repository;

namespace Hotline.Application.Orders;

public class OrderApplication : IOrderApplication, IScopeDependency
{
    private readonly IOrderDomainService _orderDomainService;
    private readonly IWorkflowDomainService _workflowDomainService;
    private readonly IOrderRepository _orderRepository;
    private readonly ITimeLimitDomainService _timeLimitDomainService;
    private readonly IMapper _mapper;
    private readonly ISystemSettingCacheManager _systemSettingCacheManager;
    private readonly IRepository<OrderWord> _orderWrodRepository;
    private readonly IRepositoryTextSearch<OrderTs> _repositoryts;
    private readonly IFileRepository _fileRepository;
    private readonly ISessionContext _sessionContext;
    private readonly IRepository<OrderVisit> _orderVisitRepository;
    private readonly IRepository<OrderVisitDetail> _orderVisitDetailRepository;
    private readonly IQualityApplication _qualityApplication;
    private readonly ICapPublisher _capPublisher;

    public OrderApplication(
        IOrderDomainService orderDomainService,
        IOrderRepository orderRepository,
        IWorkflowDomainService workflowDomainService,
        ITimeLimitDomainService timeLimitDomainService,
        ISystemSettingCacheManager systemSettingCacheManager,
        IMapper mapper,
        IRepository<OrderWord> orderWrodRepository,
        IRepositoryTextSearch<OrderTs> repositoryts,
        IFileRepository fileRepository,
        ISessionContext sessionContext,
        IRepository<OrderVisit> orderVisitRepository,
        IRepository<OrderVisitDetail> orderVisitDetailRepository,
        IQualityApplication qualityApplication,
        ICapPublisher capPublisher
        )
    {
        _orderDomainService = orderDomainService;
        _workflowDomainService = workflowDomainService;
        _orderRepository = orderRepository;
        _timeLimitDomainService = timeLimitDomainService;
        _mapper = mapper;
        _systemSettingCacheManager = systemSettingCacheManager;
        _orderWrodRepository = orderWrodRepository;
        _repositoryts = repositoryts;
        _fileRepository = fileRepository;
        _sessionContext = sessionContext;
        _orderVisitRepository = orderVisitRepository;
        _orderVisitDetailRepository = orderVisitDetailRepository;
        _qualityApplication = qualityApplication;
        _capPublisher = capPublisher;
    }

    /// <summary>
    /// 更新工单办理期满时间(延期调用，其他不调用)
    /// 1.更新工单 2.更新流程 3.推送省平台
    /// </summary>
    /// <returns></returns>
    public async Task DelayOrderExpiredTimeAsync(string orderId, int timeCount, ETimeType timeType, CancellationToken cancellationToken)
    {
        var order = await _orderDomainService.GetOrderAsync(orderId, cancellationToken: cancellationToken);
        var expiredTimeConfig =
            _timeLimitDomainService.CalcEndTime(DateTime.Now, new TimeConfig(timeCount, timeType), order.AcceptTypeCode);
        order.TimeLimit = expiredTimeConfig.TimeText;
        order.TimeLimitCount = expiredTimeConfig.Count;
        order.TimeLimitUnit = expiredTimeConfig.TimeType;
        order.ExpiredTime = expiredTimeConfig.ExpiredTime;
        order.NearlyExpiredTime = expiredTimeConfig.NearlyExpiredTime;

        //if (string.IsNullOrEmpty(order.WorkflowId))
        //    throw new UserFriendlyException("该工单流程id异常");
        //var workflow = await _workflowDomainService.GetWorkflowAsync(order.WorkflowId, cancellationToken: cancellationToken);
        //await _workflowDomainService.UpdateExpiredTimeAsync(workflow, expiredTimeConfig.ExpiredTime,
        //    expiredTimeConfig.TimeText, expiredTimeConfig.Count, expiredTimeConfig.TimeType, expiredTimeConfig.NearlyExpiredTime, cancellationToken);

        if (string.IsNullOrEmpty(order.WorkflowId))
            throw new UserFriendlyException("该工单流程id异常");
        await _workflowDomainService.UpdateUnhandleExpiredTimeAsync(order.WorkflowId, expiredTimeConfig.ExpiredTime, cancellationToken);

        await _orderRepository.UpdateAsync(order, cancellationToken);
    }

    /// <summary>
    /// 新增工单办理流程记录
    /// </summary>
    public async Task AddOrderTracesAsync(string orderId, ICollection<WorkflowTraceDto> traces, CancellationToken cancellationToken)
    {
        var order = await _orderRepository.GetAsync(orderId, cancellationToken);
        if (order is null)
            throw new UserFriendlyException("工单不存在");
        if (string.IsNullOrEmpty(order.WorkflowId))
            throw new UserFriendlyException("工单未开启流程");
        await _workflowDomainService.AddTracesAsync(order.WorkflowId, _mapper.Map<List<WorkflowTrace>>(traces),
            cancellationToken);
    }

    /// <summary>
    /// 撤销工单
    /// </summary>
    public async Task CancelOrderAsync(string orderId, string opinion, CancellationToken cancellationToken)
    {
        var order = await _orderRepository.GetAsync(orderId, cancellationToken);
        if (order is null)
            throw new UserFriendlyException("工单不存在");
        if (!string.IsNullOrEmpty(order.WorkflowId))
        {
            //结束流程
            await _workflowDomainService.TerminateAsync(new TerminateDto
            {
                WorkflowId = order.WorkflowId,
                Opinion = opinion
            }, cancellationToken);
        }

        //归档工单
        var now = DateTime.Now;
        var handleDuration = order.StartTime.HasValue
            ? _timeLimitDomainService.CalcWorkTime(order.StartTime.Value,
                now, order.ProcessType is EProcessType.Zhiban)
            : 0;
        var fileDuration = order.CenterToOrgTime.HasValue
            ? _timeLimitDomainService.CalcWorkTime(order.CenterToOrgTime.Value,
                now, order.ProcessType is EProcessType.Zhiban)
            : 0;
        var allDuration = order.StartTime.HasValue
            ? _timeLimitDomainService.CalcWorkTime(order.StartTime.Value, now,
                order.ProcessType is EProcessType.Zhiban)
            : 0;
        order.File(now, handleDuration, fileDuration, allDuration);
        await _orderRepository.UpdateAsync(order, cancellationToken);
    }

    /// <summary>
    /// 即将超期列表
    /// </summary>
    /// <param name="dto"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    public ISugarQueryable<Order> GetAboutToExpireAsync(AboutToExpireListDto dto)
    {
        var setting = _systemSettingCacheManager.GetSetting(SettingConstants.OrderAboutToExpire);
        var value = setting?.SettingValue[0];
        value = string.IsNullOrEmpty(value) ? "0" : value;
        DateTime stTime = DateTime.Now.AddDays(int.Parse(value));
        stTime = _timeLimitDomainService.WorkDay(stTime);
        DateTime stTime2 = _timeLimitDomainService.WorkDay(DateTime.Now);
        return  _orderRepository.Queryable(canView: true).Includes(d=>d.OrderDelays)
            .WhereIF(dto.IsProvince.HasValue, d => d.IsProvince == dto.IsProvince)
            .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.No.Contains(dto.No!))
            .WhereIF(!string.IsNullOrEmpty(dto.Title), d => d.Title.Contains(dto.Title!))
            .WhereIF(dto.Delay.HasValue && dto.Delay == 1,d=>d.OrderDelays.Any() == true)
            .WhereIF(dto.Delay.HasValue && dto.Delay == 2, d => d.OrderDelays.Any() == false)
			.Where(d => d.ExpiredTime != null &&
            d.Status != EOrderStatus.Filed && d.Status != EOrderStatus.Published && d.Status != EOrderStatus.Visited && stTime >= d.ExpiredTime.Value && stTime2 <= d.ExpiredTime.Value)
            .OrderByDescending(d => d.CreationTime);
    }

    // /// <summary>
    // /// 即将超期节点列表
    // /// </summary>
    // /// <param name="dto"></param>
    // /// <param name="cancellationToken"></param>
    // /// <returns></returns>
    //public async Task<PagedDto<WorkflowOrderDto>> GetAboutToExpireNodeAsync(AboutToExpireListDto dto, CancellationToken cancellationToken)
    //{
    //	var setting = _systemSettingCacheManager.GetSetting(SettingConstants.OrderAboutToExpire);
    //	var value = setting?.SettingValue[0];
    //	value = string.IsNullOrEmpty(value) ? "0" : value;
    //	DateTime stTime = DateTime.Now.AddDays(int.Parse(value));
    //	stTime = _timeLimitDomainService.WorkDay(DateTime.Now);
    //	DateTime stTime2 = _timeLimitDomainService.WorkDay(DateTime.Now);
    //	RefAsync<int> total = 0;
    //	var items = await Db.Queryable<Workflow>()
    //		.LeftJoin<Order>((x, o) => x.ExternalId == o.Id)
    //		.Where(x => x.ModuleCode == "OrderHandle")
    //		.WhereIF(dto.IsProvince.HasValue, (x, o) => o.IsProvince == dto.IsProvince)
    //		.WhereIF(!string.IsNullOrEmpty(dto.Keyword), (x, o) => o.Title.Contains(dto.Keyword!) || o.No.Contains(dto.Keyword!))
    //		.Where((x, o) => (int)x.Status < 20 && stTime >= x.ExpiredTime && stTime2 <= x.ExpiredTime)
    //		.Select((x, o) => new WorkflowOrder { Order = o }, true)
    //		.OrderByDescending(x => x.CreationTime)
    //		.ToPageListAsync(dto.PageIndex, dto.PageSize, total, cancellationToken);
    //	return new PagedDto<WorkflowOrderDto>(total, _mapper.Map<IReadOnlyList<WorkflowOrderDto>>(items));
    //}

    /// <summary>
    /// 已超期列表
    /// </summary>
    /// <param name="dto"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    public ISugarQueryable<Order> GetToExpireAsync(AboutToExpireListDto dto)
    {
        DateTime stTime = _timeLimitDomainService.WorkDay(DateTime.Now);

        return _orderRepository.Queryable(canView: true).Includes(d => d.OrderDelays)
			.WhereIF(dto.IsProvince.HasValue, d => d.IsProvince == dto.IsProvince)
              //.WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Title.Contains(dto.Keyword!) || d.No.Contains(dto.Keyword!))
            .WhereIF(!string.IsNullOrEmpty(dto.No), x => x.No.Contains(dto.No))
            .WhereIF(!string.IsNullOrEmpty(dto.Title), x => x.Title.Contains(dto.Title!))
		    .WhereIF(dto.Delay.HasValue && dto.Delay == 1, d => d.OrderDelays.Any() == true)
            .WhereIF(dto.Delay.HasValue && dto.Delay == 2, d => d.OrderDelays.Any() == false)
			.Where(d => d.ExpiredTime != null &&
            (((d.Status == EOrderStatus.Filed || d.Status == EOrderStatus.Published || d.Status == EOrderStatus.Visited) && d.FiledTime >= d.ExpiredTime) ||
            ((d.Status != EOrderStatus.Filed && d.Status != EOrderStatus.Published && d.Status != EOrderStatus.Visited) && stTime >= d.ExpiredTime.Value)))
            .OrderByDescending(x => x.CreationTime);
    }

    //     /// <summary>
    //     /// 已超期节点列表
    //     /// </summary>
    //     /// <param name="dto"></param>
    //     /// <param name="cancellationToken"></param>
    //     /// <returns></returns>
    //     public async Task<PagedDto<WorkflowOrderDto>> GetToExpireNodeAsync(AboutToExpireListDto dto, CancellationToken cancellationToken)
    //     {
    //      DateTime stTime = _timeLimitDomainService.WorkDay(DateTime.Now);
    //RefAsync<int> total = 0;
    //var  items= await Db.Queryable<Workflow>()
    //             .LeftJoin<Order>((x,o)=>x.ExternalId == o.Id)
    //             .Where(x => x.ModuleCode == "OrderHandle")
    //             .WhereIF(dto.IsProvince.HasValue, (x, o) => o.IsProvince == dto.IsProvince)
    //             .WhereIF(!string.IsNullOrEmpty(dto.Keyword), (x, o) => o.Title.Contains(dto.Keyword!) || o.No.Contains(dto.Keyword!))
    //             .Where((x,o) => (((int)x.Status >= 20 && x.EndTime >= x.ExpiredTime) || ((int)x.Status < 20 && stTime >= x.ExpiredTime)))
    //             .Select((x, o) => new WorkflowOrder { Order = o }, true)
    //             .OrderByDescending(x => x.CreationTime)
    //             .ToPageListAsync(dto.PageIndex, dto.PageSize, total, cancellationToken);
    //      return new PagedDto<WorkflowOrderDto>(total, _mapper.Map<IReadOnlyList<WorkflowOrderDto>>(items));
    //     }

    /// <summary>
    /// 工单关键字分词
    /// </summary>
    /// <param name="inputStr"></param>
    /// <returns></returns>
    public async Task OrderParticiple(string inputStr, string orderId, CancellationToken cancellationToken)
    {
        var words = await _orderWrodRepository.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(inputStr, ref words);
        var participles = await _orderWrodRepository.Queryable().In(x => x.Tag, res).ToListAsync(cancellationToken);
        if (participles.Any())
        {
            //关键词
            var tags = participles.Select(x => x.Tag).ToList();
            var tagsStr = string.Join(",", tags);
            await _orderRepository.Updateable().SetColumns(x => x.TagNames == tagsStr).Where(x => x.Id == orderId).ExecuteCommandAsync(cancellationToken);
            List<string> synonyms = participles.Select(x => x.Synonym).ToList();
            if (synonyms.Any())
            {
                var synonymsStr = string.Join(",", synonyms);
                synonyms = synonymsStr.Split(",").Distinct().ToList();
                tags.AddRange(synonyms);
            }
            var vector = await _orderRepository.Queryable().Where(x => x.Id == orderId).ToListAsync(cancellationToken);
            if (vector.Any()) await _repositoryts.UpdateVectorAsync(orderId, tags, cancellationToken);
            else await _repositoryts.AddVectorAsync(orderId, DateTime.Now, tags, cancellationToken);
        }
    }

    public async Task OrderSensitiveParticiple(string inputStr, string orderId, CancellationToken cancellationToken)
    {
        var words = await _orderWrodRepository.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(inputStr, ref words);
        if (res.Any())
        {
            var intersect = words.Intersect(res).ToList();
            await _orderRepository.Updateable().SetColumns(o => new Order() { Sensitive = intersect }).Where(o => o.Id == orderId).ExecuteCommandAsync(cancellationToken);
        }
    }

    /// <summary>
    /// 接收外部平台工单
    /// </summary>
    public Task<AddOrderResponse> ReceiveOrderFromExternalAsync(AddOrderDto dto, ISessionContext current, CancellationToken cancellationToken)
    {
        switch (dto.Source)
        {
            case ESource.ProvinceStraight:
                return ReceiveOrderFromProvinceAsync(dto, dto.Files, current, cancellationToken);
            case ESource.Police110:
            case ESource.CityDataExchangeLz:
            case ESource.CityDataExchangeYB:
            case ESource.CityDataExchangeZG:
            case ESource.CityDataExchangeNJ:
            case ESource.WebPortal:
            case ESource.ConvergenceMedia:
            case ESource.IYIBIN:
            case ESource.ZHYB:
            case ESource.ZZPT:
            case ESource.WLLZ:
                return ReceiveOrderFromOtherPlatformAsync(dto, dto.Files, current, cancellationToken);
            case ESource.Hotline:
            case ESource.HotlineImport:
            default:
                throw new ArgumentOutOfRangeException();
        }
    }

    /// <summary>
    /// 接收外部平台修改工单附件
    /// </summary>
    public async Task UpdateOrderFilesAnonymousAsync(UpdateOrderFilesDto dto, CancellationToken cancellationToken)
    {
        if (string.IsNullOrEmpty(dto.Id) && string.IsNullOrEmpty(dto.OrderNo))
            throw new UserFriendlyException("工单外部编号不能为空");

        var order = await _orderRepository.Queryable()
              .FirstAsync(d => d.Id == dto.Id || d.No == dto.OrderNo, cancellationToken);
        if (order != null && dto.Files != null && dto.Files.Any())
        {
            order.FileJson = await _fileRepository.AddFileAsync(dto.Files, order.Id, "", cancellationToken);
            await _orderRepository.UpdateAsync(order, cancellationToken);
        }
    }

    /// <summary>
    /// 工单回访
    /// </summary>
    /// <param name="dto"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    public async Task OrderVisitWeb(OrderVisitWebDto dto, CancellationToken cancellationToken)
    {
        var visit = await _orderVisitRepository.Queryable()
            .Includes(x => x.Order)
            .Includes(x => x.OrderVisitDetails)
            .FirstAsync(x => x.Id == dto.Id);
        if (visit != null)
        {
            var first = dto.OrderVisitDetailDto.FirstOrDefault(x => x.VisitTarget == EVisitTarget.Org);

            if (first != null)
            {
                visit.NowEvaluate = first.OrgProcessingResults;
                visit.Order.Visited(first.OrgProcessingResults.Key, first.OrgProcessingResults.Value);
            }
            visit.VisitState = EVisitState.Visited;
            visit.VisitTime = dto.VisitTime;
            visit.VisitType = dto.VisitType;

            for (int i = 0; i < visit.OrderVisitDetails.Count; i++)
            {
                var detail = visit.OrderVisitDetails[i];
                var detaildto = dto.OrderVisitDetailDto.FirstOrDefault(x => x.Id == detail.Id);
                if (detaildto != null)
                {
                    _mapper.Map(detaildto, visit.OrderVisitDetails[i]);
                }
            }

            await _orderVisitRepository.UpdateAsync(visit, cancellationToken);
            await _orderVisitDetailRepository.UpdateRangeAsync(visit.OrderVisitDetails, cancellationToken);
            await _orderRepository.UpdateAsync(visit.Order, cancellationToken);
            var orderDto = _mapper.Map<OrderDto>(visit.Order);
            if (first != null)
            {
                //推省上
                await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderVisited,
                        new PublishVisitDto()
                        {
                            Order = orderDto,
                            No = visit.No,
                            VisitType = visit.VisitType,
                            VisitName = visit.CreatorName,
                            VisitTime = visit.VisitTime,
                            VisitRemark = string.IsNullOrEmpty(first.VisitContent) ? first.OrgProcessingResults?.Value : first.VisitContent,
                            AreaCode = visit.Order.AreaCode!,
                            SubjectResultSatifyCode = first.OrgProcessingResults.Key,
                            FirstSatisfactionCode = visit.Order.FirstVisitResultCode!,
                            ClientGuid = ""
                        }, cancellationToken: cancellationToken);
            }
            //写入质检
            await _qualityApplication.AddQualityAsync(EQualitySource.Visit, orderDto.Id, visit.Id,
                cancellationToken);
        }
    }

    public ISugarQueryable<Order> QueryOrders(QueryOrderDto dto)
    {
        var isCenter = _sessionContext.OrgIsCenter;

        return _orderRepository.Queryable(canView: isCenter ? false : true)
            .Includes(x => x.OrderScreens)
            .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Title.Contains(dto.Keyword!)) //标题
            .WhereIF(!string.IsNullOrEmpty(dto.ProvinceNo), d => d.ProvinceNo.Contains(dto.ProvinceNo)) //省本地编号
            .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.No.Contains(dto.No)) //工单编码
                                                                                //.WhereIF(!string.IsNullOrEmpty(dto.Content), d => d.Content.Contains(dto.Content!))
            .WhereIF(dto.AcceptTypes.Any(), d => dto.AcceptTypes.Contains(d.AcceptTypeCode)) //受理类型
            .WhereIF(dto.Channels.Any(), d => dto.Channels.Contains(d.SourceChannelCode)) //来源渠道
            .WhereIF(dto.HotspotIds.Any(), d => dto.HotspotIds.Contains(d.HotspotId)) //热点类型
            .WhereIF(!string.IsNullOrEmpty(dto.TransferPhone), d => d.TransferPhone.Contains(dto.TransferPhone!)) //转接号码
                                                                                                                  //.WhereIF(dto.OrgCodes.Any(), d => d.Workflow.Assigns.Any(s => dto.OrgCodes.Contains(s.OrgCode)))
            .WhereIF(dto.OrgCodes.Any(), d => dto.OrgCodes.Contains(d.ActualHandleOrgCode)) //接办部门
            .WhereIF(!string.IsNullOrEmpty(dto.NameOrNo), d => d.AcceptorName.Contains(dto.NameOrNo!) || d.AcceptorStaffNo.Contains(dto.NameOrNo!)) //受理人/坐席
            .WhereIF(dto.CreationTimeStart.HasValue, d => d.CreationTime >= dto.CreationTimeStart) //受理时间开始
            .WhereIF(dto.CreationTimeEnd.HasValue, d => d.CreationTime <= dto.CreationTimeEnd) //受理时间结束
            .WhereIF(dto.EmergencyLevels.Any(), d => dto.EmergencyLevels.Contains(d.EmergencyLevel))  //紧急程度
            .WhereIF(!string.IsNullOrEmpty(dto.FromPhone), d => d.FromPhone.Contains(dto.FromPhone)) //来电号码
            .WhereIF(!string.IsNullOrEmpty(dto.PhoneNo), d => d.Contact.Contains(dto.PhoneNo!)) //联系电话
            .WhereIF(!string.IsNullOrEmpty(dto.PushTypeCode), d => d.PushTypeCode == dto.PushTypeCode) //推送分类
            .WhereIF(dto.ExpiredTimeStart.HasValue, d => d.ExpiredTime >= dto.ExpiredTimeStart) //超期时间开始
            .WhereIF(dto.ExpiredTimeEnd.HasValue, d => d.ExpiredTime <= dto.ExpiredTimeEnd) //超期时间结束
            .WhereIF(dto.Statuses.Any(), d => dto.Statuses.Contains(d.Status))  //工单状态
            .WhereIF(dto.Statuses.Any(d => d == EOrderStatus.SpecialToUnAccept), d => d.Status <= EOrderStatus.SpecialToUnAccept)
            .WhereIF(!string.IsNullOrEmpty(dto.ActualHandlerName), d => d.ActualHandlerName.Contains(dto.ActualHandlerName)) //接办人
            .WhereIF(dto.IsScreen == true, d => d.OrderScreens.Any(x => x.Status != EScreenStatus.Refuse)) //有甄别
            .WhereIF(dto.IsScreen == false, d => !d.OrderScreens.Any(x => x.Status != EScreenStatus.Refuse)) //无甄别
            .WhereIF(!string.IsNullOrEmpty(dto.CurrentStepCode), d => d.ActualHandleStepCode == dto.CurrentStepCode) //当前办理节点
            .WhereIF(dto.ActualHandleTimeStart.HasValue, d => d.ActualHandleTime >= dto.ActualHandleTimeStart) //办结时间开始
            .WhereIF(dto.ActualHandleTimeEnd.HasValue, d => d.ActualHandleTime <= dto.ActualHandleTimeEnd) //办结时间结束
            .WhereIF(dto.IsOverTime == true, d => (d.ExpiredTime < DateTime.Now && d.Status < EOrderStatus.Filed) || (d.ExpiredTime < d.ActualHandleTime && d.Status >= EOrderStatus.Filed)) //是 超期
            .WhereIF(dto.IsOverTime == false, d => (d.ExpiredTime > DateTime.Now && d.Status < EOrderStatus.Filed) || (d.ExpiredTime > d.ActualHandleTime && d.Status >= EOrderStatus.Filed)) //否 超期
            .WhereIF(dto.IdentityType != null, d => d.IdentityType == dto.IdentityType) //来电主体
            .WhereIF(!string.IsNullOrEmpty(dto.FromName), d => d.FromName.Contains(dto.FromName)) //来电人姓名
            .WhereIF(dto.AreaCodes.Any(), d => dto.AreaCodes.Contains(d.AreaCode)) //区域
            .WhereIF(dto.IsProvinceOrder.HasValue && dto.IsProvinceOrder == true, x => x.IsProvince == true)
            .WhereIF(dto.IsProvinceOrder.HasValue && dto.IsProvinceOrder == false, x => x.IsProvince == false)
            .WhereIF(!string.IsNullOrEmpty(dto.SensitiveWord), x => SqlFunc.JsonArrayAny(x.Sensitive, dto.SensitiveWord))
            .WhereIF(dto.IsSensitiveWord.HasValue && dto.IsSensitiveWord == true, x => x.Sensitive != null && SqlFunc.JsonArrayLength(x.Sensitive) > 0)
            .OrderByDescending(d => d.CreationTime);
    }

    /// <summary>
    /// 未签收统计
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    public ISugarQueryable<Order,WorkflowStep> QueryUnsignedOrders(QueryUnsignedOrdersRequest dto) {
		if (dto.EndTime.HasValue)
			dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
		var IsCenter = _sessionContext.OrgIsCenter;
		return _orderRepository.Queryable()
            .LeftJoin<WorkflowStep>((x,ws)=>x.Id == ws.ExternalId)
            .WhereIF(dto.StartTime.HasValue, (x,ws) => ws.CreationTime >= dto.StartTime)
            .WhereIF(dto.EndTime.HasValue, (x, ws) => ws.CreationTime <= dto.EndTime)
            .WhereIF(dto.Level == 0 && IsCenter == false, (x, ws) => ws.AcceptorOrgId.StartsWith(_sessionContext.OrgId))
			.WhereIF(dto.Level == 1,(x,ws)=> ws.AcceptorOrgId == _sessionContext.OrgId)
            .WhereIF(dto.Level == 2, (x, ws) => ws.AcceptorOrgId.StartsWith(_sessionContext.OrgId))
            .WhereIF(dto.Signed == 0 ,(x,ws)=>ws.Status == Share.Enums.FlowEngine.EWorkflowStepStatus.WaitForAccept)
            .WhereIF(dto.Signed == 1, (x, ws) => ws.Status == Share.Enums.FlowEngine.EWorkflowStepStatus.WaitForHandle)
            .Where((x,ws)=>ws.CountersignPosition ==  Share.Enums.FlowEngine.ECountersignPosition.None && x.Status > EOrderStatus.WaitForAccept)
			.OrderByDescending((x,ws) => ws.CreationTime);
	}

    /// <summary>
    /// 信件来源统计
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    public ISugarQueryable<Order> QueryOrderSource(QueryOrderSourceRequest dto)
    {
	    if (dto.EndTime.HasValue)
		    dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
	    return _orderRepository.Queryable()
		    .WhereIF(dto.StartTime.HasValue, d => d.CreationTime >= dto.StartTime)
		    .WhereIF(dto.EndTime.HasValue, d => d.CreationTime <= dto.EndTime)
            .WhereIF(dto.IdentityType.HasValue , d=>d.IdentityType == dto.IdentityType)
            .Where(d=> d.SourceChannel != null &&  d.SourceChannel !="");
	}

	/// <summary>
	/// 信件来源统计列表
	/// </summary>
	/// <param name="dto"></param>
	/// <returns></returns>
	public async Task<List<OrderSourceHeaderVo>> QueryOrderSourceList(QueryOrderSourceRequest dto)
    {
	    if (dto.EndTime.HasValue)
		    dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
        var data = await _orderRepository.Queryable()
            .WhereIF(dto.StartTime.HasValue, d => d.CreationTime >= dto.StartTime)
            .WhereIF(dto.EndTime.HasValue, d => d.CreationTime <= dto.EndTime)
            .WhereIF(dto.IdentityType.HasValue, d => d.IdentityType == dto.IdentityType)
            .Where(d => d.SourceChannel != null && d.SourceChannel != "")
            .GroupBy(d => new { Time = d.CreationTime.ToString("yyyy-MM-dd"), d.SourceChannel })
            .Select(d => new OrderSourceHeaderVo
			{
                Time = d.CreationTime.ToString("yyyy-MM-dd"),
                Phone = SqlFunc.AggregateSum(SqlFunc.IIF(d.SourceChannelCode == "RGDH", 1, 0)),
                Web = SqlFunc.AggregateSum(SqlFunc.IIF(d.SourceChannelCode == "YTW", 1, 0)),
                Rests = SqlFunc.AggregateSum(SqlFunc.IIF(d.SourceChannelCode == "QT", 1, 0)),
                Created = SqlFunc.AggregateSum(SqlFunc.IIF(d.SourceChannelCode == "ZJ", 1, 0)),
                WeChat = SqlFunc.AggregateSum(SqlFunc.IIF(d.SourceChannelCode == "WX", 1, 0)),
                App = SqlFunc.AggregateSum(SqlFunc.IIF(d.SourceChannelCode == "AP", 1, 0)),
                WisdomYB = SqlFunc.AggregateSum(SqlFunc.IIF(d.SourceChannelCode == "ZHYB", 1, 0)),
                Platform = SqlFunc.AggregateSum(SqlFunc.IIF(d.SourceChannelCode == "ZZPT", 1, 0)),
                Platform12328 = SqlFunc.AggregateSum(SqlFunc.IIF(d.SourceChannelCode == "S12328", 1, 0)),
                MayorAndNetizens = SqlFunc.AggregateSum(SqlFunc.IIF(d.SourceChannelCode == "SZYSM", 1, 0)),
                MediaYB = SqlFunc.AggregateSum(SqlFunc.IIF(d.SourceChannelCode == "YBRMT", 1, 0)),
                Platform12345 = SqlFunc.AggregateSum(SqlFunc.IIF(d.SourceChannelCode == "S12345", 1, 0)),
                Interaction = SqlFunc.AggregateSum(SqlFunc.IIF(d.SourceChannelCode == "SZMHD", 1, 0)),
                ServiceYB = SqlFunc.AggregateSum(SqlFunc.IIF(d.SourceChannelCode == "YBS", 1, 0)),
                CityTransfer = SqlFunc.AggregateSum(SqlFunc.IIF(d.SourceChannelCode == "SZHZ", 1, 0)),
                Platform110 = SqlFunc.AggregateSum(SqlFunc.IIF(d.SourceChannelCode == "YB110", 1, 0)),
                NoService = SqlFunc.AggregateSum(SqlFunc.IIF(d.SourceChannelCode == "SMZXBNCS", 1, 0)),
                Iyb = SqlFunc.AggregateSum(SqlFunc.IIF(d.SourceChannelCode == "IYB", 1, 0))
			}).ToListAsync() ;
        var totalVo = new OrderSourceHeaderVo()
        {
            Time = "合计",
            Phone = data.Sum(x => x.Phone),
            Web = data.Sum(x => x.Web),
            Rests = data.Sum(x => x.Rests),
            Created = data.Sum(x => x.Created),
            WeChat = data.Sum(x => x.WeChat),
            App = data.Sum(x => x.App),
            WisdomYB = data.Sum(x => x.WisdomYB),
            Platform = data.Sum(x => x.Platform),
            Platform12328 = data.Sum(x => x.Platform12328),
            MayorAndNetizens = data.Sum(x => x.MayorAndNetizens),
            MediaYB = data.Sum(x => x.MediaYB),
            Platform12345 = data.Sum(x => x.Platform12345),
            Interaction = data.Sum(x => x.Interaction),
            ServiceYB = data.Sum(x => x.ServiceYB),
            CityTransfer = data.Sum(x => x.CityTransfer),
            Platform110 = data.Sum(x => x.Platform110),
            NoService = data.Sum(x => x.NoService),
            Iyb = data.Sum(x => x.Iyb)
        };
        data.Add(totalVo);
		return data;
	}

    public ISugarQueryable<Order> QueryOrderSourceDetail(QueryOrderSourceDetailRequest dto) {
		
		return _orderRepository.Queryable()
            .WhereIF(string.IsNullOrEmpty(dto.SourceChannel),d=>d.SourceChannel == dto.SourceChannel)
            .WhereIF(dto.Time.HasValue,d=>d.CreationTime.ToString("yyyy-MM-dd") == dto.Time.Value.ToString("yyyy-MM-dd"))
			.WhereIF(dto.IdentityType.HasValue, d => d.IdentityType == dto.IdentityType)
			.Where(d => d.SourceChannel != null && d.SourceChannel != "");
	}

	#region private

	/// <summary>
	/// 接受外部工单（除省平台）
	/// </summary>
	/// <param name="dto"></param>
	/// <param name="cancellationToken"></param>
	/// <returns></returns>
	private async Task<AddOrderResponse> ReceiveOrderFromOtherPlatformAsync(AddOrderDto dto, List<FileDto> files,
        ISessionContext current, CancellationToken cancellationToken)
    {
        if (string.IsNullOrEmpty(dto.ExternalId))
            throw new UserFriendlyException("工单外部编号不能为空");

        var order = await _orderRepository.Queryable()
            .FirstAsync(d => d.ExternalId == dto.ExternalId, cancellationToken);
        if (order == null)
        {
            order = _mapper.Map<Order>(dto);
            order.InitId();
            if (files != null && files.Any())
                order.FileJson = await _fileRepository.AddFileAsync(files, order.Id, "", cancellationToken);
            await _orderDomainService.AddAsync(order, cancellationToken: cancellationToken);
        }
        else
        {
            _mapper.Map(dto, order);
            if (files != null && files.Any())
                order.FileJson = await _fileRepository.AddFileAsync(files, order.Id, "", cancellationToken);
            await _orderRepository.UpdateAsync(order, cancellationToken);
        }

        return _mapper.Map<AddOrderResponse>(order);
    }

    /// <summary>
    /// 接受省平台工单
    /// </summary>
    private async Task<AddOrderResponse> ReceiveOrderFromProvinceAsync(AddOrderDto dto, List<FileDto> files,
        ISessionContext current, CancellationToken cancellationToken)
    {
        if (string.IsNullOrEmpty(dto.ProvinceNo))
            throw new UserFriendlyException("无效省工单编号");

        var orderExtension = await _orderDomainService.GetOrderExtensionsAsync(dto.ProvinceNo, cancellationToken);

        var order = await _orderRepository.GetAsync(d => d.ProvinceNo == dto.ProvinceNo, cancellationToken);
        if (order is null)
        {
            order = _mapper.Map<Order>(dto);
            order.InitId();
            if (files != null && files.Any())
                order.FileJson = await _fileRepository.AddFileAsync(files, order.Id, "", cancellationToken);
            await _orderDomainService.AddAsync(order, cancellationToken: cancellationToken);

            if (orderExtension is not null)
            {
                orderExtension.Id = order.Id;
                if (dto.OrderExtension != null)
                    _mapper.Map(dto.OrderExtension, orderExtension);
                await _orderDomainService.UpdateExtensionAsync(orderExtension, cancellationToken);
            }
        }
        else
        {
            _mapper.Map(dto, order);
            if (files != null && files.Any())
                order.FileJson = await _fileRepository.AddFileAsync(files, order.Id, "", cancellationToken);
            await _orderRepository.UpdateAsync(order, cancellationToken);

            if (orderExtension is not null)
            {
                orderExtension.Id = order.Id;
                if (dto.OrderExtension != null)
                    _mapper.Map(dto.OrderExtension, orderExtension);
                await _orderDomainService.UpdateExtensionAsync(orderExtension, cancellationToken);
            }

            //特提（撤回至发起)
            if (!string.IsNullOrEmpty(order.WorkflowId))
                await _workflowDomainService.RecallToStartStepAsync(order.WorkflowId, "省工单重派", current, cancellationToken);
        }
        return _mapper.Map<AddOrderResponse>(order);
    }

    #endregion
}