using DotNetCore.CAP;
using Hotline.Caching.Interfaces;
using Hotline.Share.Dtos.Order;
using Hotline.Share.Enums.Order;
using MapsterMapper;
using Microsoft.Extensions.Logging;
using XF.Domain.Authentications;
using XF.Domain.Cache;
using XF.Domain.Dependency;
using XF.Domain.Exceptions;
using XF.Domain.Repository;
using Hotline.CallCenter.Calls;
using Hotline.File;
using Hotline.FlowEngine.Workflows;
using Hotline.Schedulings;
using Hotline.SeedData;
using Hotline.Users;
using Hotline.Share.Dtos;
using Hotline.Settings.Hotspots;
using Hotline.Share.Dtos.FlowEngine;
using Microsoft.AspNetCore.Http;
using Hotline.Settings;
using SqlSugar;
using Hotline.Push.Notifies;
using Hotline.Share.Enums.Push;
using MediatR;
using Hotline.Authentications;
using Hotline.ContingencyManagement.Notifies;
using Hotline.EventBus;
using Hotline.Share.Enums.FlowEngine;
using Mapster;
using Microsoft.AspNetCore.Builder.Extensions;
using Hotline.Configurations;
using Microsoft.Extensions.Options;
using Hotline.Share.Tools;

namespace Hotline.Orders;

public class OrderDomainService : IOrderDomainService, IScopeDependency
{
    private readonly IOrderRepository _orderRepository;
    private readonly IRepository<OrderRedo> _orderRedoRepository;
    private readonly IRepository<OrderPublish> _orderPublishRepository;
    private readonly IRepository<OrderVisit> _orderVisitRepository;
    private readonly IRepository<OrderExtension> _orderExtensionRepository;
    private readonly IRepository<OrderComplement> _orderComplementRepository;
    private readonly ITypedCache<CacheOrderNO> _cacheOrderNo;
    private readonly ISessionContext _sessionContext;
    private readonly ICapPublisher _capPublisher;
    private readonly IRepository<OrderVisitDetail> _orderVisitDetailRepository;
    private readonly IMapper _mapper;
    private readonly ILogger<OrderDomainService> _logger;
    private readonly IFileRepository _fileRepository;
    private readonly IRepository<Scheduling> _schedulingRepository;
    private readonly Publisher _publisher;
    private readonly IOptionsSnapshot<AppConfiguration> _appOptions;
    private readonly IRepository<User> _userRepository;
    private readonly ISystemSettingCacheManager _systemSettingCacheManager;
    private readonly IWorkflowDomainService _workflowDomainService;
    private readonly IRepository<Hotspot> _hotspotRepository;
    private readonly IMediator _mediator;
    private readonly IRepository<WorkflowStep> _workflowStepRepository;
    private readonly ISystemLogRepository _systemLogRepository;

    public OrderDomainService(
        IOrderRepository orderRepository,
        IRepository<OrderRedo> orderRedoRepository,
        IRepository<OrderPublish> orderPublishRepository,
        IRepository<OrderVisit> orderVisitRepository,
        IRepository<OrderExtension> orderExtensionRepository,
        IRepository<OrderComplement> orderComplementRepository,
        ITypedCache<CacheOrderNO> cacheOrderNo,
        ISessionContext sessionContext,
        ICapPublisher capPublisher,
        IMapper mapper,
        ILogger<OrderDomainService> logger,
        IFileRepository fileRepository,
        IRepository<WexCallRecord> wexCallRecordRepository,
        IRepository<User> userRepository,
        ISystemSettingCacheManager systemSettingCacheManager,
        IRepository<Scheduling> schedulingRepository,
        IWorkflowDomainService workflowDomainService,
        IRepository<Hotspot> hotspotRepository,
        IMediator mediator,
        Publisher publisher,
        IRepository<OrderVisitDetail> orderVisitDetailRepository,
        IRepository<WorkflowStep> workflowStepRepository,
        ISystemLogRepository systemLogRepository,
        IOptionsSnapshot<AppConfiguration> appOptions)
    {
        _orderRepository = orderRepository;
        _orderRedoRepository = orderRedoRepository;
        _orderPublishRepository = orderPublishRepository;
        _orderVisitRepository = orderVisitRepository;
        _orderExtensionRepository = orderExtensionRepository;
        _orderComplementRepository = orderComplementRepository;
        _cacheOrderNo = cacheOrderNo;
        _sessionContext = sessionContext;
        _capPublisher = capPublisher;
        _mapper = mapper;
        _logger = logger;
        _fileRepository = fileRepository;
        _userRepository = userRepository;
        _schedulingRepository = schedulingRepository;
        _systemSettingCacheManager = systemSettingCacheManager;
        _workflowDomainService = workflowDomainService;
        _hotspotRepository = hotspotRepository;
        _mediator = mediator;
        _publisher = publisher;
        _orderVisitDetailRepository = orderVisitDetailRepository;
        _workflowStepRepository = workflowStepRepository;
        _systemLogRepository = systemLogRepository;
        _appOptions = appOptions;
    }

