package com.cyksj.service.corp.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.cyksj.common.constant.Constant;
import com.cyksj.common.exception.BusinessRuntimeException;
import com.cyksj.common.task.GlobalThreadPoolTaskExecutor;
import com.cyksj.common.util.Jsons;
import com.cyksj.common.util.StringUtil;
import com.cyksj.common.util.Xmls;
import com.cyksj.common.util.corp.WxCryptUtil;
import com.cyksj.config.corp.WeChatCorpFactory;
import com.cyksj.config.corp.YHLXWxCorpConfig;
import com.cyksj.dto.CorpOauth2UserInfo;
import com.cyksj.mapper.OrderDonMapper;
import com.cyksj.mapper.corp.*;
import com.cyksj.mapper.corp.kf.*;
import com.cyksj.model.dto.CorpKfServicerDto;
import com.cyksj.model.dto.WxCorpEncryptDto;
import com.cyksj.model.entity.*;
import com.cyksj.model.kf.*;
import com.cyksj.model.request.corp.Attachments;
import com.cyksj.model.request.corp.CorpXmlMessage;
import com.cyksj.model.request.corp.CorpXmlOutMessage;
import com.cyksj.model.response.corp.CorpMediaUploadResult;
import com.cyksj.model.response.corp.CorpUserInfo;
import com.cyksj.redis.RedisService;
import com.cyksj.service.corp.CorpService;
import com.cyksj.service.corp.WxCorpOps;
import com.cyksj.service.corp.msg.CorpEventActionService;
import com.cyksj.service.corp.msg.CorpMessageHandler;
import com.cyksj.service.corp.msg.CorpMessageRouter;
import com.cyksj.service.order.OrderDonPostService;
import com.cyksj.util.WxCorpUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.io.File;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

/*
 *项目名: netflix
 *文件名: CorpServiceImpl
 *创建者: JavaZou
 *创建时间:2022/10/13 14:59
 */
@Slf4j
@Service
public class CorpServiceImpl implements CorpService {
	@Autowired
	private YHLXWxCorpConfig yhlXWxCorpConfig;

	private CorpMessageRouter corpMessageRouter;

	@Autowired
	private CorpEventActionService corpEventActionService;

	@Autowired
	private WxCorpOps wxCorpOps;

	@Autowired
	private CorpFollowMapper corpFollowMapper;

	@Autowired
	private GlobalThreadPoolTaskExecutor THREAD_POOL;

	@Autowired
	private RedisService redisService;

	@Autowired
	private OrderDonPostService orderDonPostService;

	@Autowired
	private CorpCustomerAcquistionCallbackMapper corpCustomerAcquistionCallbackMapper;

	@Autowired
	private CorpUserPayIntentionMapper corpUserPayIntentionMapper;

	@Autowired
	private CorpUserMapper corpUserMapper;

	@Autowired
	private CorpUserTagMapper corpUserTagMapper;

	@Autowired
	private OrderDonMapper orderDonMapper;

	@Autowired
	private CorpUserFollowRelationMapper corpUserFollowRelationMapper;

	@Autowired
	private CorpKfAccountMapper corpKfAccountMapper;

	@Autowired
	private CorpKfAccountFollowMapper corpKfAccountFollowMapper;

	@Autowired
	private CorpKfAccountSessionConfigMapper corpKfAccountSessionConfigMapper;

	@Autowired
	private CorpKfWaitingQueueUserMapper corpKfWaitingQueueUserMapper;

	@Autowired
	private CorpKfServicerSessionRecordMapper corpKfServicerSessionRecordMapper;

	@Autowired
	private CorpKfAccountSyncMsgProgressMapper corpKfAccountSyncMsgProgressMapper;

	@Autowired
	private CorpKfAccountSessionChatMapper corpKfAccountSessionChatMapper;

	@Autowired
	private CorpKfUserMapper corpKfUserMapper;

	@PostConstruct
	private void init() {
		corpMessageRouter = new CorpMessageRouter(this)
				//添加企业客户事件
				.rule().async(false).changeType("add_external_contact")
				.handler(new CorpMessageHandler() {
					@Override
					public CorpXmlOutMessage handle(CorpXmlMessage message, Map<String, Object> context, CorpService corpService) throws Exception {
						return corpEventActionService.addExternalContact(message, context);
					}
				})
				.end()
				//编辑企业客户事件
				.rule().async(false).changeType("edit_external_contact")
				.handler(new CorpMessageHandler() {
					@Override
					public CorpXmlOutMessage handle(CorpXmlMessage message, Map<String, Object> context, CorpService corpService) throws Exception {
						return corpEventActionService.editExternalContact(message, context);
					}
				})
				.end()
				//外部联系人免验证添加成员事件
				.rule().async(false).changeType("add_half_external_contact")
				.handler(new CorpMessageHandler() {
					@Override
					public CorpXmlOutMessage handle(CorpXmlMessage message, Map<String, Object> context, CorpService corpService) throws Exception {
						return corpEventActionService.addExternalContact(message, context);
					}
				})
				.end()
				//删除企业客户事件
				.rule().async(false).changeType("del_external_contact")
				.handler(new CorpMessageHandler() {
					@Override
					public CorpXmlOutMessage handle(CorpXmlMessage message, Map<String, Object> context, CorpService corpService) throws Exception {
						return corpEventActionService.delExternalContact(message, context);
					}
				})
				.end()
				//删除跟进人员
				.rule().async(false).changeType("del_follow_user")
				.handler(new CorpMessageHandler() {
					@Override
					public CorpXmlOutMessage handle(CorpXmlMessage message, Map<String, Object> context, CorpService corpService) throws Exception {
						return corpEventActionService.delFollowUser(message, context);
					}
				})
				.end()
				//企业客户标签创建事件
				.rule().async(false).changeType("create").event("change_external_tag")
				.handler(new CorpMessageHandler() {
					@Override
					public CorpXmlOutMessage handle(CorpXmlMessage message, Map<String, Object> context, CorpService corpService) throws Exception {
						return corpEventActionService.saveCorpTag(message, context);
					}
				})
				.end()
				//企业客户标签变更事件
				.rule().async(false).changeType("update").event("change_external_tag")
				.handler(new CorpMessageHandler() {
					@Override
					public CorpXmlOutMessage handle(CorpXmlMessage message, Map<String, Object> context, CorpService corpService) throws Exception {
						return corpEventActionService.saveCorpTag(message, context);
					}
				})
				.end()
				//企业客户标签删除事件
				.rule().async(false).changeType("delete").event("change_external_tag")
				.handler(new CorpMessageHandler() {
					@Override
					public CorpXmlOutMessage handle(CorpXmlMessage message, Map<String, Object> context, CorpService corpService) throws Exception {
						return corpEventActionService.delCorpTag(message, context);
					}
				})
				.end()
				//用户同意会话存档
				.rule().async(false).changeType("msg_audit_approved").event("change_external_contact")
				.handler(new CorpMessageHandler() {
					@Override
					public CorpXmlOutMessage handle(CorpXmlMessage message, Map<String, Object> context, CorpService corpService) throws Exception {
						return corpEventActionService.msgAuditApproved(message, context);
					}
				})
				.end()
				//微信客户发起会话事件
				.rule().async(false).changeType("customer_start_chat").event("customer_acquisition")
				.handler(new CorpMessageHandler() {
					@Override
					public CorpXmlOutMessage handle(CorpXmlMessage message, Map<String, Object> context, CorpService corpService) throws Exception {
						return corpEventActionService.customerStartChat(message, context);
					}
				})
				.end()
				//新增成员
				.rule().async(false).changeType("create_user")
				.handler(new CorpMessageHandler() {
					@Override
					public CorpXmlOutMessage handle(CorpXmlMessage message, Map<String, Object> context, CorpService corpService) throws Exception {
						return corpEventActionService.creatOrUpdateFollowUser(message);
					}
				})
				.end()
				//成员更新事件
				.rule().async(false).changeType("update_user")
				.handler(new CorpMessageHandler() {
					@Override
					public CorpXmlOutMessage handle(CorpXmlMessage message, Map<String, Object> context, CorpService corpService) throws Exception {
						return corpEventActionService.creatOrUpdateFollowUser(message);
					}
				})
				.end()
//				//企业微信客服 用户进入会话事件
//				.rule().async(false).msgType("event").event("kf_msg_or_event")
//				.handler(new CorpMessageHandler() {
//					@Override
//					public CorpXmlOutMessage handle(CorpXmlMessage message, Map<String, Object> context, CorpService corpService) throws Exception {
//						//
//						return kfMsgOrEvent(message, context);
//					}
//				})
//				.end()
		;

	}

