using Consul;
using DocumentFormat.OpenXml.Wordprocessing;
using DotNetCore.CAP;
using Hotline.Ai.CallOut;
using Hotline.Ai.Jths;
using Hotline.Ai.Visit;
using Hotline.Application.Quality;
using Hotline.Caching.Interfaces;
using Hotline.Caching.Services;
using Hotline.Orders;
using Hotline.Repository.SqlSugar.Extensions;
using Hotline.Settings;
using Hotline.Share.Dtos;
using Hotline.Share.Dtos.Ai;
using Hotline.Share.Dtos.Order;
using Hotline.Share.Enums.Ai;
using Hotline.Share.Enums.Order;
using Hotline.Share.Enums.Quality;
using Hotline.Tools;
using MapsterMapper;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Novacode.NETCorePort;
using Org.BouncyCastle.Utilities;
using SqlSugar;
using System.Runtime.CompilerServices;
using System.Threading;
using Hotline.Application.OrderApp;
using XF.Domain.Authentications;
using XF.Domain.Constants;
using XF.Domain.Exceptions;
using XF.Domain.Repository;
using XF.Utility.EnumExtensions;

namespace Hotline.Api.Controllers
{
    public class AiController: BaseController
    {
        private readonly ISystemSettingCacheManager _systemSettingCacheManager;
        private readonly IRepository<AiOrderVisit> _aiOrderVisitRepository;
        private readonly IRepository<AiOrderVisitDetail> _aiOrderVisitDetailRepository;
        private readonly IRepository<OrderVisit> _orderVisitRepository;
        private readonly IRepository<OrderVisitDetail> _orderVisitDetailRepository;
        private readonly IMapper _mapper;
        //private readonly IOptionsSnapshot<AiVisitConfig> _options;
        private readonly IAiVisitService _aiVisitService;
        private readonly ILogger<AiController> _logger;
        private readonly ICapPublisher _capPublisher;
        private readonly IOrderRepository _orderRepository;
        private readonly IQualityApplication _qualityApplication;
        private readonly ISystemDicDataCacheManager _sysDicDataCacheManager;
        private readonly IRepository<CallOutTemplate> _callOutTemplateRepository;
        private readonly IRepository<CallOutTask> _callOutTaskRepository;
        private readonly IRepository<CallOutTaskDetail> _callOutTaskDetailRepository;
        private readonly ISessionContext _sessionContext;
        private readonly IAiOrderVisitApplication _aiOrderVisitApplication;

        public AiController(ISystemSettingCacheManager systemSettingCacheManager,IRepository<AiOrderVisit> aiOrderVisitRepository,IRepository<AiOrderVisitDetail>  aiOrderVisitDetailRepository,IRepository<OrderVisit> orderVisitRepository,IRepository<OrderVisitDetail> orderVisitDetailRepository,IMapper mapper, /*IOptionsSnapshot<AiVisitConfig> options,*/IAiVisitService aiVisitService, ILogger<AiController> logger,ICapPublisher capPublisher,IOrderRepository orderRepository,IQualityApplication qualityApplication, ISystemDicDataCacheManager sysDicDataCacheManager,IRepository<CallOutTemplate> callOutTemplateRepository, IRepository<CallOutTask> callOutTaskRepository,IRepository<CallOutTaskDetail> callOutTaskDetailRepository,ISessionContext sessionContext,IAiOrderVisitApplication aiOrderVisitApplication)
        {
           _systemSettingCacheManager = systemSettingCacheManager;
            _aiOrderVisitRepository = aiOrderVisitRepository;
            _aiOrderVisitDetailRepository = aiOrderVisitDetailRepository;
            _orderVisitRepository = orderVisitRepository;
            _orderVisitDetailRepository = orderVisitDetailRepository;
            _mapper = mapper;
            //_options = options;
            _aiVisitService = aiVisitService;
            _logger = logger;
            _capPublisher = capPublisher;
            _orderRepository = orderRepository;
            _qualityApplication = qualityApplication;
            _sysDicDataCacheManager = sysDicDataCacheManager;
            _callOutTemplateRepository = callOutTemplateRepository;
            _callOutTaskRepository = callOutTaskRepository;
            _callOutTaskDetailRepository = callOutTaskDetailRepository;
            _sessionContext = sessionContext;
            _aiOrderVisitApplication = aiOrderVisitApplication;
        }


        /// <summary>
        /// 智能语音导航配置查询
        /// </summary>
        /// <param name="count"></param>
        /// <returns></returns>
        [HttpGet("ivr/access-confirm")]
        [AllowAnonymous]
        public async Task<bool> AccessConfirm([FromQuery]int count) 
        {

            //获取是否开启智能语音队列
            bool isAiIvr = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.IsAIIVR)?.SettingValue[0]);
            if (!isAiIvr)
                return false;

