package com.cyksj.service.corp.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
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.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.model.dto.WxCorpEncryptDto;
import com.cyksj.model.entity.*;
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.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;

/*
 *项目名: 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;

	@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()
		;

	}

	@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));
		}

	}
}