	@Override
	public String VerifyURL(String msgSignature, String timestamp, String nonce, String echoStr) throws Exception {
		WxCorpUtil wxCorpMsgUtil = new WxCorpUtil(yhlXWxCorpConfig.getToken(), yhlXWxCorpConfig.getEncodingAESKey(), yhlXWxCorpConfig.getCorpId());
		return wxCorpMsgUtil.VerifyURL(msgSignature, timestamp, nonce, echoStr);
	}

	@Override
	public String corpMsg(String msgSignature, String timestamp, String nonce, String content) throws Exception {
		WxCorpEncryptDto corpEncryptDto = Xmls.parseObject(content, WxCorpEncryptDto.class);
		WxCorpApp wxCorpApp = WeChatCorpFactory.getCorpConfigStrategy(corpEncryptDto.getToUserName());

		WxCorpUtil wxCorpUtil = new WxCorpUtil(wxCorpApp.getToken(), wxCorpApp.getEncodingAESKey(), wxCorpApp.getCorpId());

		String msg = wxCorpUtil.DecryptMsg(msgSignature, timestamp, nonce, corpEncryptDto);
		log.info("企业微信 解密 msg:\n{}", msg);

		CorpXmlMessage inMessage = Xmls.parseObject(msg, CorpXmlMessage.class);

		//事件路由
		CorpXmlOutMessage outMessage = corpMessageRouter.route(inMessage);

		if (outMessage != null) {
			return outMessage.toEncryptedXml(new WxCryptUtil(yhlXWxCorpConfig.getToken(), yhlXWxCorpConfig.getEncodingAESKey(), yhlXWxCorpConfig.getCorpId()));
		}
		return "";
	}

	@Override
	public String dataInitByCorpId(String corpId) throws Exception {
		//获取成员列表
		List<String> followUserList = wxCorpOps.getFollowUserList(corpId);
		WxCorpApp wxCorpApp = WeChatCorpFactory.getCorpConfigStrategy(corpId);
		Long wxCorpId = wxCorpApp.getId();
		for (String userId : followUserList) {
			THREAD_POOL.execute(() -> {
				CorpUserInfo userInfo = null;
				try {
					userInfo = wxCorpOps.getFollowUser(corpId, userId);
				} catch (Exception e) {
					e.printStackTrace();
					return;
				}
				if (!userInfo.getDepartment().contains(2)) {
					System.out.println("不是客服");
					return;
				}
				CorpFollow corpFollow = new CorpFollow();
				BeanUtil.copyProperties(userInfo, corpFollow);
				CorpFollow follow = corpFollowMapper.selectOne(Wrappers.lambdaQuery(CorpFollow.class).eq(CorpFollow::getUserid, corpFollow.getUserid()).eq(CorpFollow::getWxCorpId, wxCorpId));
				if (follow == null) {
					corpFollow.setWxCorpId(wxCorpId);
					corpFollowMapper.insert(corpFollow);
				} else {
					corpFollow.setId(follow.getId());
					corpFollowMapper.updateById(corpFollow);
				}
			});
		}
		return "";
	}

	@Override
	public String createUrl(String corpId, String state) {
		return wxCorpOps.createUrl(corpId, state);
	}

	@Override
	public CorpOauth2UserInfo getUserInfo(String corpId, String code) throws Exception {
		return wxCorpOps.getUserInfo(corpId, code);
	}

	@Override
	@Transactional(rollbackFor = Throwable.class)
	public CorpFollow saveFollowUser(String corpId, CorpOauth2UserInfo corpOauth2UserInfo) throws Exception {
		WxCorpApp wxCorpApp = WeChatCorpFactory.getCorpConfigStrategy(corpId);
		Long wxCorpId = wxCorpApp.getId();
		CorpFollow corpFollow = corpFollowMapper.selectOne(Wrappers.lambdaQuery(CorpFollow.class).eq(CorpFollow::getWxCorpId, wxCorpId).eq(CorpFollow::getUserid, corpOauth2UserInfo.getUserId()));
		CorpUserInfo userInfo = wxCorpOps.getFollowUser(corpId, corpOauth2UserInfo.getUserId());
		if (corpFollow == null) {
			corpFollow = new CorpFollow();
			BeanUtil.copyProperties(userInfo, corpFollow);
			corpFollow.setWxCorpId(wxCorpId);
			corpFollowMapper.insert(corpFollow);
		}else {
			BeanUtil.copyProperties(userInfo, corpFollow);
			corpFollow.setWxCorpId(wxCorpId);
			corpFollowMapper.updateById(corpFollow);
		}

		return corpFollow;
	}