            //获取智能语音队列数
            var queueNum = int.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.QueueNum)?.SettingValue[0]);
            if (count < queueNum)
                return false;

            //判断是否在时间段内
            var aiIVRTimeArr = _systemSettingCacheManager.GetSetting(SettingConstants.AIIVRTime)?.SettingValue;
            bool IsOk = false;
            aiIVRTimeArr.ForEach((item) => {
                List<string> times = JsonConvert.DeserializeObject<List<string>>(item);
                var beginTime = DateTime.Parse(DateTime.Now.ToShortDateString() + " " + times[0] + ":00");
                var endTime = DateTime.Parse(DateTime.Now.ToShortDateString() + " " + times[1] + ":00");
                if (DateTime.Now>beginTime && DateTime.Now< endTime)
                {
                    IsOk = true;
                }
            });
            return IsOk;
        }

        #region 批量外呼

        #region 批量外呼模板

        /// <summary>
        /// 外呼模板列表
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpGet("callout-template-list")]
        public async Task<PagedDto<AiCallOutTemplateQueryRep>> AiCallOutTemplateQuery([FromQuery]AiCallOutTemplateQueryRequest dto)
        {
            var (total,items) =await _callOutTemplateRepository.Queryable()
                .Includes(x=>x.CallOutTasks)
                .WhereIF(!string.IsNullOrEmpty(dto.TemplateName), x => x.TemplateName.Contains(dto.TemplateName))
                .WhereIF(dto.StartTime != null, x => x.CreationTime >= dto.StartTime)
                .WhereIF(dto.EndTime != null, x => x.CreationTime <= dto.EndTime)
                .Select(x => new AiCallOutTemplateQueryRep()
                {
                    Id = x.Id,
                    TemplateName = x.TemplateName,
                    TemplateContent = x.TemplateContent,
                    CallOutTaskCount = x.CallOutTasks.Count(),
                    CreationTime = x.CreationTime,
                    IsEnable = x.IsEnable,
                    CreatorName = x.CreatorName,
                    CreatorOrgName = x.CreatorOrgName,
                })
                .OrderByDescending(x => x.CreationTime)
                .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
            return new PagedDto<AiCallOutTemplateQueryRep>(total,items);
        }

        /// <summary>
        /// 新增外呼模板
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPost("add-callouttemplate")]
        public async Task AddCallOutTemplate([FromBody]CallOutTemplateDto dto)
        {
            var callOutTemplate = _mapper.Map<CallOutTemplate>(dto);
            callOutTemplate.IsEnable = true;
            await _callOutTemplateRepository.AddAsync(callOutTemplate, HttpContext.RequestAborted);
        }
        /// <summary>
        /// 修改外呼模板
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPost("update-callouttemplate")]
        public async Task UpdateCallOutTemplate([FromBody] UpdateCallOutTemplateDto dto)
        {
            var model = await _callOutTemplateRepository.Queryable().Includes(x=>x.CallOutTasks).FirstAsync(x => x.Id == dto.Id, HttpContext.RequestAborted);
            if (model == null)
                throw UserFriendlyException.SameMessage("无效模板");
            //验证是否有待执行的外呼任务
            if (model.CallOutTasks.Any(x=>x.AiCallOutTaskState!= EAiCallOutTaskState.Ended))
            {
                throw UserFriendlyException.SameMessage("当前模板有待执行的外呼任务，暂时无法修改！");
            }

            model.TemplateName = dto.TemplateName;
            model.TemplateContent = dto.TemplateContent;

            await _callOutTemplateRepository.UpdateAsync(model, HttpContext.RequestAborted);
        }

        /// <summary>
        /// 删除外呼模板
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpDelete("del-callouttemplate")]
        public async Task DelCallOutTemplate([FromQuery]string id)
        {
            var model = await _callOutTemplateRepository.Queryable().Includes(x => x.CallOutTasks).FirstAsync(x => x.Id == id, HttpContext.RequestAborted);
            if (model == null)
                throw UserFriendlyException.SameMessage("无效模板");

            //验证是否有待执行的外呼任务
            if (model.CallOutTasks.Any(x => x.AiCallOutTaskState != EAiCallOutTaskState.Ended))
            {
                throw UserFriendlyException.SameMessage("当前模板有待执行的外呼任务，暂时无法删除！");
            }

            await _callOutTemplateRepository.RemoveAsync(id, true, HttpContext.RequestAborted);
        }

        /// <summary>
        /// 外呼模板启用禁用
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpGet("callouttemplate-enable-unenable")]
        public async Task CallOutTemplateEnableAndUnEnable([FromQuery]string id)
        {
            var model = await _callOutTemplateRepository.Queryable().Includes(x => x.CallOutTasks).FirstAsync(x => x.Id == id, HttpContext.RequestAborted);
            if (model == null)
                throw UserFriendlyException.SameMessage("无效模板");

            //验证是否有待执行的外呼任务
            if (model.CallOutTasks.Any(x => x.AiCallOutTaskState != EAiCallOutTaskState.Ended))
            {
                throw UserFriendlyException.SameMessage("当前模板有待执行的外呼任务，暂时无法操作！");
            }

            model.IsEnable = !model.IsEnable;

            await _callOutTemplateRepository.UpdateAsync(model, HttpContext.RequestAborted);
        }




        #endregion


        #region 批量外呼任务

        /// <summary>
        /// 批量外呼任务列表
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpGet("callout/callouttask-list")]
        public async Task<PagedDto<AiCallOutListRep>> AiCallOutList([FromQuery]AiCallOutListRequest dto)
        {
            var (total,items) = await _callOutTaskRepository.Queryable()
                .Includes(x => x.CallOutTemplate)
                .WhereIF(!string.IsNullOrEmpty(dto.TaskName), x => x.TaskName.Contains(dto.TaskName))
                .WhereIF(dto.AiCallOutTaskState != null, x => x.AiCallOutTaskState == dto.AiCallOutTaskState)
                .WhereIF(dto.StartTime.HasValue,x=>x.CreationTime>= dto.StartTime)
                .WhereIF(dto.EndTime.HasValue,x=>x.CreationTime<=dto.EndTime)
                .OrderByDescending(x => x.CreationTime)
                .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
            return new PagedDto<AiCallOutListRep>(total, _mapper.Map<IReadOnlyList<AiCallOutListRep>>(items));
        }

        /// <summary>
        /// 外呼任务列表基础数据
        /// </summary>
        /// <returns></returns>
        [HttpGet("callout/list-basedata")]
        public async Task<object> AiCallOuttListBaseData()
        {
            return new {
                AiCallOutTaskState = EnumExts.GetDescriptions<EAiCallOutTaskState>(),
                AiCallOutState = EnumExts.GetDescriptions<EAiCallOutState>()
            };
        }

        /// <summary>
        /// 批量外呼任务明细列表
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpGet("callout/callouttaskdetail")]
        public async Task<PagedDto<AiCallOutDetailListRep>> AiCallOutDetailList([FromQuery] AiCallOutDetailListRequest dto)
        {
            var (total, items) = await _callOutTaskDetailRepository.Queryable()
                .Where(x => x.CallOutTaskId == dto.Id)
                .WhereIF(!string.IsNullOrEmpty(dto.OuterNo),x=>x.OuterNo.Contains(dto.OuterNo))
                .WhereIF(!string.IsNullOrEmpty(dto.Name),x=>x.Name.Contains(dto.Name))
                .WhereIF(dto.AiCallOutState!=null,x=>x.AiCallOutState== dto.AiCallOutState)
                .OrderByDescending(x => x.CreationTime)
                .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
            return new PagedDto<AiCallOutDetailListRep>(total,_mapper.Map<IReadOnlyList<AiCallOutDetailListRep>>(items));
        }

        /// <summary>
        /// 新增批量外呼任务
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPost("callout/add-callout")]
        public async Task AddAiCallOut([FromBody] AddAiCallOutRequest dto)
        {
            //验证是否有重复电话
            if (dto.AddAiCallOutTaskDetailDtos.DistinctBy(x => x.OuterNo).Count() != dto.AddAiCallOutTaskDetailDtos.Count)
            {
                throw UserFriendlyException.SameMessage("任务中存在重复外呼号码，请检查后重新提交");
            }
            var model = _mapper.Map<CallOutTask>(dto);
            var detaillist = _mapper.Map<List<CallOutTaskDetail>>(dto.AddAiCallOutTaskDetailDtos);
            model.AiCallOutTaskState = EAiCallOutTaskState.NoStarted;
            model.HasVisitCount = dto.AddAiCallOutTaskDetailDtos.Count;
            model.VisitedCount = 0;
            model.VisitedFailCount = 0;
            var id = await _callOutTaskRepository.AddAsync(model, HttpContext.RequestAborted);

            detaillist.ForEach(x =>
            {
                x.CallOutTaskId = id;
                x.AiCallOutState = EAiCallOutState.InProgress;
            });
            await _callOutTaskDetailRepository.AddRangeAsync(detaillist, HttpContext.RequestAborted);
            #region 获取系统设置
            var callOutSceneUid = _systemSettingCacheManager.GetSetting(SettingConstants.CallOutSceneUid)?.SettingValue[0];
            var callOutRuleUid = _systemSettingCacheManager.GetSetting(SettingConstants.CallOutRuleUid)?.SettingValue[0];
            var CallOutContentKey = _systemSettingCacheManager.GetSetting(SettingConstants.CallOutContentKey)?.SettingValue[0];
            #endregion
            var pushModel = await _callOutTaskRepository.Queryable()
                .Includes(x => x.CallOutTemplate)
                .Includes(x => x.CallOutTaskDetails)
                .FirstAsync(x => x.Id == id);
            var newModel = await _aiVisitService.CreateAiCallOutTask(pushModel, callOutSceneUid, callOutRuleUid, CallOutContentKey, HttpContext.RequestAborted);

            if (string.IsNullOrEmpty(newModel.BatchUid))
            {
                newModel.AiCallOutTaskState = EAiCallOutTaskState.Ended;
            }
            await _callOutTaskRepository.UpdateAsync(newModel, HttpContext.RequestAborted);
            await _callOutTaskDetailRepository.UpdateRangeAsync(newModel.CallOutTaskDetails, HttpContext.RequestAborted);
        }


        /// <summary>
        /// 可用外呼模板
        /// </summary>
        /// <returns></returns>
        [HttpGet("callout/canuse-template")]
        public async Task<List<CanUseCallOutTemplateListRep>> CanUseCallOutTemplateList()
        {
            var list = await _callOutTemplateRepository.Queryable().Where(x => x.IsEnable == true).ToListAsync(HttpContext.RequestAborted);
            return _mapper.Map<List<CanUseCallOutTemplateListRep>>(list);
        }

        /// <summary>
        /// 终止外呼任务
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [HttpPost("callout/closecallouttask")]
        public async Task CloseCalloutTask([FromBody] CloseCalloutTaskReq request)
        {
            switch (request.TypeId)
            {
                case 1:
                    var aiVisit = await _aiOrderVisitRepository.Queryable()
                        .Includes(x => x.AiOrderVisitDetails,s=>s.OrderVisit)
                        .FirstAsync(x => x.Id == request.Id,HttpContext.RequestAborted);
                    if (aiVisit!=null && !string.IsNullOrEmpty(aiVisit.BatchUid))
                    {
                        if (aiVisit.TaskState !=  EAiOrderVisitTaskState.Pause)
                            throw UserFriendlyException.SameMessage("请先暂停任务，再进行终止;");

                        bool isOk = await _aiVisitService.ChangeStatusAsync(aiVisit.BatchUid, "cancel", HttpContext.RequestAborted);

                        if (!isOk)
                            throw UserFriendlyException.SameMessage("终止失败");

                        aiVisit.TaskState = EAiOrderVisitTaskState.Close;
                        aiVisit.AiOrderVisitDetails.ForEach(async x =>
                        {
                            if (x.AiOrderVisitState == EAiOrderVisitState.NoStarted)
                            {
                                x.AiOrderVisitState = EAiOrderVisitState.LoseEfficacy;
                                x.OrderVisit.VisitState = EVisitState.WaitForVisit;
                            }
                            await _orderVisitRepository.UpdateAsync(x.OrderVisit);
                        });
                        await _aiOrderVisitRepository.UpdateAsync(aiVisit, HttpContext.RequestAborted);
                        await _aiOrderVisitDetailRepository.UpdateRangeAsync(aiVisit.AiOrderVisitDetails, HttpContext.RequestAborted);

                    }
                    break;
                case 2:
                    var callOut = await _callOutTaskRepository.Queryable()
                       .Includes(x => x.CallOutTaskDetails)
                       .FirstAsync(x => x.Id == request.Id);
                    if (callOut != null && !string.IsNullOrEmpty(callOut.BatchUid))
                    {
                        if (callOut.AiCallOutTaskState !=  EAiCallOutTaskState.Pause)
                            throw UserFriendlyException.SameMessage("请先暂停任务，再进行终止;");

                        bool isOk = await _aiVisitService.ChangeStatusAsync(callOut.BatchUid, "cancel", HttpContext.RequestAborted);

                        if (!isOk)
                            throw UserFriendlyException.SameMessage("终止失败");
                        //处理业务数据
                        callOut.AiCallOutTaskState = EAiCallOutTaskState.Close;
                        callOut.CallOutTaskDetails.ForEach(x =>
                        {
                            if (x.AiCallOutState == EAiCallOutState.NoStarted)
                                x.AiCallOutState = EAiCallOutState.LoseEfficacy;
                        });
                        await _callOutTaskRepository.UpdateAsync(callOut, HttpContext.RequestAborted);
                        await _callOutTaskDetailRepository.UpdateRangeAsync(callOut.CallOutTaskDetails, HttpContext.RequestAborted);
                    }
                    break;
                default:
                    throw UserFriendlyException.SameMessage("未知业务");
            }
        }

        /// <summary>
        /// 暂停外呼任务
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [HttpPost("callout/pausecallouttask")]
        public async Task PauseCalloutTask([FromBody] CloseCalloutTaskReq request)
        {
            switch (request.TypeId)
            {
                case 1:
                    var aiVisit = await _aiOrderVisitRepository.Queryable()
                        .FirstAsync(x => x.Id == request.Id,HttpContext.RequestAborted);
                    if (aiVisit != null && !string.IsNullOrEmpty(aiVisit.BatchUid))
                    {
                        if (aiVisit.TaskState != EAiOrderVisitTaskState.NoStarted && aiVisit.TaskState != EAiOrderVisitTaskState.InProgress)
                            throw UserFriendlyException.SameMessage("当前状态不能终止");

                        bool isOk = await _aiVisitService.ChangeStatusAsync(aiVisit.BatchUid, "stop", HttpContext.RequestAborted);

                        if (!isOk)
                            throw UserFriendlyException.SameMessage("终止失败");

                        aiVisit.TaskState = EAiOrderVisitTaskState.Pause;
                        await _aiOrderVisitRepository.UpdateAsync(aiVisit, HttpContext.RequestAborted);
                    }
                    break;
                case 2:
                    var callOut = await _callOutTaskRepository.Queryable()
                       .FirstAsync(x => x.Id == request.Id);
                    if (callOut != null && !string.IsNullOrEmpty(callOut.BatchUid))
                    {
                        if (callOut.AiCallOutTaskState != EAiCallOutTaskState.NoStarted && callOut.AiCallOutTaskState != EAiCallOutTaskState.InProgress)
                            throw UserFriendlyException.SameMessage("当前状态不能终止");

                        bool isOk = await _aiVisitService.ChangeStatusAsync(callOut.BatchUid, "stop", HttpContext.RequestAborted);

                        if (!isOk)
                            throw UserFriendlyException.SameMessage("终止失败");
                        //处理业务数据
                        callOut.AiCallOutTaskState = EAiCallOutTaskState.Pause;
                        await _callOutTaskRepository.UpdateAsync(callOut, HttpContext.RequestAborted);
                    }
                    break;
                default:
                    throw UserFriendlyException.SameMessage("未知业务");
            }
        }

        /// <summary>
        /// 启动外呼任务
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [HttpPost("callout/startcallouttask")]
        public async Task StartCalloutTask([FromBody] CloseCalloutTaskReq request)
        {
            switch (request.TypeId)
            {
                case 1:
                    var aiVisit = await _aiOrderVisitRepository.Queryable()
                        .FirstAsync(x => x.Id == request.Id, HttpContext.RequestAborted);
                    if (aiVisit != null && !string.IsNullOrEmpty(aiVisit.BatchUid))
                    {
                        if (aiVisit.TaskState != EAiOrderVisitTaskState.Pause)
                            throw UserFriendlyException.SameMessage("当前状态不能启动");

                        bool isOk = await _aiVisitService.ChangeStatusAsync(aiVisit.BatchUid, "start", HttpContext.RequestAborted);

                        if (!isOk)
                            throw UserFriendlyException.SameMessage("启动失败");

                        aiVisit.TaskState = EAiOrderVisitTaskState.InProgress;
                        await _aiOrderVisitRepository.UpdateAsync(aiVisit, HttpContext.RequestAborted);
                    }
                    break;
                case 2:
                    var callOut = await _callOutTaskRepository.Queryable()
                       .FirstAsync(x => x.Id == request.Id);
                    if (callOut != null && !string.IsNullOrEmpty(callOut.BatchUid))
                    {
                        if (callOut.AiCallOutTaskState != EAiCallOutTaskState.Pause)
                            throw UserFriendlyException.SameMessage("当前状态不能启动");

                        bool isOk = await _aiVisitService.ChangeStatusAsync(callOut.BatchUid, "start", HttpContext.RequestAborted);

                        if (!isOk)
                            throw UserFriendlyException.SameMessage("启动失败");
                        //处理业务数据
                        callOut.AiCallOutTaskState = EAiCallOutTaskState.InProgress;
                        await _callOutTaskRepository.UpdateAsync(callOut, HttpContext.RequestAborted);
                    }
                    break;
                default:
                    break;
            }
        }

        #endregion

        #endregion

        #region 智能回访


        /// <summary>
        /// 智能回访外呼结果回传
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [AllowAnonymous]
        [HttpPost("aivisit/aivisit-back")]
        public async Task AiVisitBack([FromBody]AiVisitBackDto dto)
        {
            _logger.LogInformation($"收到智能外呼结果回传：{JsonConvert.SerializeObject(dto)}");
            var SceneUid = _systemSettingCacheManager.GetSetting(SettingConstants.VisitSceneUid)?.SettingValue[0];//场景ID
            var CallOutSceneUid = _systemSettingCacheManager.GetSetting(SettingConstants.CallOutSceneUid)?.SettingValue[0];//批量外呼场景ID
            //回访
            if (dto.SceneUid== SceneUid)
            {
                var aiOrderVisit = await _aiOrderVisitRepository.Queryable()
                .Includes(x => x.AiOrderVisitDetails, s => s.OrderVisit, d => d.Order)
                .FirstAsync(x => x.BatchUid == dto.BatchUid);
                if (aiOrderVisit != null)
                {
                    //验证记录中是否存在有结果的任务
                    if (dto.TaskStatus == 6)//执行完
                    {

                        #region 获取所有配置参数
                        var QuestionIdZero = _systemSettingCacheManager.GetSetting(SettingConstants.QuestionIdZero)?.SettingValue[0]; //是否联系
                        var QuestionIdOne = _systemSettingCacheManager.GetSetting(SettingConstants.QuestionIdOne)?.SettingValue[0];//是否解决
                        var QuestionIdTwo = _systemSettingCacheManager.GetSetting(SettingConstants.QuestionIdTwo)?.SettingValue[0];//办件结果满意度
                        //var QuestionIdThree = _systemSettingCacheManager.GetSetting(SettingConstants.QuestionIdThree)?.SettingValue[0];//坐席是否满意
                        var VisitContentIdOne = _systemSettingCacheManager.GetSetting(SettingConstants.VisitContentIdOne)?.SettingValue[0];//办件结果不满意原因
                        //var VisitContentIdTwo = _systemSettingCacheManager.GetSetting(SettingConstants.VisitContentIdTwo)?.SettingValue[0];//坐席不满意原因
                        #endregion

                        var aiOrderVisitDetail = aiOrderVisit.AiOrderVisitDetails.FirstOrDefault(x => x.TaskUid == dto.TaskUid);
                        if (aiOrderVisitDetail != null)
                        {
                            var callRecord = dto.CallRecordList.OrderBy(x => x.CallNo).LastOrDefault();
                            // 回访结果(ReturnVisit)[1成功、0不涉及、-1失败]
                            if (callRecord != null) //有结果的任务
                            {
                                aiOrderVisitDetail.AiOrderVisitState = Share.Enums.Ai.EAiOrderVisitState.Ended; //更新AI子表
                                aiOrderVisitDetail.AiVisitTime = DateTime.Now;
                                aiOrderVisitDetail.CallTime = string.IsNullOrEmpty(callRecord.CallTime)? null : DateTime.Parse(callRecord.CallTime);
                                //aiOrderVisitDetail.SentenceList = _mapper.Map<List<SentenceList>>(callRecord.SentenceList);
                                aiOrderVisit.VisitedCount++;
                                //处理结果
                                var visitDetail = _orderVisitDetailRepository.Queryable().Where(x => x.VisitId == aiOrderVisitDetail.OrderVisit.Id).ToList();
                                //先处理子表

                                //处理部门
                                var orgDetail = visitDetail.Where(x => x.VisitTarget == Share.Enums.Order.EVisitTarget.Org).ToList();
                                //过滤结果
                                Kv? orgProcessingResults = null;
                                //var orgHandledAttitude = new Kv();
                                ESeatEvaluate? seatEvaluate = ESeatEvaluate.DefaultSatisfied;
                                var visitContent = "";
                                var seatVisitContent = "默认满意";
                                var volveConent = "";
                                bool? isSolve = null;
                                bool? isContact = null;
                                //通话录音
                                var recordUrl = callRecord.RecordUrl;
                                if (callRecord.QuestionnaireResult!=null)
                                {
                                    foreach (var item in callRecord.QuestionnaireResult)
                                    {
                                        ////服务过程满意度
                                        //if (item.QuestionId == _options.Value.QuestionIdOne)
                                        //{
                                        //    if (item.QuestionResult == "满意")
                                        //    {
                                        //        orgHandledAttitude = new Kv() { Key="4", Value="满意" };
                                        //    }
                                        //    else
                                        //    {
                                        //        orgHandledAttitude = new Kv() { Key = "2", Value = "不满意" };

                                        //    }
                                        //}
                                        ////是否联系
                                        //if (item.QuestionId == QuestionIdZero)
                                        //{
                                        //    if (item.QuestionResult == "有联系")
                                        //    {
                                        //        isContact = true;
                                        //    }
                                        //    else if (item.QuestionResult == "没有联系")
                                        //    {
                                        //        isContact = false;
                                        //    }
                                        //}
                                        ////是否解决
                                        //if (item.QuestionId == QuestionIdOne)
                                        //{
                                        //    if (item.QuestionResult == "得到解决")
                                        //    {
                                        //        isSolve = true;
                                        //    }
                                        //    else if (item.QuestionResult == "未得到解决")
                                        //    {
                                        //        isSolve = false;
                                        //    }
                                        //}
                                        //办件结果满意度
                                        if (item.QuestionId == QuestionIdTwo)
                                        {
                                            if (item.QuestionResult == "办件结果满意")
                                            {
                                                orgProcessingResults = new Kv() { Key = "4", Value = "满意" };
                                                isContact = true;
                                                isSolve = true;
                                            }
                                            else if (item.QuestionResult == "办件结果不满意")
                                            {
                                                orgProcessingResults = new Kv() { Key = "2", Value = "不满意" };
                                                isContact = false;
                                                isSolve = false;
                                                visitContent = callRecord.SceneVariable != null ? callRecord.SceneVariable[VisitContentIdOne] : "";
                                            }
                                        }
                                        else
                                        {
                                            aiOrderVisitDetail.OrderVisit.VisitState = Share.Enums.Order.EVisitState.WaitForVisit;
                                        }

                                        ////坐席是否满意
                                        //if (item.QuestionId == QuestionIdThree)
                                        //{
                                        //    if (item.QuestionResult == "满意接电坐席")
                                        //    {
                                        //        seatEvaluate = ESeatEvaluate.Satisfied;
                                        //    }
                                        //    else if (item.QuestionResult == "不满意接电坐席")
                                        //    {
                                        //        seatEvaluate = ESeatEvaluate.NoSatisfied;
                                        //        seatVisitContent = callRecord.SceneVariable != null ? callRecord.SceneVariable[VisitContentIdTwo] : "";
                                        //    }
                                        //}
                                    }
                                }

                                //先处理坐席（因没有坐席回访，所以默认满意）
                                var seatDetail = visitDetail.Where(x => x.VisitTarget == Share.Enums.Order.EVisitTarget.Seat).ToList();
                                seatDetail.ForEach(x =>
                                {
                                    x.VoiceEvaluate = Share.Enums.Order.EVoiceEvaluate.Satisfied;
                                    x.SeatEvaluate = seatEvaluate;
                                    x.VisitContent = seatVisitContent;
                                });

                                //处理结果
                                orgDetail.ForEach(x =>
                                {
                                    //x.OrgHandledAttitude = orgHandledAttitude;
                                    if (orgProcessingResults!=null)
                                    {
                                        x.OrgProcessingResults = orgProcessingResults;
                                    }
                                    x.VisitContent = visitContent;
                                    x.Volved = isSolve;
                                    x.IsContact = isContact;
                                    if (string.IsNullOrEmpty(orgProcessingResults?.Key) ||  orgProcessingResults?.Value == "不满意")
                                    {
                                        //x.OrgNoSatisfiedReason = new List<Kv>() { new Kv() { Key = "7", Value = "未回复" } };
                                        //TODO 记录不满意原因到内容中供人工回访甄别选择不满意原因
                                        if (dto.CallTimes.Value>=1 && orgProcessingResults == null)
                                        {
                                            orgProcessingResults = new Kv() { Key = "0", Value = "默认满意" };
                                            aiOrderVisitDetail.OrderVisit.VisitState = EVisitState.Visited;
                                            aiOrderVisitDetail.OrderVisit.NowEvaluate = orgProcessingResults;
                                            x.VisitContent = "智能回访两次未接默认已回访";
                                            x.Volved = true;
                                            x.IsContact = true;
                                            x.OrgProcessingResults = orgProcessingResults;
                                            seatDetail.ForEach(x =>
                                            {
                                                x.VoiceEvaluate = Share.Enums.Order.EVoiceEvaluate.Satisfied;
                                                x.SeatEvaluate =  ESeatEvaluate.DefaultSatisfied;
                                                x.VisitContent = "智能回访两次未接默认已回访";
                                            });
                                        }
                                        else
                                        {
                                            aiOrderVisitDetail.OrderVisit.VisitState = Share.Enums.Order.EVisitState.AiVisitWaitForVisit;
                                            aiOrderVisitDetail.OrderVisit.IsEffectiveAiVisit = false;
                                        }
                                        
                                    }
                                    else
                                    {
                                        aiOrderVisitDetail.OrderVisit.VisitState = Share.Enums.Order.EVisitState.Visited;
                                        aiOrderVisitDetail.OrderVisit.IsEffectiveAiVisit = true;
                                    }
                                });
                                await _orderVisitDetailRepository.UpdateRangeAsync(seatDetail, HttpContext.RequestAborted);
                                await _orderVisitDetailRepository.UpdateRangeAsync(orgDetail, HttpContext.RequestAborted);

                                //var first = orgProcessingResults; //aiOrderVisitDetail.OrderVisit.OrderVisitDetails.FirstOrDefault(x => x.VisitTarget == EVisitTarget.Org);
                                //处理主表
                                aiOrderVisitDetail.OrderVisit.AiVisitCount++;
                                aiOrderVisitDetail.OrderVisit.VisitTime = DateTime.Now;
                                aiOrderVisitDetail.OrderVisit.RecordUrl = recordUrl;
                                aiOrderVisitDetail.OrderVisit.IsPutThrough = true;
                                aiOrderVisitDetail.OrderVisit.RecordUrl = recordUrl;
                                aiOrderVisitDetail.OrderVisit.VisitType = Share.Enums.Order.EVisitType.ChipVoiceVisit;
                                aiOrderVisitDetail.OrderVisit.AiVisitTime();
                                aiOrderVisitDetail.SentenceList = aiOrderVisitDetail.SentenceList;
                                aiOrderVisitDetail.IsSuccess = true;
                                aiOrderVisitDetail.AiVolved = isSolve;
                                aiOrderVisitDetail.AiIsContact = isContact;
                                aiOrderVisitDetail.AiVolveConent = visitContent;
                                aiOrderVisitDetail.AiSeatEvaluate = seatEvaluate;
                                aiOrderVisitDetail.AiOrgProcessingResults = orgProcessingResults;
                                aiOrderVisitDetail.AiOrgNoSatisfiedReason = visitContent;
                                aiOrderVisitDetail.AiSeatNoSatisfiedReason = seatVisitContent;
                                aiOrderVisitDetail.CallTimes = dto.CallTimes.Value;

                                if (orgProcessingResults != null)
                                {
                                    aiOrderVisitDetail.OrderVisit.NowEvaluate = orgProcessingResults;
                                }

                                //处理是否回访完成
                                await _orderVisitRepository.UpdateAsync(aiOrderVisitDetail.OrderVisit, HttpContext.RequestAborted);

                                //处理Order表
                                if (orgProcessingResults != null && !string.IsNullOrEmpty(orgProcessingResults.Key) && aiOrderVisitDetail.OrderVisit.VisitState == EVisitState.Visited)
                                {
                                    aiOrderVisitDetail.OrderVisit.Order.Visited(orgProcessingResults.Key, orgProcessingResults.Value);
                                    await _orderRepository.UpdateAsync(aiOrderVisitDetail.OrderVisit.Order);

                                    //推省上
                                    var orderDto = _mapper.Map<OrderDto>(aiOrderVisitDetail.OrderVisit.Order);
                                    await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderVisited,
                                    new PublishVisitDto()
                                    {
                                        Order = orderDto,
                                        No = aiOrderVisitDetail.OrderVisit.No,
                                        VisitType = aiOrderVisitDetail.OrderVisit.VisitType,
                                        VisitName = aiOrderVisitDetail.OrderVisit.CreatorName,
                                        VisitTime = aiOrderVisitDetail.OrderVisit.VisitTime,
                                        VisitRemark = string.IsNullOrEmpty(visitContent) ? aiOrderVisitDetail.OrderVisit.NowEvaluate?.Value : visitContent,
                                        AreaCode = aiOrderVisitDetail.OrderVisit.Order.AreaCode!,
                                        SubjectResultSatifyCode = orgProcessingResults.Key,
                                        FirstSatisfactionCode = aiOrderVisitDetail.OrderVisit.Order.FirstVisitResultCode!,
                                        ClientGuid = ""
                                    }, cancellationToken: HttpContext.RequestAborted);

                                    //推门户
                                    await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderVisitedWeb, new PublishVisitAllDto()
                                    {
                                        Id = aiOrderVisitDetail.OrderVisit.Id,
                                        Order = orderDto,
                                        OrderVisitDetails = _mapper.Map<List<VisitDetailDto>>(aiOrderVisitDetail.OrderVisit.OrderVisitDetails),
                                        VisitTime = aiOrderVisitDetail.OrderVisit.VisitTime,
                                        VisitType = aiOrderVisitDetail.OrderVisit.VisitType,
                                        PublishTime = aiOrderVisitDetail.OrderVisit.PublishTime,
                                    }, cancellationToken: HttpContext.RequestAborted);
                                }
                            }
                            else
                            {
                                aiOrderVisitDetail.AiOrderVisitState = (Share.Enums.Ai.EAiOrderVisitState)(dto.TaskStatus); //更新AI子表
                                aiOrderVisit.VisitedFailCount++;
                                //处理回访主表
                                aiOrderVisitDetail.OrderVisit.AiVisitTime();
                                aiOrderVisitDetail.OrderVisit.AiVisitCount++;
                                aiOrderVisitDetail.OrderVisit.IsCanAiVisit = true;
                                aiOrderVisitDetail.OrderVisit.VisitState = EVisitState.WaitForVisit;
                                aiOrderVisitDetail.IsSuccess = false;
                                await _orderVisitRepository.UpdateAsync(aiOrderVisitDetail.OrderVisit, HttpContext.RequestAborted);
                            }
                            //var callRecord = dto.CallRecordList.OrderByDescending(x => x.CallNo).FirstOrDefault(x => x.ReturnVisit == 1);


                            await _aiOrderVisitDetailRepository.UpdateAsync(aiOrderVisitDetail, HttpContext.RequestAborted);
                            if ((aiOrderVisit.VisitedFailCount + aiOrderVisit.VisitedCount) == aiOrderVisit.HasVisitCount)
                            {
                                aiOrderVisit.TaskState = Share.Enums.Ai.EAiOrderVisitTaskState.Ended;
                            }
                            else
                            {
                                aiOrderVisit.TaskState = EAiOrderVisitTaskState.InProgress;
                            }
                            await _aiOrderVisitRepository.UpdateAsync(aiOrderVisit, HttpContext.RequestAborted);
                            #region 注释
                            //处理不满意结果(如果差评没有不满意原因则不能视为回访完成)   --(不满意设置为失效，生成新的人工回访记录)
                            //处理网站通知差评数据
                            //if (aiOrderVisitDetail.OrderVisit.Order.Source == ESource.Hotline && aiOrderVisitDetail.OrderVisit.OrderVisitDetails.Any(x => x.OrgHandledAttitude?.Key == "1" || x.OrgHandledAttitude?.Key == "2" || x.OrgProcessingResults?.Key == "1" || x.OrgProcessingResults?.Key == "2"))
                            //{

                            //    //处理老数据
                            //    aiOrderVisitDetail.OrderVisit.VisitState = EVisitState.None;
                            //    await _orderVisitRepository.UpdateAsync(aiOrderVisitDetail.OrderVisit);
                            //    //推送老数据变更给门户
                            //    await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderVisitedWeb, new PublishVisitAllDto()
                            //    {
                            //        Id = aiOrderVisitDetail.OrderVisit.Id,
                            //        Order = _mapper.Map<OrderDto>(aiOrderVisitDetail.OrderVisit.Order),
                            //        OrderVisitDetails = _mapper.Map<List<VisitDetailDto>>(aiOrderVisitDetail.OrderVisit.OrderVisitDetails),
                            //        VisitTime = aiOrderVisitDetail.OrderVisit.VisitTime,
                            //        VisitType = aiOrderVisitDetail.OrderVisit.VisitType,
                            //        VisitState = aiOrderVisitDetail.OrderVisit.VisitState,
                            //        PublishTime = aiOrderVisitDetail.OrderVisit.PublishTime,
                            //    }, cancellationToken: HttpContext.RequestAborted);

                            //    //包含不满意数据，重新生成新的回访
                            //    var newOrderVisit = _mapper.Map<OrderVisit>(aiOrderVisitDetail.OrderVisit);
                            //    newOrderVisit.InitId();
                            //    newOrderVisit.VisitState = EVisitState.NoSatisfiedWaitForVisit;
                            //    newOrderVisit.VisitTime = null;
                            //    newOrderVisit.IsCanHandle = false;
                            //    newOrderVisit.IsCanAiVisit = false;
                            //    newOrderVisit.AiVisitCount = 0;
                            //    await _orderVisitRepository.AddAsync(newOrderVisit, HttpContext.RequestAborted);
                            //    var visitDetail = _orderVisitDetailRepository.Queryable().Where(x => x.VisitId == aiOrderVisitDetail.OrderVisit.Id);
                            //    var list = _mapper.Map<List<OrderVisitDetail>>(visitDetail);
                            //    list.ForEach(x =>
                            //    {
                            //        x.VisitId = newOrderVisit.Id;
                            //        x.VoiceEvaluate = null;
                            //        x.VoiceEvaluate = null;
                            //        x.OrgHandledAttitude = null;
                            //        x.OrgNoSatisfiedReason = null;
                            //        x.OrgProcessingResults = null;
                            //        x.VisitContent = "";
                            //    });
                            //    await _orderVisitDetailRepository.AddRangeAsync(list, HttpContext.RequestAborted);

                            //    //推送新数据给门户
                            //    await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderVisitedWeb, new PublishVisitAllDto()
                            //    {
                            //        Id = newOrderVisit.Id,
                            //        Order = _mapper.Map<OrderDto>(aiOrderVisitDetail.OrderVisit.Order),
                            //        OrderVisitDetails = _mapper.Map<List<VisitDetailDto>>(list),
                            //        VisitTime = newOrderVisit.VisitTime,
                            //        VisitType = newOrderVisit.VisitType,
                            //        VisitState = newOrderVisit.VisitState,
                            //        PublishTime = newOrderVisit.PublishTime,
                            //    }, cancellationToken: HttpContext.RequestAborted);
                            //}
                            //else
                            //{
                            #endregion
                            if (aiOrderVisitDetail.OrderVisit.VisitState == EVisitState.Visited)
                            {
                                //写入质检
                                await _qualityApplication.AddQualityAsync(EQualitySource.Visit, aiOrderVisitDetail.OrderVisit.Order.Id, aiOrderVisitDetail.OrderVisit.Id,
                                    HttpContext.RequestAborted);
                            }
                            //}
                        }
                    }
                    else
                    {
                        //失败
                        var aiOrderVisitDetail = aiOrderVisit.AiOrderVisitDetails.FirstOrDefault(x => x.TaskUid == dto.TaskUid);
                        if (aiOrderVisitDetail!=null)
                        {
                            aiOrderVisitDetail.AiOrderVisitState = (EAiOrderVisitState)dto.TaskStatus;
                            await _aiOrderVisitDetailRepository.UpdateAsync(aiOrderVisitDetail, HttpContext.RequestAborted);
                        }
                    }
                }
            }
            //批量外呼
            else if(dto.SceneUid == CallOutSceneUid)
            {
                var callOut = await _callOutTaskRepository.Queryable()
                    .Includes(x => x.CallOutTaskDetails)
                    .FirstAsync(x => x.BatchUid == dto.BatchUid);
                if (callOut != null)
                {
                    var aicallOutDetail = callOut.CallOutTaskDetails.FirstOrDefault(x => x.TaskUid == dto.TaskUid);
                    if (aicallOutDetail != null)
                    {
                        if (dto.TaskStatus == 6)
                        {
                            var callRecord = dto.CallRecordList.OrderBy(x => x.CallNo).LastOrDefault();
                            if (callRecord!=null)
                            {
                                aicallOutDetail.IsSuccess = true;
                                aicallOutDetail.AiCallOutState = Share.Enums.Ai.EAiCallOutState.Ended; //更新AI子表
                                aicallOutDetail.CallOutTime = DateTime.Now;
                                callOut.VisitedCount++;
                            }
                            else
                            {
                                aicallOutDetail.IsSuccess = false;
                                aicallOutDetail.AiCallOutState = (EAiCallOutState)dto.TaskStatus;
                                aicallOutDetail.CallOutTime = DateTime.Now;
                                callOut.VisitedFailCount++;
                            }

                        }
                        else
                        {
                            aicallOutDetail.IsSuccess = false;
                            aicallOutDetail.AiCallOutState = (EAiCallOutState)dto.TaskStatus;
                            aicallOutDetail.CallOutTime = DateTime.Now;
                            callOut.VisitedFailCount++;
                        }
                        if ((callOut.VisitedFailCount + callOut.VisitedCount) == callOut.HasVisitCount)
                        {
                            callOut.AiCallOutTaskState = EAiCallOutTaskState.Ended;
                        }
                        else
                        {
                            callOut.AiCallOutTaskState = EAiCallOutTaskState.InProgress;
                        }
                        await _callOutTaskRepository.UpdateAsync(callOut,HttpContext.RequestAborted);
                        await _callOutTaskDetailRepository.UpdateAsync(aicallOutDetail,HttpContext.RequestAborted);
                    }
                }
            }
            else
            {

            }

            
        }

        /// <summary>
        /// 智能回访列表
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpGet("aivisit/aivisit-list")]
        public async Task<PagedDto<AiOrderVisitDto>> AiVisitList([FromQuery]AiVisitListDto dto)
        {
            var query = _aiOrderVisitApplication.QuerysAiOrderVisit(dto);
            var (total, items) = await query
                .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
            return new PagedDto<AiOrderVisitDto>(total, _mapper.Map<IReadOnlyList<AiOrderVisitDto>>(items)); 
        }

        /// <summary>
        /// 智能回访任务导出
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPost("aivisit/taskexport")]
        public async Task<FileStreamResult> ExportAiOrderVisit([FromBody]ExportExcelDto<AiVisitListDto> dto)
        {
            var query = _aiOrderVisitApplication.QuerysAiOrderVisit(dto.QueryDto);
            List<AiOrderVisit> aiOrderVisits;
            if (dto.IsExportAll)
            {
                aiOrderVisits = await query.ToListAsync(HttpContext.RequestAborted);
            }
            else
            {
                var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted);
                aiOrderVisits = items;
            }

            var aiOrderVisitDtos = _mapper.Map<ICollection<AiOrderVisitDto>>(aiOrderVisits);

            dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass<AiOrderVisitDto>(dto.ColumnInfos);

            var dtos = aiOrderVisitDtos
                .Select(stu => _mapper.Map(stu, typeof(AiOrderVisitDto), dynamicClass))
                .Cast<object>()
                .ToList();
            var stream = ExcelHelper.CreateStream(dtos);

            return ExcelStreamResult(stream, "智能回访任务");
        }
        /// <summary>
        /// 智能回访明细
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpGet("aivisit/aivisitdetail-list")]
        public async Task<PagedDto<AiOrderVisitDetailDto>> AiVisitDetailList([FromQuery]AiVisitDetailListDto dto)
        {
            var query = _aiOrderVisitApplication.QueryAiOrderVisitDetail(dto);
            var (total,items) =await query.ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
            return new PagedDto<AiOrderVisitDetailDto>(total, _mapper.Map<IReadOnlyList<AiOrderVisitDetailDto>>(items));
        }

        /// <summary>
        /// 智能回访明细导出
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPost("aivisit/taskdetailexport")]
        public async Task<FileStreamResult> ExportAiOrderVisitDetail([FromBody]ExportExcelDto<AiVisitDetailListDto> dto)
        {
            var query = _aiOrderVisitApplication.QueryAiOrderVisitDetail(dto.QueryDto);
            List<AiOrderVisitDetail> aiOrderVisits;
            if (dto.IsExportAll)
            {
                aiOrderVisits = await query.ToListAsync(HttpContext.RequestAborted);
            }
            else
            {
                var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted);
                aiOrderVisits = items;
            }

            var aiOrderVisitDetailDtos = _mapper.Map<ICollection<AiOrderVisitDetailDto>>(aiOrderVisits);

            dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass<AiOrderVisitDetailDto>(dto.ColumnInfos);

            var dtos = aiOrderVisitDetailDtos
                .Select(stu => _mapper.Map(stu, typeof(AiOrderVisitDetailDto), dynamicClass))
                .Cast<object>()
                .ToList();
            var stream = ExcelHelper.CreateStream(dtos);

            return ExcelStreamResult(stream, "智能回访明细");
        }

        /// <summary>
        /// 可进行智能回访记录 
        /// </summary>
        /// <returns></returns>
        [HttpGet("aivisit/canaivisit-list")]
        public async Task<IReadOnlyList<OrderVisitDto>> CanAiVisitList([FromQuery]CanAiVisitListDto dto)
        {
            var items= await _orderVisitRepository.Queryable()
                .Includes(x=>x.Order)
                .Where(x => x.VisitState == Share.Enums.Order.EVisitState.WaitForVisit && x.IsCanAiVisit == true && x.EmployeeId == _sessionContext.RequiredUserId)
                .WhereIF(!string.IsNullOrEmpty(dto.Hotspot), d => d.Order.HotspotSpliceName != null && d.Order.HotspotSpliceName.Contains(dto.Hotspot))//热点类型
                .WhereIF(!string.IsNullOrEmpty(dto.AcceptType), d => d.Order.AcceptTypeCode == dto.AcceptType)//受理类型
                .WhereIF(!string.IsNullOrEmpty(dto.No), x => x.No.Contains(dto.No)) //工单编码
                .WhereIF(!string.IsNullOrEmpty(dto.Title),x=> x.Order.Title.Contains(dto.Title))
                .Where(x=> !string.IsNullOrEmpty(x.Order.Contact) && SqlFunc.Length(x.Order.Contact)==11 && !x.Order.Contact.Contains("*"))
                .Where(x=> x.Order.IsUrgent !=true )
                .Where(x=> x.Order.IdentityType!= EIdentityType.Enterprise)
                .ToListAsync();
            return _mapper.Map<IReadOnlyList<OrderVisitDto>>(items);
        }

        /// <summary>
        /// 任务页面基础数据
        /// </summary>
        /// <returns></returns>
        [HttpGet("aivisit/taskbase-data")]
        public async Task<object> AiVisitTaskBaseData()
        {
            var rsp = new
            {
                AiOrderVisitTaskState = EnumExts.GetDescriptions<EAiOrderVisitTaskState>(),
                AiOrderVisitState = EnumExts.GetDescriptions<EAiOrderVisitState>()
            };
            return rsp;
        }


        /// <summary>
        /// 页面基础数据
        /// </summary>
        /// <returns></returns>
        [HttpGet("aivisit/base-data")]
        public async Task<object> BaseData()
        {
            var rsp = new
            {
                AcceptTypeOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.AcceptType),
            };
            return rsp;
        }
        

        /// <summary>
        /// 新增智能回访任务
        /// </summary>
        /// <returns></returns>
        [HttpPost("aivisit/add-aivisit")]
        public async Task AddAiVisit([FromBody]AddAiVisitDto dto)
        {
            //验证是否有重复电话
            //有重复电话自动排除
            dto.AiOrderVisitDetails = dto.AiOrderVisitDetails.DistinctBy(x => x.OuterNo.Trim()).ToList() ;
            //if (dto.AiOrderVisitDetails.DistinctBy(x=>x.OuterNo.Trim()).Count() != dto.AiOrderVisitDetails.Count)
            //{
            //    throw UserFriendlyException.SameMessage("任务中存在重复外呼号码，请检查后重新提交");
            //}

            var model = _mapper.Map<AiOrderVisit>(dto);

            var detaillist = _mapper.Map<List<AiOrderVisitDetail>>(dto.AiOrderVisitDetails);

            model.TaskState = Share.Enums.Ai.EAiOrderVisitTaskState.NoStarted;
            model.RuleType = 2;
            model.HasVisitCount = dto.AiOrderVisitDetails.Count;
            model.VisitedCount = 0;
            model.VisitedFailCount = 0;
            var id = await _aiOrderVisitRepository.AddAsync(model, HttpContext.RequestAborted);

            detaillist.ForEach(x =>
            {
                x.AiOrderVisitId = id;
                x.AiOrderVisitState = Share.Enums.Ai.EAiOrderVisitState.InProgress;
            });
            await _aiOrderVisitDetailRepository.AddRangeAsync(detaillist, HttpContext.RequestAborted);
            
            //推送任务
            //准备原始数据
            var pushModel = await _aiOrderVisitRepository.Queryable()
                .Includes(x => x.AiOrderVisitDetails, s => s.Order)
                .Includes(x => x.AiOrderVisitDetails, s => s.OrderVisit, q => q.OrderVisitDetails)
                .FirstAsync(x => x.Id == id);

            #region 获取系统设置
            var sceneuid = _systemSettingCacheManager.GetSetting(SettingConstants.VisitSceneUid)?.SettingValue[0];
            var ruleuId = _systemSettingCacheManager.GetSetting(SettingConstants.VisitRuleUid)?.SettingValue[0];
            var visitFromNameKey = _systemSettingCacheManager.GetSetting(SettingConstants.VisitFromNameKey)?.SettingValue[0];
            var visitFromGenderKey = _systemSettingCacheManager.GetSetting(SettingConstants.VisitFromGenderKey)?.SettingValue[0];
            var visitCreationTimeKey = _systemSettingCacheManager.GetSetting(SettingConstants.VisitCreationTimeKey)?.SettingValue[0];
            var visitOrderTitleKey = _systemSettingCacheManager.GetSetting(SettingConstants.VisitOrderTitleKey)?.SettingValue[0];
            var visitIsCallOrderKey = _systemSettingCacheManager.GetSetting(SettingConstants.VisitIsCallOrder)?.SettingValue[0];
            #endregion

            var newModel = await _aiVisitService.CreateAiOrderVisitTask(pushModel, sceneuid, ruleuId, visitFromNameKey, visitFromGenderKey, visitCreationTimeKey, visitOrderTitleKey, visitIsCallOrderKey, HttpContext.RequestAborted);

            if (!string.IsNullOrEmpty(newModel.BatchUid))
            {
                //修改回访主表
                await _orderVisitRepository.Updateable()
                   .SetColumns(x => x.IsCanAiVisit == false)
                   .SetColumns(x => x.VisitState == EVisitState.AiVisiting)
                   .Where(x => detaillist.Select(s => s.OrderVisitId).Contains(x.Id)).ExecuteCommandAsync(HttpContext.RequestAborted);
            }
            else
            {
                newModel.TaskState = Share.Enums.Ai.EAiOrderVisitTaskState.Ended;
            }
            await _aiOrderVisitRepository.UpdateAsync(newModel, HttpContext.RequestAborted);
            await _aiOrderVisitDetailRepository.UpdateRangeAsync(newModel.AiOrderVisitDetails, HttpContext.RequestAborted);
        }

        #endregion


        
    }
}