    /// <summary>
    /// 归档后自动发布
    /// </summary>
    /// <param name="order"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    public async Task OrderAutomaticPublishAsync(Order order, CancellationToken cancellationToken)
    {
        var name = "中心直办件归档后默认自动发布";
        try
        {
            if (_systemSettingCacheManager.AutomaticPublishOrder == false)
            {
                return;
            }
            var checkResult = order.AutoPublishCheck();
            if (checkResult.NotNullOrEmpty())
            {
                await _systemLogRepository.AddAsync(name, order.Id, checkResult);
                return;
            }

            if (order.ProcessType != EProcessType.Zhiban)
            {
                await _systemLogRepository.AddAsync(name, order.Id, "非中心直办件");
                return;
            }

            await OrderPublishAsync(order, cancellationToken);
        }
        catch (Exception e)
        {
            await _systemLogRepository.AddAsync(name, order.Id, $"系统异常: {e.Message}");
        }
    }

    public async Task OrderPublishAsync(Order order, CancellationToken cancellationToken)
    {
        OrderPublish orderPublish = new()
        {
            OrderId = order.Id,
            No = order.No,
            PublishState = false, //当前写死为false
            ArrangeTitle = order.Title,
            ArrangeContent = order.Content,
            ArrangeOpinion = order.FileOpinion,
            ProPublishState = false,
            FeedBackPhone = order.Contact,
            CreatorName = _sessionContext.UserName
        };
        await _orderPublishRepository.AddAsync(orderPublish, cancellationToken);
        order.Publish(orderPublish.PublishState);
        await _orderRepository.UpdateAsync(order, cancellationToken);
        //推省上
        var publishPublishOrder = orderPublish.Adapt<PublishPublishOrderDto>();
        publishPublishOrder.Order = order.Adapt<OrderDto>();
        //查询实际办理附件
        if (!string.IsNullOrEmpty(order.ActualHandleStepId))
        {
            var actualHandleStep = await _workflowStepRepository.GetAsync(order.ActualHandleStepId, cancellationToken);
            publishPublishOrder.FileJsons = actualHandleStep?.FileJson;
        }

        await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderPublishOrder, publishPublishOrder, cancellationToken: cancellationToken);

        //推应急管理局
        //是否开启
        var isOpenContingencyManagement =
            _systemSettingCacheManager.GetSetting(SettingConstants.IsOpenContingencyManagement)?.SettingValue[0];
        if (isOpenContingencyManagement == "true")
            await _publisher.PublishAsync(new ContingencyManagementNotify(order, order.Title, order.Content, order.ActualOpinion),
                PublishStrategy.ParallelWhenAll, cancellationToken);

        // 取消发布的工单数量
        var orderPublishDeletedCount = await _orderPublishRepository.Queryable(includeDeleted: true)
            .Where(m => m.OrderId == order.Id && m.IsDeleted == true)
            .CountAsync(cancellationToken);
        var orderVisitVisitedCount = await _orderVisitRepository.Queryable()
            .Where(m => m.OrderId == order.Id && m.VisitState == EVisitState.Visited)
            .CountAsync(cancellationToken);