	@Override
	public String getJsTicket(String corpId) throws Exception {
		return wxCorpOps.getJsTicket(corpId);
	}

	@Override
	public String getAgentJsTicket(String corpId, String agentId) throws Exception {
		return wxCorpOps.getAgentJsTicket(corpId, agentId);
	}

	@Override
	public Attachments updateMaterial(Attachments attachments, String corpId, Integer type) {
		if("image".equals(attachments.getMsgtype())) {
			Attachments.Image image = attachments.getImage();
			if(type == 1) {
				image.setMediaId(wxCorpOps.getMediaIdByFileName(attachments.getMsgtype(),image.getPicUrl(),corpId));
			} else {
				image.setMediaId(this.uploadAttachmentAndGetMediaIdByFileName(attachments.getMsgtype(),image.getPicUrl(),corpId,1));
			}

		} else if("link".equals(attachments.getMsgtype())) {
			// 链接不做处理
//            Attachments.Link link = attachments.getLink();
//            link.setMediaId(corpService.getMediaIdByFileName("image",link.getPicurl(),corpId));

		} else if("video".equals(attachments.getMsgtype())) {
			Attachments.Video video = attachments.getVideo();
			if(type == 1) {
				video.setMediaId(wxCorpOps.getMediaIdByFileName(attachments.getMsgtype(),video.getUrl(),corpId));
			} else {
				video.setMediaId(this.uploadAttachmentAndGetMediaIdByFileName(attachments.getMsgtype(),video.getUrl(),corpId,1));
			}
		} else if("miniprogram".equals(attachments.getMsgtype())) {
			Attachments.MiniProgram miniProgram = attachments.getMiniProgram();
			miniProgram.setPicMediaId(wxCorpOps.getMediaIdByFileName("image",miniProgram.getUrl(),corpId));
		} else {
			throw BusinessRuntimeException.getInstance("附件类型错误");
		}
		return attachments;
	}

	public String uploadAttachmentAndGetMediaIdByFileName(String msgType, String url, String corpId, Integer attachmentType) {
		//临时解决
		if ("miniprogram".equals(msgType)) {
			msgType = "image";
		}
		String[] split = url.split("/");
		String filename = split[split.length - 1];
		String mediaId = redisService.getStr(String.format(RedisService.key.CORP_UPLOAD_ATTACHMENTS.getName(), corpId) + filename.split("\\.")[0]);

		if (StringUtils.isBlank(mediaId)) {
			File file = new File("./" + filename);
			HttpUtil.downloadFile(url, file);

			Map<String, Object> paramMap = new HashMap<>();
			//文件上传只需将参数中的键指定（默认file），值设为文件对象即可，对于使用者来说，文件上传与普通表单提交并无区别
			paramMap.put("media", FileUtil.file(file.getAbsolutePath()));

			try {
				String result = HttpUtil.post("https://qyapi.weixin.qq.com/cgi-bin/media/upload_attachment?media_type=" + msgType + "&access_token=" + wxCorpOps.getAccessToken(corpId) + "&attachment_type=" + attachmentType, paramMap);

				CorpMediaUploadResult corpMediaUploadResult = JSONUtil.toBean(result, CorpMediaUploadResult.class);
				if (StringUtils.isBlank(corpMediaUploadResult.getMediaId())) {
					throw BusinessRuntimeException.getInstance("企微上传附件错误。回现素材为空.");
				}
				FileUtil.del(file);
				long time = System.currentTimeMillis() / 1000 - (corpMediaUploadResult.getCreatedAt() + 60 * 60 * 24 * 3 - 60 * 60);
				redisService.set(String.format(RedisService.key.CORP_UPLOAD_ATTACHMENTS.getName(), corpId) + filename, corpMediaUploadResult.getMediaId(), time);
				return corpMediaUploadResult.getMediaId();
			} catch (Exception e) {
				FileUtil.del(file);
				throw BusinessRuntimeException.getInstance("上传临时附件出错,errorMsg:" + StringUtil.getErrorText(e));
			}
		}

		return mediaId;
	}

	/**
	 *  加粉回传 目前 OE
	 */
	@Override
	public void postAcquistionLinkCallback(Long id) {
		try {
			CorpCustomerAcquistionCallback corpCustomerAcquistionCallback = corpCustomerAcquistionCallbackMapper.selectById(id);
			if(corpCustomerAcquistionCallback == null){
				throw BusinessRuntimeException.getInstance("回传记录不存在");
			}
			if (corpCustomerAcquistionCallback.getStatus()) {
				throw BusinessRuntimeException.getInstance("该记录已回传");
			}
			orderDonPostService.post(OrderDonPost.Type.OE.getType(), corpCustomerAcquistionCallback.getCallback(), corpCustomerAcquistionCallback.getEvent());
			corpCustomerAcquistionCallback.setStatus(true);
			corpCustomerAcquistionCallbackMapper.updateById(corpCustomerAcquistionCallback);
		} catch (Exception e) {
			throw BusinessRuntimeException.getInstance("加粉回传出错. error:" + StringUtil.getErrorText(e));
		}
	}

	@Override
	public void upCallbackIntention(CorpCustomerAcquistionCallback corpCustomerAcquistionCallback) {
		corpCustomerAcquistionCallbackMapper.update(null, Wrappers.lambdaUpdate(CorpCustomerAcquistionCallback.class).eq(CorpCustomerAcquistionCallback::getId, corpCustomerAcquistionCallback.getId()).set(CorpCustomerAcquistionCallback::getIntention, corpCustomerAcquistionCallback.getIntention()));
	}

	@Override
	public void updateUserIntention(CorpUserPayIntention corpUserPayIntention) {
		if (corpUserPayIntention.getId() == null) {
			try {
				corpUserPayIntentionMapper.insert(corpUserPayIntention);
			} catch (DuplicateKeyException e) {
			}
		} else {
			corpUserPayIntentionMapper.updateById(corpUserPayIntention);
		}
		//将所属意向标签组不属于该标签的全删除
		//并打上对应标签
		CorpUserPayIntention.Intention intention = CorpUserPayIntention.Intention.values()[corpUserPayIntention.getIntention()];
		String tagName = intention.getTagName();
		String tagId = intention.getTagId();
		String externalUserId = corpUserMapper.selectUserExternalUserId(corpUserPayIntention.getUnionId());
		if (StrUtil.isEmpty(externalUserId)) {
			return;
		}
		List<CorpUserTag> corpUserTags = corpUserTagMapper.selectIntentionUserTag(externalUserId, Constant.EP_INTENTION_GROUP_NAME);
		//是否存在对应标签
		AtomicBoolean isExistIntentionTag = new AtomicBoolean(false);
		if (CollUtil.isNotEmpty(corpUserTags)) {
			//删除之前的意向标签
			corpUserTags.forEach(userTag -> {
				if (!StrUtil.equals(userTag.getTagId(), tagId)) {
					try {
						wxCorpOps.markTag(userTag.getExternalUserId(), userTag.getFollowId(), null, new String[]{userTag.getTagId()});
						corpUserTagMapper.deleteById(userTag.getId());
					} catch (Exception e) {
					}
				} else {
					if (!isExistIntentionTag.get()) {
						isExistIntentionTag.set(true);
					}
				}
			});
		}
		if (!isExistIntentionTag.get()) {
			CorpUser corpUser = corpUserMapper.selectOne(Wrappers.lambdaQuery(CorpUser.class)
					.eq(CorpUser::getUnionid, corpUserPayIntention.getUnionId())
					.last("limit 1"));
			Boolean isPayEp = false;
			if (corpUser != null && corpUser.getUserId() != 0) {
				//是否买过设备
				Integer selectCount = orderDonMapper.selectCount(Wrappers.lambdaQuery(OrderDon.class)
						.eq(OrderDon::getGoodsId, 15)
						.eq(OrderDon::getUserId, corpUser.getUserId())
						.notIn(OrderDon::getStatus, Constant.noOrderAllStatus));
				if (selectCount > 0) {
					isPayEp = true;
				}
			}
			if (!isPayEp) {
				insertUserIntentionTag(corpUserPayIntention, tagId, tagName);
			}
		}
	}

	public void insertUserIntentionTag(CorpUserPayIntention corpUserPayIntention, String tagId, String tagName) {
		CorpUserFollowRelation corpUserFollowRelation = corpUserFollowRelationMapper.getCorpUserFollowRelation(corpUserPayIntention.getUnionId(), corpUserPayIntention.getFollowId());
		if (corpUserFollowRelation == null) {
			return;
		}
		String externalUserId = corpUserFollowRelation.getCorpUserId();
		String followId = corpUserFollowRelation.getFollowId();
		try {
			wxCorpOps.markTag(externalUserId, followId, new String[]{tagId}, null);
			//新增用户标签
			CorpUserTag corpUserTag = new CorpUserTag();
			corpUserTag.setRelationId(corpUserFollowRelation.getId());
			corpUserTag.setGroupName(Constant.EP_INTENTION_GROUP_NAME);
			corpUserTag.setTagId(tagId);
			corpUserTag.setTagName(tagName);
			corpUserTag.setType(1);
			corpUserTagMapper.insert(corpUserTag);
		} catch (Exception e) {
			log.error("新增用户意向标签错误:{}", StringUtil.getErrorText(e));
		}

	}

	/**
	 * 企业微信客服 时间消息回调
	 */
	private CorpXmlOutMessage kfMsgOrEvent(CorpXmlMessage message, Map<String, Object> context) {
		try {
			String openKfId = message.getOpenKfId();
			CorpKfAccount corpKfAccount = corpKfAccountMapper.selectOne(Wrappers.lambdaQuery(CorpKfAccount.class)
					.eq(CorpKfAccount::getOpenKfId, openKfId)
					.last("limit 1"));
			if (corpKfAccount == null) {
				log.info("客服账号:{}已被删除或不存在", openKfId);
				return null;
			}
			//账号会话设置
			CorpKfAccountSessionConfig corpKfAccountSessionConfig = Optional.ofNullable(corpKfAccountSessionConfigMapper.selectOne(Wrappers.lambdaQuery(CorpKfAccountSessionConfig.class)
					.eq(CorpKfAccountSessionConfig::getOpenKfId, openKfId)
					.last("limit 1"))).orElse(new CorpKfAccountSessionConfig());
			//同步消息进度
			CorpKfAccountSyncMsgProgress corpKfAccountSyncMsgProgress = Optional.ofNullable(corpKfAccountSyncMsgProgressMapper.selectOne(Wrappers.lambdaQuery(CorpKfAccountSyncMsgProgress.class)
					.eq(CorpKfAccountSyncMsgProgress::getOpenKfId, openKfId)
					.last("limit 1"))).orElse(new CorpKfAccountSyncMsgProgress());
			String cursor = null;
			if (corpKfAccountSyncMsgProgress.getNextCursor() != null) {
				cursor = corpKfAccountSyncMsgProgress.getNextCursor();
			}
			String corpId = message.getToUserName();
			String token = message.getToken();
			syncCorpKfMsg(corpKfAccount, corpKfAccountSessionConfig, corpId, cursor, token, null, corpKfAccountSyncMsgProgress);
			corpKfAccountSyncMsgProgress.setOpenKfId(openKfId);
			//同步记录
			if (corpKfAccountSyncMsgProgress.getId() == null) {
				corpKfAccountSyncMsgProgressMapper.insert(corpKfAccountSyncMsgProgress);
			} else corpKfAccountSyncMsgProgressMapper.updateById(corpKfAccountSyncMsgProgress);
		} catch (Exception e) {
			log.error("企业微信客服 事件消息回调 错误,e：{}", StringUtil.getErrorText(e));
		}
		return null;
	}