        // 若取消发布的工单，已经被回访过了，没有经过重新办理，再次发布后，自动跳过回访环节，展示取消发布前的回访结果
        if (orderPublishDeletedCount != 0 && orderVisitVisitedCount !=0)
        {
            return;
        }
        var orderVisit = new OrderVisit
        {
            No = order.No,
            OrderId = order.Id,
            VisitState = EVisitState.WaitForVisit,
            PublishTime = DateTime.Now,
            IsCanHandle = true,
            EmployeeId = _sessionContext.RequiredUserId
        };
        if (!order.IsProvince)
        {
            orderVisit.EmployeeId = _sessionContext.RequiredUserId;
        }

        if (_appOptions.Value.IsZiGong)
        {
            orderVisit.EmployeeId = string.Empty;
        }

        if (order is { ProcessType: EProcessType.Zhiban, CounterSignType: null } && !order.IsProvince)
        {
            orderVisit.VisitState = EVisitState.Visited;
            orderVisit.VisitTime = DateTime.Now;
            orderVisit.VisitType = EVisitType.OtherVisit;
            orderVisit.NowEvaluate = new Kv() { Key = "4", Value = "满意" };
            if (_appOptions.Value.IsZiGong)
            {
                // 根据禅道 自贡需求 Id_361, 第一条, 3小条需求;
                // 直办件归档后自动回访量需统计在“胡玲”的默认回访量中;
                orderVisit.EmployeeId = _systemSettingCacheManager.DefaultVisitEmployeeId;
            }
        }

        if (order.CounterSignType != ECounterSignType.Center)
        {
            orderVisit.IsCanAiVisit = true;
        }

        string visitId = await _orderVisitRepository.AddAsync(orderVisit);

        //新增回访信息
        var visitedDetail = new List<OrderVisitDetail>();

        var seatDetail = new OrderVisitDetail();
        seatDetail.VisitId = visitId;
        seatDetail.VisitTarget = EVisitTarget.Seat;


        var orgDetail = new OrderVisitDetail();
        orgDetail.VisitId = visitId;
        orgDetail.VisitOrgCode = order.ActualHandleOrgCode;
        orgDetail.VisitOrgName = order.ActualHandleOrgName;
        orgDetail.VisitTarget = EVisitTarget.Org;
        if (order is { ProcessType: EProcessType.Zhiban, CounterSignType: null, IsProvince: false })
        {
            var satisfy = new Kv() { Key = "4", Value = "满意" };
            orgDetail.OrgProcessingResults = satisfy;
            //orgDetail.OrgHandledAttitude = satisfy;
        }

        visitedDetail.Add(orgDetail);

        if (order is { ProcessType: EProcessType.Zhiban, CounterSignType: null })
        {
            seatDetail.VoiceEvaluate = EVoiceEvaluate.Satisfied;
            seatDetail.SeatEvaluate = ESeatEvaluate.Satisfied;
            order.Visited("4", "满意");
            order.Status = EOrderStatus.Visited;
            await _orderRepository.UpdateAsync(order, cancellationToken);
        }

        visitedDetail.Add(seatDetail);
        await _orderVisitDetailRepository.AddRangeAsync(visitedDetail, cancellationToken);