	private void syncCorpKfMsg(CorpKfAccount corpKfAccount, CorpKfAccountSessionConfig corpKfAccountSessionConfig, String corpId, String cursor, String token, Integer limit, CorpKfAccountSyncMsgProgress corpKfAccountSyncMsgProgress) throws Exception {
		String openKfId = corpKfAccount.getOpenKfId();
		WxCpKfMsgListResp wxCpKfMsgListResp = wxCorpOps.syncMsg(corpId, cursor, token, limit, openKfId);
		List<WxCpKfMsgListResp.WxCpKfMsgItem> msgList = wxCpKfMsgListResp.getMsgList();
		for (WxCpKfMsgListResp.WxCpKfMsgItem item : msgList) {
			if (item.getEvent() != null) {
				//会话事件
				if (item.getEvent().getEventType().equals("enter_session")) {
					//进入会话事件
					enterSessionEvent(corpKfAccount, corpKfAccountSessionConfig, corpId, item);
				}
				//会话变更事件
				if (item.getEvent().getEventType().equals("session_status_change")) {
					//会话更变事件
					sessionStatusChange(corpId, openKfId, item, corpKfAccountSessionConfig);
				}
			}
			//同步微信客服账号信息
			syncKfChatMsg(corpId, openKfId, corpKfAccountSessionConfig, item);
		}
		cursor = wxCpKfMsgListResp.getNextCursor();
		corpKfAccountSyncMsgProgress.setNextCursor(cursor);
		//同步信息
//		while (wxCpKfMsgListResp.getHasMore() == 1) {
//			syncCorpKfMsg(corpKfAccount, corpKfAccountSessionConfig, corpId, wxCpKfMsgListResp.getNextCursor(), token, limit, corpKfAccountSyncMsgProgress);
//		}
	}

	private void syncKfChatMsg(String corpId, String openKfId, CorpKfAccountSessionConfig corpKfAccountSessionConfig, WxCpKfMsgListResp.WxCpKfMsgItem item) throws Exception {
		CorpKfAccountSessionChat corpKfAccountSessionChat = new CorpKfAccountSessionChat();
		Boolean record = false;
		//文本
		if (item.getText() != null) {
			corpKfAccountSessionChat.setMsgContent(item.getText().getContent());
			record = true;
		} else if (item.getMergedMsg() != null) {
			//聊天记录 转发
			corpKfAccountSessionChat.setMsgContent(Jsons.toJson(item.getMergedMsg().getItem()));
			record = true;
		} else if (item.getVideo() != null) {
			//视频记录
			setMediaUrl(corpKfAccountSessionChat, item.getVideo().getMedia_id());
			record = true;
		} else if (item.getFile() != null) {
			//文件
			setMediaUrl(corpKfAccountSessionChat, item.getFile().getMedia_id());
			record = true;
		} else if (item.getImage() != null) {
			//图片
			setMediaUrl(corpKfAccountSessionChat, item.getImage().getMedia_id());
			record = true;
		} else if (item.getLink() != null) {
			//链接
			WxCorpLinkMsg link = item.getLink();
			corpKfAccountSessionChat.setLinkTitle(link.getTitle());
			corpKfAccountSessionChat.setLinkDesc(link.getDesc());
			corpKfAccountSessionChat.setLinkUrl(link.getUrl());
			corpKfAccountSessionChat.setLinkPicUrl(link.getPic_url());
			record = true;
		} else if (item.getMsgmenu() != null) {
			//菜单 结束语统计
			corpKfAccountSessionChat.setMsgContent(Jsons.toJson(item.getMsgmenu()));
			record = true;
		}
		if (record) {
			//新增
			String openKfid = item.getOpenKfid();
			//客户id
			String externalUserId = item.getExternalUserId();
			//接待人员id
			String servicerUserId = item.getServicerUserId();
			//消息来源。3-微信客户发送的消息 4-系统推送的事件消息 5-接待人员在企业微信客户端发送的消息
			Integer origin = item.getOrigin();
			//发送时间
			Long sendTime = item.getSendTime();
			//消息id
			String msgId = item.getMsgId();
			//消息类型
			String msgType = item.getMsgType();
			corpKfAccountSessionChat.setOpenKfId(openKfid);
			corpKfAccountSessionChat.setMsgid(msgId);
			corpKfAccountSessionChat.setServicerUserid(servicerUserId);
			corpKfAccountSessionChat.setExternalUserid(externalUserId);
			corpKfAccountSessionChat.setOrign(origin);
			corpKfAccountSessionChat.setMsgType(msgType);
			corpKfAccountSessionChat.setSendTime(sendTime);
			corpKfAccountSessionChat.setSendDate(DateTime.of(sendTime * 1000));
			saveChatMsg(corpKfAccountSessionChat);

			if (StrUtil.isNotEmpty(externalUserId)) {
				//会话状态为待处理 则分配接待人员
				assignKfSession(corpId, openKfId, externalUserId, corpKfAccountSessionConfig, corpKfAccountSessionChat.getSendDate(), msgId);
			}
			syncSessionSatisfaction(item);
		}
	}

	private void syncSessionSatisfaction(WxCpKfMsgListResp.WxCpKfMsgItem item) throws Exception {
		Integer satisfaction = null;
		WxCorpTextMsg text = item.getText();
		//自定义菜单id
		if (text != null && text.getMenu_id() != null) {
			String[] split = text.getMenu_id().split("-");
			if (split.length < 2) {
				return;
			}
			String menuId = split[0];
			String msgid = split[1];
			//满意
			if ("101".equals(menuId)) {
				satisfaction = 1;
			}
			//一般
			if ("102".equals(menuId)) {
				satisfaction = 2;
			}
			//不满意
			if ("103".equals(menuId)) {
				satisfaction = 3;
			}
			if (satisfaction != null) {
				CorpKfServicerSessionRecord corpKfServicerSessionRecord = corpKfServicerSessionRecordMapper.selectOne(Wrappers.lambdaQuery(CorpKfServicerSessionRecord.class)
						.eq(CorpKfServicerSessionRecord::getMsgid, msgid)
						.last("limit 1"));
				if (corpKfServicerSessionRecord != null) {
					corpKfServicerSessionRecord.setSatisfaction(satisfaction);
					corpKfServicerSessionRecordMapper.updateById(corpKfServicerSessionRecord);
					//设置会话id
					corpKfAccountSessionChatMapper.update(null, Wrappers.lambdaUpdate(CorpKfAccountSessionChat.class)
							.set(CorpKfAccountSessionChat::getSessionId, corpKfServicerSessionRecord.getId())
							.eq(CorpKfAccountSessionChat::getMsgid, item.getMsgId()));
				}
			}
		}
	}

	private void sessionStatusChange(String corpId, String openKfId, WxCpKfMsgListResp.WxCpKfMsgItem wxCpKfMsgItem, CorpKfAccountSessionConfig corpKfAccountSessionConfig) throws Exception {
		WxCpKfEventMsg event = wxCpKfMsgItem.getEvent();
		Integer changeType = event.getChangeType();
		String externalUserId = event.getExternalUserId();
		Long sendTime = wxCpKfMsgItem.getSendTime();
		DateTime sendDate = DateTime.of(sendTime * 1000);
		//1-从接待池接入会话 2-转接会话 3-结束会话 4-重新接入已结束/已转接会话
		String oldServicerUserId = event.getOldServicerUserId();
		String newServicerUserId = event.getNewServicerUserId();
		String msgId = wxCpKfMsgItem.getMsgId();
		String msgCode = wxCpKfMsgItem.getEvent().getMsgCode();
		//1-从接待池接入会话 4-重新接入已结束/已转接会话
		if (changeType == 1 || changeType == 4) {
			CorpKfServicerSessionRecord newSession = new CorpKfServicerSessionRecord();
			newSession.setOpenKfId(openKfId);
			newSession.setServicerUserid(newServicerUserId);
			newSession.setExternalUserid(externalUserId);
			newSession.setChangeType(changeType);
			newSession.setServiceState(0);
			newSession.setStartTime(sendDate);
			newSession.setMsgid(msgId);
			corpKfServicerSessionRecordMapper.insert(newSession);
			//等待用户删除
			delQueueUser(openKfId, externalUserId, sendDate);
			syncUserChatSession(newSession.getId(), externalUserId);
		}
		//2-转接会话
		if (changeType == 2) {
			//设置表中会话状态
			setDbSessionState(openKfId, oldServicerUserId, externalUserId, sendDate, changeType, msgId, msgCode);
			transCorpKfSessionToServicer(corpId, openKfId, oldServicerUserId, newServicerUserId, externalUserId, changeType, 3, sendDate, msgId);
		}
		//3-结束会话
		if (changeType == 3) {
			setDbSessionState(openKfId, oldServicerUserId, externalUserId, sendDate, changeType, msgId, msgCode);
		}
	}

	/**
	 * enter_session 会话事件
	 */
	public void enterSessionEvent(CorpKfAccount corpKfAccount, CorpKfAccountSessionConfig corpKfAccountSessionConfig, String corpId, WxCpKfMsgListResp.WxCpKfMsgItem wxCpKfMsgItem) throws Exception {
		String openKfId = corpKfAccount.getOpenKfId();
		DateTime sendDate = DateTime.of(wxCpKfMsgItem.getSendTime() * 1000);
		WxCpKfEventMsg event = wxCpKfMsgItem.getEvent();
		String welcomeCode = event.getWelcomeCode();
		String msgid = wxCpKfMsgItem.getMsgId();
		//如果满足发送欢迎语条件（条件为：用户在过去48小时里未收过欢迎语，且未向客服发过消息），会返回该字段。
		//可用该welcome_code调用发送事件响应消息接口给客户发送欢迎语。
		if (StrUtil.isNotEmpty(welcomeCode)) {
			WxCorpKfMsgSendRequest wxCpKfMsgSendRequest = new WxCorpKfMsgSendRequest();
			wxCpKfMsgSendRequest.setMsgType("text");
			wxCpKfMsgSendRequest.setCode(welcomeCode);
			WxCorpKfMsgSendRequest.WxCpKfTextMsg textMsg = new WxCorpKfMsgSendRequest.WxCpKfTextMsg();
			if (StrUtil.isNotEmpty(corpKfAccountSessionConfig.getWelcomeContent())) {
				textMsg.setContent(corpKfAccountSessionConfig.getWelcomeContent());
				wxCpKfMsgSendRequest.setText(textMsg);
				wxCpKfMsgSendRequest.setToUser(welcomeCode);
				wxCpKfMsgSendRequest.setOpenKfid(event.getOpenKfid());
				try {
					wxCorpOps.sendMsgOnEvent(corpId, wxCpKfMsgSendRequest);
					//同步用户信息
					syncCorpkfUserInfo(event.getExternalUserId());
				} catch (Exception e) {
					log.error("发送微信客服欢迎语失败:{}", StringUtil.getErrorText(e));
				}
			}
		}
		//分配接待人员
		assignKfSession(corpId, openKfId, event.getExternalUserId(), corpKfAccountSessionConfig, sendDate, msgid);
	}

	/**
	 * 同步用户信息
	 */
	private void syncCorpkfUserInfo(String externalUserid) throws Exception {
		CorpKfUserInfo corpKfUserInfo = wxCorpOps.getCorpKfUserInfo(externalUserid);
		CorpKfUser corpKfUser = corpKfUserMapper.selectOne(Wrappers.lambdaQuery(CorpKfUser.class)
				.eq(CorpKfUser::getExternalUserid, externalUserid)
				.last("limit 1"));
		if (corpKfUser == null) {
			try {
				corpKfUser = new CorpKfUser();
				BeanUtil.copyProperties(corpKfUserInfo, corpKfUser);
				corpKfUserMapper.insert(corpKfUser);
			} catch (Exception e) {
			}
		} else {
			corpKfUser.setAvatar(corpKfUserInfo.getAvatar());
			corpKfUser.setNickname(corpKfUserInfo.getNickname());
			corpKfUser.setGender(corpKfUserInfo.getGender());
			corpKfUserMapper.updateById(corpKfUser);
		}
	}

	/**
	 * 变更用户会话状态
	 * serviceState 0未处理 1由智能助手接待 2待接入池排队中 3由人工接待 4 已结束/未开始
	 */
	private void transCorpKfSessionToServicer(String corpId, String openKfId, String oldServicerUserId, String userid, String externalUserId, Integer changeType, Integer serviceState, Date sendTime, String msgid) throws Exception {
		//调用微信客服接口 变更会话状态
		try {
			wxCorpOps.transCorpKfSessionToServicer(corpId, openKfId, userid, externalUserId, serviceState);
			//记录接待人员会话
			CorpKfServicerSessionRecord corpKfServicerSessionRecord = new CorpKfServicerSessionRecord();
			corpKfServicerSessionRecord.setOpenKfId(openKfId);
			corpKfServicerSessionRecord.setServiceState(0);
			corpKfServicerSessionRecord.setFromUserid(oldServicerUserId);
			corpKfServicerSessionRecord.setServicerUserid(userid);
			corpKfServicerSessionRecord.setExternalUserid(externalUserId);
			corpKfServicerSessionRecord.setChangeType(changeType);
			corpKfServicerSessionRecord.setStartTime(sendTime);
			corpKfServicerSessionRecord.setMsgid(msgid);
			corpKfServicerSessionRecordMapper.insert(corpKfServicerSessionRecord);
			//等待用户删除
			delQueueUser(openKfId, externalUserId, sendTime);
			//同步这一次接待记录
			if (serviceState == 3) {
				corpKfAccountSessionChatMapper.update(null, Wrappers.lambdaUpdate(CorpKfAccountSessionChat.class)
						.set(CorpKfAccountSessionChat::getSessionId, corpKfServicerSessionRecord.getId())
						.eq(CorpKfAccountSessionChat::getOpenKfId, openKfId)
						.eq(CorpKfAccountSessionChat::getExternalUserid, externalUserId)
						.isNull(CorpKfAccountSessionChat::getSessionId));
			}
		} catch (Exception e) {
			log.error("创建新的会话错误：{}", StringUtil.getErrorText(e));
		}
	}