        if (order.IsProvince == false && orderVisit.VisitState == EVisitState.Visited)
        {
            //推省上
            await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderVisited,
                new PublishVisitDto()
                {
                    Order = order.Adapt<OrderDto>(),
                    No = orderVisit.No,
                    VisitType = orderVisit.VisitType,
                    VisitName = orderVisit.CreatorName,
                    VisitTime = orderVisit.VisitTime,
                    VisitRemark = orderVisit.NowEvaluate?.Value,
                    AreaCode = order.AreaCode!,
                    SubjectResultSatifyCode = orderVisit.NowEvaluate?.Key,
                    FirstSatisfactionCode = orderVisit.NowEvaluate?.Key,
                    ClientGuid = ""
                }, cancellationToken: cancellationToken);
        }

        //推门户
        await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderVisitedWeb, new PublishVisitAllDto()
        {
            Id = orderVisit.Id,
            Order = order.Adapt<OrderDto>(),
            OrderVisitDetails = orderVisit.OrderVisitDetails.Adapt<List<VisitDetailDto>>(),
            VisitName = _sessionContext.UserName,
            VisitTime = orderVisit.VisitTime,
            VisitType = orderVisit.VisitType,
            VisitState = orderVisit.VisitState,
            PublishTime = orderVisit.PublishTime,
        }, cancellationToken: cancellationToken);
    }

    /// <summary>
    /// 重办和退回工单时如果有取消发布的工单, 清除回访待办和回访列表中的数据
    /// </summary>
    /// <param name="orderId"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    public async Task VisitNoneByCancelPublishAsync(string orderId, CancellationToken cancellationToken)
    {
        var cancelPublishOrderEnabled = _systemSettingCacheManager.CancelPublishOrderEnabled;

        // 取消发布的工单数量
        var orderPublishDeletedCount = await _orderPublishRepository.Queryable(includeDeleted: true)
            .Where(m => m.OrderId == orderId && m.IsDeleted == true)
            .CountAsync(cancellationToken);

        if (orderPublishDeletedCount == 0 || cancelPublishOrderEnabled == false) return;

        var visit = await _orderVisitRepository.GetAsync(x => x.OrderId == orderId && x.VisitState != EVisitState.None, cancellationToken);
        if (visit != null)
        {
            visit.VisitState = EVisitState.None;
            await _orderVisitRepository.UpdateAsync(visit, cancellationToken);
        }
    }

    public async Task<Order> GetOrderAsync(string? orderId, bool withHotspot = false, bool withAcceptor = false,
        bool withExtension = false, CancellationToken cancellationToken = default)
    {
        if (string.IsNullOrEmpty(orderId))
            throw UserFriendlyException.SameMessage("无效工单编号");

        var query = _orderRepository.Queryable();
        if (withHotspot)
            query = query.Includes(d => d.Hotspot);
        if (withAcceptor)
            query = query.Includes(d => d.Acceptor);
        if (withExtension)
            query = query.Includes(d => d.OrderExtension);

        var order = await query.FirstAsync(d => d.Id == orderId, cancellationToken);
        if (order == null)
            throw new UserFriendlyException($"无效工单编号, orderId: {orderId}", "无效工单编号");
        return order;
    }

    public async Task<string> AddAsync(Order order, bool autoAccept = false, CancellationToken cancellationToken = default)
    {
        if (autoAccept)
        {
            order.AutoAccept(_sessionContext.RequiredUserId, _sessionContext.UserName, _sessionContext.StaffNo);
            order.Sign(_sessionContext.RequiredUserId, _sessionContext.UserName);
        }
        order.Init();
        order.No = GenerateNewOrderNo();
        order.Password = Random.Shared.Next(100000, 1000000).ToString();
        order.ProvinceNo = string.IsNullOrEmpty(order.ProvinceNo) ? GenerateNewProvinceNo(order.No, order.SourceChannelCode) : order.ProvinceNo;
        return await _orderRepository.AddOrderNavAsync(order, cancellationToken);
    }

    /// <summary>
    /// 撤回或跳转前处理数据及校验
    /// <remarks>
    ///工单撤回时需校验工单当前是否存在待发布记录、待回访记录，若存在需删除对应记录（跳转同理）
    ///工单撤回时需校验工单是否存在甄别中记录，若存在不允许撤回当前工单（跳转同理）
    /// </remarks>
    /// </summary>
    public async Task ReadyToRecallAsync(string orderId, CancellationToken cancellationToken)
    {
        var order = await _orderRepository.Queryable()
            .Includes(d => d.OrderPublish)
            .Includes(d => d.OrderVisits.Where(d => d.VisitState == EVisitState.WaitForVisit))
            .Includes(d => d.OrderScreens)
            .FirstAsync(d => d.Id == orderId, cancellationToken);

        if (order.OrderScreens.Any())
            throw UserFriendlyException.SameMessage("已甄别工单无法撤回或跳转");

        //todo 需求调整：P72， 4，5，6，7，8，9，10

        if (order.OrderPublish is not null)
            await _orderPublishRepository.RemoveAsync(order.OrderPublish, cancellationToken: cancellationToken);

        if (order.OrderVisits.Any())
            await _orderVisitRepository.RemoveNav(order.OrderVisits)
                .Include(d => d.OrderVisitDetails)
                .ExecuteCommandAsync();
    }

    public Task<string> AddOrderRedoAsync(OrderRedo orderRedo, CancellationToken cancellationToken) =>
        _orderRedoRepository.AddAsync(orderRedo, cancellationToken);

    public Task RemoveOrderRedoAsync(string id, CancellationToken cancellationToken) =>
        _orderRedoRepository.RemoveAsync(id, cancellationToken: cancellationToken);

    public Task UpdateOrderRedoAsync(OrderRedo orderRedo, CancellationToken cancellationToken) =>
        _orderRedoRepository.UpdateAsync(orderRedo, cancellationToken);

    #region 工单扩展信息

    public async Task<OrderExtension?> GetOrderExtensionsAsync(string provinceNo, CancellationToken cancellationToken) =>
        await _orderExtensionRepository.GetAsync(d => d.ProvinceNo == provinceNo, cancellationToken);

    public Task UpdateExtensionAsync(OrderExtension orderExtension, CancellationToken cancellationToken) =>
        _orderExtensionRepository.UpdateAsync(orderExtension, cancellationToken);


    /// <summary>
    /// 新增工单扩展信息
    /// </summary>
    public async Task AddExtensionAsync(OrderExtension extension, CancellationToken cancellationToken) =>
        await _orderExtensionRepository.AddAsync(extension, cancellationToken);

    /// <summary>
    /// 新增工单补充信息
    /// </summary>
    public async Task<string> AddOrderComplementAsync(AddOrderComplementDto dto, CancellationToken cancellationToken)
    {
        var complement = _mapper.Map<OrderComplement>(dto);
        complement.InitId();
        if (dto.Files.Any()) complement.FileJson = await _fileRepository.AddFileAsync(dto.Files, complement.Id, "", cancellationToken);
        return await _orderComplementRepository.AddAsync(complement, cancellationToken);
    }


    #endregion

    /// <summary>
    /// 验证是否是管理员
    /// </summary>
    /// <returns></returns>
    public bool IsCheckAdmin()
    {
        var systemAdministrator = _systemSettingCacheManager.GetSetting(SettingConstants.SystemAdministrator)?.SettingValue[0];
        if (!string.IsNullOrEmpty(systemAdministrator) && (_sessionContext.Roles.Contains(systemAdministrator) || _sessionContext.Roles.Contains(RoleSeedData.AdminRole)))
            return true;
        else
            return false;
    }



    #region 平均派单
    /// <summary>
    /// 平均派单
    /// </summary>
    /// <returns></returns>
    public async Task<FlowStepHandler> AverageOrder(CancellationToken cancellationToken)
    {
        var time = DateTime.Parse(DateTime.Now.ToString("yyyy-MM-dd"));
        var scheduling = await _schedulingRepository.Queryable().Includes(x => x.SchedulingUser)
            .Where(x => x.SchedulingTime == time && x.WorkingTime <= DateTime.Now.TimeOfDay && x.OffDutyTime >= DateTime.Now.TimeOfDay && x.AtWork == true)
            .OrderBy(x => x.SendOrderNum).FirstAsync(cancellationToken);
        var centerOrgName = _systemSettingCacheManager.GetSetting(SettingConstants.CenterOrgName)?.SettingValue[0];
        if (scheduling is null)
            return new FlowStepHandler
            {
                Key = AppDefaults.SendPoolId,
                Value = "待派单池",
                UserId = AppDefaults.SendPoolId,
                Username = "待派单池",
                OrgId = OrgSeedData.CenterId,
                OrgName = centerOrgName
            };
        scheduling.SendOrderNum++;
        await _schedulingRepository.UpdateAsync(scheduling, cancellationToken);
        var user = scheduling.SchedulingUser;
        return new FlowStepHandler
        {
            Key = user.UserId,
            Value = user.UserName,
            UserId = user.UserId,
            Username = user.UserName,
            OrgId = user.OrgId,
            OrgName = user.OrgIdName
        };
    }

    /// <summary>
    /// 登录平均派单
    /// </summary>
    /// <param name="userId"></param>
    /// <returns></returns>
    public async Task LogAverageOrder(string userId, Scheduling scheduling, CancellationToken cancellationToken)
    {
        //1.获取默认派单员所属的工单
        //2.获取今天上班的人员
        //3.给当前这个用户平均派单

        var steps = await _workflowDomainService.GetStepsBelongsToAsync(AppDefaults.SendPoolId,
            cancellationToken);

        var user = await _userRepository.Queryable()
            .Includes(d => d.Organization)
            .FirstAsync(d => d.Id == userId, cancellationToken);
        var time = DateTime.Parse(DateTime.Now.ToString("yyyy-MM-dd"));
        var schedulings = await _schedulingRepository.Queryable().Includes(x => x.SchedulingUser)
            .Where(x => x.SchedulingTime == time).CountAsync(cancellationToken);
        if (schedulings > 0)
        {
            var sendNum = steps.Count / schedulings;
            scheduling.SendOrderNum += sendNum;
            await _schedulingRepository.Updateable()
                .SetColumns(s => new Scheduling() { SendOrderNum = scheduling.SendOrderNum, AtWork = scheduling.AtWork })
                .Where(s => s.Id == scheduling.Id).ExecuteCommandAsync(cancellationToken);
            if (sendNum <= 0) return;
            var sendSteps = steps.Take(sendNum).ToList();
            await _workflowDomainService.ChangeHandlerBatchAsync(new List<(string userId, string username, string orgId, string orgName, string? roleId, string? roleName, ICollection<WorkflowStep> steps)>
            {
                new(user.Id, user.Name, user.OrgId, user.Organization.Name,null,null, sendSteps)
            }, cancellationToken);
        }

    }

    /// <summary>
    /// 触发平均派单
    /// </summary>
    /// <returns></returns>
    public async Task TriggerAverageOrder(CancellationToken cancellationToken)
    {
        //1.从排班里面获取今天上班的人
        //2.获取默认派单员剩下的工单
        //3.平均分配剩下的工单给今天上班的人
        DateTime time = DateTime.Parse(DateTime.Now.ToString("yyyy-MM-dd"));
        var schedulings = await _schedulingRepository.Queryable().Includes(x => x.SchedulingUser)
            .Where(x => x.SchedulingTime!.Value == time && x.WorkingTime!.Value <= DateTime.Now.TimeOfDay && x.OffDutyTime!.Value >= DateTime.Now.TimeOfDay && x.AtWork == true)
            .OrderBy(x => x.SendOrderNum).ToListAsync(cancellationToken);

        if (schedulings.Any())
        {
            var steps = await _workflowDomainService.GetStepsBelongsToAsync(AppDefaults.SendPoolId,
                cancellationToken);
            if (steps.Any())
            {
                List<(string userId, string username, string orgId, string orgName, string? roleId, string? roleName, ICollection<WorkflowStep> steps)> handlers = new();
                var avg = steps.Count / schedulings.Count;
                var remaining = steps.Count % schedulings.Count;
                var skip = 0;
                for (var i = 0;i < schedulings.Count;i++)
                {
                    var scheduling = schedulings[i];
                    var size = avg + (i < remaining ? 1 : 0);
                    if (size > 0)
                    {
                        handlers.Add(new(
                            scheduling.SchedulingUser.UserId,
                            scheduling.SchedulingUser.UserName,
                            scheduling.SchedulingUser.OrgId,
                            scheduling.SchedulingUser.OrgIdName,
                            null, null,
                            steps.Skip(skip).Take(size).ToList()));
                        skip += size;
                        scheduling.SendOrderNum += size;
                        await _schedulingRepository.Updateable()
                            .SetColumns(s => new Scheduling() { SendOrderNum = scheduling.SendOrderNum })
                            .Where(s => s.Id == scheduling.Id).ExecuteCommandAsync(cancellationToken);
                    }
                }
                if (handlers.Any())
                    await _workflowDomainService.ChangeHandlerBatchAsync(handlers, cancellationToken);
            }
        }
    }
    #endregion

    #region  工单校验- 交通类工单

    /// <summary>
    /// 工单校验  - 交通类工单
    /// </summary>
    /// <returns></returns>
    public async Task<OrderValidation> OrderValidation(AddOrderDto dto, CancellationToken cancellationToken)
    {
        var valid = new OrderValidation { Validation = false, Result = "" };
        var hotspot = await _hotspotRepository.GetAsync(dto.HotspotId, cancellationToken);
        if (hotspot.TrunkNum.Equals(AppDefaults.TrafficTrunkNum))
        {
            switch (dto.AcceptTypeCode)
            {
                //投诉举报
                case "30":
                case "35":
                    valid.Validation = dto.Title.Contains("意见") || dto.Title.Contains("建议") || dto.Title.Contains("咨询")
                        || dto.Content.Contains("意见") || dto.Content.Contains("建议") || dto.Content.Contains("咨询");
                    if (dto.Content.Length < 25)
                    {
                        valid.Validation = true;
                        valid.Result = "保存失败，受理内容字数不足,需要至少25个字!";
                    }
                    break;
                // 意见
                case "1":
                    valid.Validation = dto.Title.Contains("投诉") || dto.Title.Contains("举报") || dto.Title.Contains("咨询")
                        || dto.Content.Contains("投诉") || dto.Content.Contains("举报") || dto.Content.Contains("咨询");
                    if (dto.Content.Length < 5)
                    {
                        valid.Validation = true;
                        valid.Result = "保存失败，受理内容字数不足,需要至少5个字!";
                    }
                    break;
                //建议求助
                case "15":
                case "20":
                    valid.Validation = dto.Title.Contains("投诉") || dto.Title.Contains("举报") || dto.Title.Contains("咨询")
                        || dto.Content.Contains("投诉") || dto.Content.Contains("举报") || dto.Content.Contains("咨询");
                    if (dto.Content.Length < 25)
                    {
                        valid.Validation = true;
                        valid.Result = "保存失败，受理内容字数不足,需要至少25个字!";
                    }
                    break;
                // 咨询
                case "10":
                    valid.Validation = dto.Title.Contains("投诉") || dto.Title.Contains("举报") || dto.Title.Contains("意见")
                        || dto.Title.Contains("建议") || dto.Content.Contains("投诉") || dto.Content.Contains("举报") || dto.Content.Contains("意见") || dto.Content.Contains("建议");
                    if (dto.Content.Length < 5)
                    {
                        valid.Validation = true;
                        valid.Result = "保存失败，受理内容字数不足,需要至少5个字!";
                    }
                    break;
                // 表扬
                case "25":
                    if (dto.Content.Length < 25)
                    {
                        valid.Validation = true;
                        valid.Result = "保存失败，受理内容字数不足,需要至少25个字!";
                    }
                    break;
                default:
                    if (dto.Content.Length < 5)
                    {
                        valid.Validation = true;
                        valid.Result = "保存失败，受理内容字数不足,需要至少5个字!";
                    }
                    break;
            }
        }

        if (valid.Validation && string.IsNullOrEmpty(valid.Result))
            valid.Result = "标题或受理内容出现限制词，请检查!";
        return valid;
    }
    #endregion


    #region 即将超期和超期短信

    /// <summary>
    ///  即将超期和超期短信
    /// </summary>
    /// <returns></returns>
    public async Task SendOverTimeSms(CancellationToken cancellationToken)
    {
        var now = DateTime.Now;
        var isSend = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.IsSendOverTimeSms).SettingValue[0]);
        if (!isSend)
        {
            return;
        }
        //查询即将超期和超期工单
        var orderList = await _orderRepository.Queryable()
            .Where(x => x.Status < EOrderStatus.Filed && !string.IsNullOrEmpty(x.CurrentHandleOrgId))
            .GroupBy(x => x.CurrentHandleOrgId)
            .Select(x => new OverTimeOrderDto
            {
                OrgId = x.CurrentHandleOrgId,
                NearlyOrderCount = SqlFunc.AggregateSum(SqlFunc.IIF(now >= x.NearlyExpiredTime && now < x.ExpiredTime, 1, 0)),
                ExpiredTimeOrderCount = SqlFunc.AggregateSum(SqlFunc.IIF(x.ExpiredTime < now, 1, 0))
            })
            .ToListAsync(cancellationToken);

        foreach (var item in orderList)
        {
            if (item.NearlyOrderCount == 0 && item.ExpiredTimeOrderCount == 0)
            {
                continue;
            }
            var acceptSmsRoleIds = _systemSettingCacheManager.GetSetting(SettingConstants.AcceptSmsRoleIds)?.SettingValue;
            //查询部门所有账号
            var userlist = await _userRepository.Queryable().Where(x =>
                x.OrgId == item.OrgId && !string.IsNullOrEmpty(x.PhoneNo) &&
                x.Roles.Any(d => acceptSmsRoleIds.Contains(d.Id))).ToListAsync();
            //发送短信
            foreach (var user in userlist)
            {
                var messageDto = new Share.Dtos.Push.MessageDto
                {
                    PushBusiness = EPushBusiness.OrderExpire,
                    PushPlatform = EPushPlatform.Sms,
                    Name = user.Name,
                    TemplateCode = "1009",
                    Params = new List<string>() { item.NearlyOrderCount.ToString(), item.ExpiredTimeOrderCount.ToString() },
                    TelNumber = user.PhoneNo,
                };
                await _mediator.Publish(new PushMessageNotify(messageDto), cancellationToken);
            }
        }
    }

    #endregion


    #region private

    private async Task<Order> GetOrderByFlowIdAsync(string workflowId, CancellationToken cancellationToken)
    {
        if (string.IsNullOrEmpty(workflowId))
            throw UserFriendlyException.SameMessage("无效流程编号");
        var order = await _orderRepository.Queryable()
            .Includes(d => d.Hotspot)
            .FirstAsync(d => d.WorkflowId == workflowId);
        if (order == null)
            throw new UserFriendlyException($"无效流程编号, workflowId: {workflowId}", "无效流程编号");
        return order;
    }

    private CacheOrderNO GetCurrentOrderNo()
    {
        var today = DateTime.Today;
        var cacheKey = today.ToString("yyyyMMdd");
        var cacheOrderNo = _cacheOrderNo.GetOrSet(cacheKey, f =>
        {
            var todayOrderCount = _orderRepository.Queryable(includeDeleted: true)
                .CountAsync(d => d.CreationTime.Date == today.Date)
                .GetAwaiter()
                .GetResult();
            return new CacheOrderNO { TotalCount = todayOrderCount };
        }, TimeSpan.FromDays(1));

        return cacheOrderNo;
    }

    public string GenerateNewOrderNo()
    {
        var today = DateTime.Today;
        var cacheKey = $"{today:yyyyMMdd}";
        var cacheOrderNo = _cacheOrderNo.GetOrSet(cacheKey, f =>
        {
            var todayOrderCount = _orderRepository.Queryable(true)
                .CountAsync(d => d.CreationTime.Date == today.Date)
                .GetAwaiter()
                .GetResult();
            return new CacheOrderNO { TotalCount = todayOrderCount };
        }, TimeSpan.FromDays(1));
        cacheOrderNo!.TotalCount += 1;
        var no = GenerateOrderNo(today, cacheOrderNo.TotalCount);
        _cacheOrderNo.Set(cacheKey, cacheOrderNo);
        return no;
    }

    private string GenerateNewProvinceNo(string no, string sourceChannelCode)
    {
        //诉求渠道+成员单位标识+行政区划代码+年月日+流水号
        //成员单位标识  99
        //宜宾市 511500  市级
        var today = DateTime.Today;
        //var count = no.Substring(no.Length - 5);
        var setting = _systemSettingCacheManager.GetSetting(SettingConstants.VersionsAreaCode);
        var versionsAreaCode = setting?.SettingValue[0];

        //todo 双系统并行暂时执行此方案
        var count = no.Substring(no.Length - 4);
        count = (Convert.ToInt32(count) + 50000).ToString();

        var provinceCodes = new[] { "RGDH", "WX", "WB", "AP", "WZ", "YJ", "SCZWFWW", "XCX", "QT" };
        var prefix = provinceCodes.Any(d => d.Equals(sourceChannelCode))
            ? sourceChannelCode
            : "QT";
        return $"{prefix}99{versionsAreaCode}{today:yyMMdd}{count}";
    }


    private string GenerateOrderNo(DateTime today, int count)
    {
        return $"{today:yyyyMMdd}{count:000000}";
    }


    #endregion
}

public class CacheOrderNO
{
    public int TotalCount { get; set; }
}

public class OrderValidation
{
    public bool Validation { get; set; }

    public string Result { get; set; }

}