	/**
	 * 发送微信客服会话文本消息
	 */
	public void sendCorpKfTextTips(String corpId, String externalUserid, String openKfId, String content) throws Exception {
		if (StrUtil.isEmpty(content)) {
			return;
		}
		//查询会话状态
		ServiceStateResponse serviceStateResponse = wxCorpOps.getCorpKfSessionStatus(corpId, openKfId, externalUserid);
		Integer state = serviceStateResponse.getService_state();
		//0.未处理 1.人工智能接待 可调用api发送消息
		if (state == null && state != 0 && state != 1) {
			log.info("目前openKfId:{}用户eid:{}会话处于状态中state:{}，无法发送消息", openKfId, externalUserid, state);
			return;
		}
		WxCorpKfMsgSendRequest wxCpKfMsgSendRequest = new WxCorpKfMsgSendRequest();
		wxCpKfMsgSendRequest.setMsgType("text");
		wxCpKfMsgSendRequest.setToUser(externalUserid);
		wxCpKfMsgSendRequest.setOpenKfid(openKfId);
		WxCorpKfMsgSendRequest.WxCpKfTextMsg textMsg = new WxCorpKfMsgSendRequest.WxCpKfTextMsg();
		textMsg.setContent(content);
		wxCpKfMsgSendRequest.setText(textMsg);
		wxCorpOps.sendTextMsg(corpId, wxCpKfMsgSendRequest);
	}

	/**
	 * 会话状态为待处理 则分配接待人员
	 */
	public void assignKfSession(String corpId, String openKfId, String externalUserid, CorpKfAccountSessionConfig corpKfAccountSessionConfig, Date sendDate, String msgid) throws Exception {
		//超过15分钟 进入会话时间不处理
		if (sendDate.compareTo(DateUtil.offsetMinute(DateTime.now(), -15)) <= 0) {
			return;
		}
		//查询用户会话状态 0待处理 	1智能助手接待
		ServiceStateResponse serviceStateResponse = wxCorpOps.getCorpKfSessionStatus(corpId, openKfId, externalUserid);
		Integer state = serviceStateResponse.getService_state();
		if (state != 0 && state != 1) {
			return;
		}
		//当前时间段值班客服
		Set<String> dutyFollowIds = getDutyFollowIds(openKfId);
		//非值班
		if (dutyFollowIds.isEmpty()) {
			//非值班时间 移入等待池
			log.info("当前客服账号:{}处于非值班时间:{},将客户:{}移入等待池", openKfId, DateTime.now(), externalUserid);
			//发送进入等待池消息
			sendCorpKfTextTips(corpId, externalUserid, openKfId, corpKfAccountSessionConfig.getNoDutyTips());
			moveWaitingQueue(corpId, openKfId, externalUserid);
			return;
		}
		//获取接待人员列表
		CorpKfServicerResp corpKfServicerResp = wxCorpOps.getKfServicerList(corpId, openKfId);
		List<CorpKfServicerResp.CorpKfServicer> servicerList = corpKfServicerResp.getServicerList();
		//目前值班客服id
		List<String> corpKfServiceIds = new ArrayList<>();
		servicerList.forEach(servicer -> {
			if (servicer.getUserid() != null && servicer.getStatus() == 0 && dutyFollowIds.contains(servicer.getUserid())) {
				corpKfServiceIds.add(servicer.getUserid());
			}
		});
		//客服是否已经开始值班
		//没有值班人员
		if (CollUtil.isEmpty(corpKfServiceIds)) {
			log.info("当前客服账号:{}无值班人员,将客户:{}移入等待池", openKfId, externalUserid);
			sendCorpKfTextTips(corpId, externalUserid, openKfId, corpKfAccountSessionConfig.getQueueTips());
			//接入等待池
			moveWaitingQueue(corpId, openKfId, externalUserid);
			return;
		}
		//是否有空闲接待人员
		List<CorpKfServicerDto> corpKfServicerDtos = corpKfServicerSessionRecordMapper.getAvailableServicer(openKfId);
		//暂无分配会话 初始化
		if (CollUtil.isEmpty(corpKfServicerDtos)) {
			//随机分配一个客服
			String servicerUserid = corpKfServiceIds.get(RandomUtil.randomInt(corpKfServiceIds.size()));
			//变更会话状态
			transCorpKfSessionToServicer(corpId, openKfId, null, servicerUserid, externalUserid, null, 3, sendDate, msgid);
			return;
		}
		//移入未接入的客服
		List<String> collect = corpKfServicerDtos.stream().map(CorpKfServicerDto::getServicerUserid).collect(Collectors.toList());
		corpKfServiceIds.forEach(serviceId -> {
			if (!collect.contains(serviceId)) {
				CorpKfServicerDto corpKfServicerDto = new CorpKfServicerDto();
				corpKfServicerDto.setServicerUserid(serviceId);
				corpKfServicerDto.setNum(0);
				corpKfServicerDtos.add(corpKfServicerDto);
			}
		});
		//筛选符合条件的客服
		//默认接入最少的优先分配 接待人最少的在集合前面
		//不超过最多接待人数 默认30
		Integer maxNum = Optional.ofNullable(corpKfAccountSessionConfig.getMaxNum()).orElse(30);
		List<CorpKfServicerDto> filterKfCs = corpKfServicerDtos.stream().filter(kfCs -> corpKfServiceIds.contains(kfCs.getServicerUserid()) && kfCs.getNum() < maxNum).collect(Collectors.toList());
		if (CollUtil.isEmpty(filterKfCs)) {
			log.info("当前客服账号:{}值班接待上限:{},将客户:{}移入等待池", openKfId, maxNum, externalUserid);
			//发送进入等待池消息
			sendCorpKfTextTips(corpId, externalUserid, openKfId, corpKfAccountSessionConfig.getQueueTips());
			//移入等待池
			moveWaitingQueue(corpId, openKfId, externalUserid);
			return;
		}
		//选择第一个分配接待
		CorpKfServicerDto corpKfServicerDto = filterKfCs.get(0);
		//变更会话状态
		transCorpKfSessionToServicer(corpId, openKfId, null, corpKfServicerDto.getServicerUserid(), externalUserid, null, 3, sendDate, msgid);
	}

	private void moveWaitingQueue(String corpId, String openKfId, String externalUserId) throws Exception {
		CorpKfWaitingQueueUser corpKfWaitingQueueUser = new CorpKfWaitingQueueUser();
		corpKfWaitingQueueUser.setOpenKfId(openKfId);
		corpKfWaitingQueueUser.setExternalUserid(externalUserId);
		try {
			corpKfWaitingQueueUserMapper.insert(corpKfWaitingQueueUser);
			//移入等待池
			wxCorpOps.moveWaitingQueue(corpId, openKfId, externalUserId);
		} catch (DuplicateKeyException e) {

		}
	}

	/**
	 * 设置临时素材url
	 */
	private void setMediaUrl(CorpKfAccountSessionChat corpKfAccountSessionChat, String mediaId) throws Exception {
		String url = wxCorpOps.getMedia(null, mediaId);
		corpKfAccountSessionChat.setUrl(url);
	}

	/**
	 * 新增记录
	 */
	public void saveChatMsg(CorpKfAccountSessionChat chat) {
		CorpKfServicerSessionRecord corpKfServicerSessionRecord = corpKfServicerSessionRecordMapper.selectOne(Wrappers.lambdaQuery(CorpKfServicerSessionRecord.class)
				.eq(CorpKfServicerSessionRecord::getOpenKfId, chat.getOpenKfId())
				.eq(CorpKfServicerSessionRecord::getExternalUserid, chat.getExternalUserid())
				.orderByDesc(CorpKfServicerSessionRecord::getId)
				.eq(CorpKfServicerSessionRecord::getServiceState, 0)
				.last("limit 1"));
		if (corpKfServicerSessionRecord != null) chat.setSessionId(corpKfServicerSessionRecord.getId());
		corpKfAccountSessionChatMapper.insert(chat);
	}

	/**
	 * 设置会话记录状态
	 */
	public void setDbSessionState(String openKfId, String servicerUserid, String externalUserId, Date sendDate, Integer changeType, String msgid, String msgCode) throws Exception {
		CorpKfServicerSessionRecord corpKfServicerSessionRecord = corpKfServicerSessionRecordMapper.selectOne(Wrappers.lambdaQuery(CorpKfServicerSessionRecord.class)
				.eq(CorpKfServicerSessionRecord::getOpenKfId, openKfId)
				.eq(CorpKfServicerSessionRecord::getServicerUserid, servicerUserid)
				.eq(CorpKfServicerSessionRecord::getExternalUserid, externalUserId)
				.eq(CorpKfServicerSessionRecord::getServiceState, 0)
				.last("limit 1"));
		if (corpKfServicerSessionRecord != null) {
			//同步用户该次接待记录
			syncUserChatSession(corpKfServicerSessionRecord.getId(), externalUserId);
			corpKfServicerSessionRecord.setCloseTime(sendDate);
			corpKfServicerSessionRecord.setServiceState(changeType != 2 ? 1 : changeType);
			if (changeType != 2) {
				try {
					wxCorpOps.sendSatisfactionMsg(corpKfServicerSessionRecord.getMsgid(), openKfId, externalUserId, msgCode);
					corpKfServicerSessionRecord.setSendSatisfaction(true);
				} catch (Exception e) {
					log.error("发送满意度调查内容错误：{}", StringUtil.getErrorText(e));
				}
			}
			corpKfServicerSessionRecordMapper.updateById(corpKfServicerSessionRecord);
		}
	}

	/**
	 * 删除等待池中用户
	 *
	 * @param openKfId
	 * @param externalUserid
	 */
	public void delQueueUser(String openKfId, String externalUserid, Date sendDate) {
		//等待用户删除
		Optional.ofNullable(corpKfWaitingQueueUserMapper.selectOne(Wrappers.lambdaQuery(CorpKfWaitingQueueUser.class)
				.eq(CorpKfWaitingQueueUser::getOpenKfId, openKfId)
				.eq(CorpKfWaitingQueueUser::getExternalUserid, externalUserid)
				.le(CorpKfWaitingQueueUser::getCreatedTime, sendDate)
				.last("limit 1"))).ifPresent(queueUser -> corpKfWaitingQueueUserMapper.deleteById(queueUser.getId()));
	}

	/**
	 * 获取当前值班客服
	 */
	public Set<String> getDutyFollowIds(String openKfId) throws Exception {
		DateTime now = DateTime.now();
		String thisHourDate = DateUtil.format(now, "HH:mm");
		//星期天为1
		int dayOfWeek = DateUtil.dayOfWeek(now);
		//是否值班期
		List<CorpKfAccountFollow> corpKfAccountFollows = corpKfAccountFollowMapper.selectList(Wrappers.lambdaQuery(CorpKfAccountFollow.class)
				.eq(CorpKfAccountFollow::getOpenKfId, openKfId)
				.le(CorpKfAccountFollow::getStartTime, thisHourDate)
				.ge(CorpKfAccountFollow::getEndTime, thisHourDate)
				.eq(CorpKfAccountFollow::getDutyWeek, dayOfWeek));

		//目前时间段需要值班的客服
		Set<String> thisHourDutyFollows = new HashSet<>();
		for (CorpKfAccountFollow corpKfAccountFollow : corpKfAccountFollows) {
			thisHourDutyFollows.addAll(Jsons.parseList(corpKfAccountFollow.getUserIdList(), String.class));
		}
		return thisHourDutyFollows;
	}

	/**
	 * 同步接待用户聊天会话id
	 */
	public void syncUserChatSession(Long sessionId, String externalUserid) {
		//同步用户该次接待记录
		corpKfAccountSessionChatMapper.update(null, Wrappers.lambdaUpdate(CorpKfAccountSessionChat.class)
				.set(CorpKfAccountSessionChat::getSessionId, sessionId)
				.eq(CorpKfAccountSessionChat::getExternalUserid, externalUserid)
				.isNull(CorpKfAccountSessionChat::getSessionId));
	}
}