package com.cyksj.service.sys.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cyksj.common.EnvCommonService;
import com.cyksj.common.constant.Constant;
import com.cyksj.common.exception.BusinessRuntimeException;
import com.cyksj.common.util.Jsons;
import com.cyksj.common.util.SmsUtil;
import com.cyksj.common.util.StringUtil;
import com.cyksj.enums.GatewayApiCode;
import com.cyksj.mapper.corp.CorpCustomerAcquisitionLinkMapper;
import com.cyksj.mapper.corp.CorpFollowActiveCodeMapper;
import com.cyksj.mapper.manage.cms.CmsUserMapper;
import com.cyksj.mapper.sys.SysConfigChangeRecordMapper;
import com.cyksj.model.dto.SysServiceChangeDto;
import com.cyksj.model.dto.YhServiceChangeDto;
import com.cyksj.model.dto.YhServiceDto;
import com.cyksj.model.dto.YhServiceNameDto;
import com.cyksj.model.entity.CmsUser;
import com.cyksj.model.entity.CorpCustomerAcquisitionLink;
import com.cyksj.model.entity.CorpFollowActiveCode;
import com.cyksj.model.entity.SysConfigChangeRecord;
import com.cyksj.model.request.corp.link.Range;
import com.cyksj.model.request.corp.link.WxCpLinkAddResp;
import com.cyksj.model.request.corp.link.WxCpLinkUpd;
import com.cyksj.redis.RedisService;
import com.cyksj.service.corp.CorpFollowDynamicConfigService;
import com.cyksj.service.corp.WxCorpOps;
import com.cyksj.service.sys.SysConfigChangeRecordService;
import com.cyksj.service.sys.SysCorpServiceRelateService;
import com.cyksj.xxljob.XxlJobInfo;
import com.cyksj.xxljob.XxlJobUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.DayOfWeek;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * 项目名: yhlxj
 * 文件名: SysConfigChangeRecordServiceImpl
 * 创建者: JavaZou
 * 创建时间:2023/11/24 10:44
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class SysConfigChangeRecordServiceImpl extends ServiceImpl<SysConfigChangeRecordMapper, SysConfigChangeRecord> implements SysConfigChangeRecordService {
	private final CmsUserMapper cmsUserMapper;

	private final EnvCommonService envCommonService;

	private final RedisService redisService;

	private final CorpFollowActiveCodeMapper corpFollowActiveCodeMapper;

	private final CorpFollowDynamicConfigService corpFollowDynamicConfigService;

	private final SysCorpServiceRelateService sysCorpServiceRelateService;

	private final CorpCustomerAcquisitionLinkMapper corpCustomerAcquisitionLinkMapper;

	private final WxCorpOps corpOps;

	@Override
	public SysServiceChangeDto changeRecord(Long adminId, String sysKey, String sysValue, String updateValue) throws Exception {
		CmsUser cmsUser = cmsUserMapper.selectById(adminId);
		if (cmsUser == null) {
			throw BusinessRuntimeException.getGatewayApiCode(GatewayApiCode.CMS_TOKEN_VALID);
		}
		SysServiceChangeDto sysServiceChangeDto = new SysServiceChangeDto();
		//保存客服系统配置key前后更新数据
		if (Constant.serviceKeys.contains(sysKey)) {
			if (!StrUtil.equals(sysValue, updateValue)) {
				SysConfigChangeRecord sysConfigChangeRecord = new SysConfigChangeRecord();
				sysConfigChangeRecord.setSysKey(sysKey);
				sysConfigChangeRecord.setPreValue(sysValue);
				sysConfigChangeRecord.setBackValue(updateValue);
				sysConfigChangeRecord.setOperator(cmsUser.getNickname());

				List<Integer> updateFollowIndxList = new ArrayList<>();
				if (Constant.serviceKeys.get(0).equals(sysKey)) {
					//变更记录
					List<YhServiceDto> before = Jsons.parseList(sysValue, YhServiceDto.class);
					List<YhServiceDto> after = Jsons.parseList(updateValue, YhServiceDto.class);
					//周末值班人员缺失 通知
					StringBuilder weekdayMsgNotifySb = new StringBuilder();
					//客服值班变更记录
					StringBuilder changeStr = new StringBuilder();
					AtomicInteger saturdaySelect = new AtomicInteger(0);
					AtomicInteger sundaySelect = new AtomicInteger(0);
					for (int i = 0; i < before.size(); i++) {
						YhServiceDto beforeServiceDto = before.get(i);
						//节假日按钮 关闭开启不做处理
						if (after.size() > i) {
							YhServiceDto afterServiceDto = after.get(i);
							//变更记录
							YhServiceChangeDto changeService = getChangeService(beforeServiceDto, afterServiceDto);
							if (changeService != null) {
								if (changeStr.length() > 0) {
									changeStr.append("；");
								}
								changeStr.append(changeService.toChangeString());
							}

							if ((StrUtil.equals(afterServiceDto.getSign(), "Saturday"))) {
								saturdaySelect.addAndGet(afterServiceDto.getSelect().size());
							}

							if (StrUtil.equals(afterServiceDto.getSign(), "Sunday")) {
								sundaySelect.addAndGet(afterServiceDto.getSelect().size());
							}
						}
					}
					if (saturdaySelect.get() != 0 && saturdaySelect.get() < 3) {
						weekdayMsgNotifySb.append("周六");
					}
					if (sundaySelect.get() != 0 && sundaySelect.get() < 3) {
						weekdayMsgNotifySb.append("周日");
					}
					if (changeStr.length() > 0) {
						sysConfigChangeRecord.setChangeStr(changeStr.toString());
					}
					DayOfWeek nowDayOfWeek = LocalDateTime.now().getDayOfWeek();
					if (weekdayMsgNotifySb.length() > 0 && (nowDayOfWeek == DayOfWeek.SATURDAY || nowDayOfWeek == DayOfWeek.SUNDAY) && envCommonService.isPrdEnv()) {
						//一个小时内 不重复发送
						if (redisService.setNx(RedisService.key.WEEKEND_DUTY_UNDERSTAFFED_NOTIFY.getName(), RedisService.key.WEEKEND_DUTY_UNDERSTAFFED_NOTIFY.getName(), RedisService.key.WEEKEND_DUTY_UNDERSTAFFED_NOTIFY.getTimeout())) {
							SmsUtil.sendLuoKey2Msg(Constant.DUTY_SERVICE_CHANGE_NOTIFY_PHONE, String.format(Constant.DUTY_SERVICE_CHANGE_MSG, weekdayMsgNotifySb));
						}
					}
					sysServiceChangeDto.setChangeCsImg(true);
				} else {
					List<YhServiceNameDto> before = Jsons.parseList(sysValue, YhServiceNameDto.class);
					Map<Integer, List<YhServiceNameDto>> afterIndxMap = Jsons.parseList(updateValue, YhServiceNameDto.class).stream().collect(Collectors.groupingBy(YhServiceNameDto::getIndx));
					before.forEach(e1 -> {
						List<YhServiceNameDto> serviceNameDtos = afterIndxMap.get(e1.getIndx());
						if (CollUtil.isNotEmpty(serviceNameDtos)) {
							YhServiceNameDto e2 = serviceNameDtos.get(0);
							if (e1.getIndx() == e2.getIndx() && !StrUtil.equals(e1.getFollowId(), e2.getFollowId())) {
								updateFollowIndxList.add(e1.getIndx());
							}
						}
					});
					if (CollUtil.isNotEmpty(updateFollowIndxList)) {
						sysServiceChangeDto.setChangeCsName(true);
						sysServiceChangeDto.setUpdateFollowIndxs(updateFollowIndxList);
					}
				}
				this.save(sysConfigChangeRecord);
			}
		}
		return sysServiceChangeDto;
	}


	public YhServiceChangeDto getChangeService(YhServiceDto beforeServiceDto, YhServiceDto afterServiceDto) {
		Integer index = beforeServiceDto.getIndex();
		String sign = beforeServiceDto.getSign();
		String date = beforeServiceDto.getDate();
		String workType = beforeServiceDto.getWorkType();

		Map<Integer, List<YhServiceDto.CustomerServiceDto>> afterIndxMap = afterServiceDto.getSelect().stream().collect(Collectors.groupingBy(YhServiceDto.CustomerServiceDto::getIndex));

		Map<Integer, List<YhServiceDto.CustomerServiceDto>> beforeIndxMap = beforeServiceDto.getSelect().stream().collect(Collectors.groupingBy(YhServiceDto.CustomerServiceDto::getIndex));

		List<String> beforeSelect = new ArrayList<>();
		List<String> afterSelect = new ArrayList<>();

		beforeServiceDto.getSelect().forEach(bfSelect -> {
			if (afterIndxMap.get(bfSelect.getIndex()) == null) {
				beforeSelect.add(bfSelect.getName());
			}
		});

		afterServiceDto.getSelect().forEach(afSelect -> {
			if (beforeIndxMap.get(afSelect.getIndex()) == null) {
				afterSelect.add(afSelect.getName());
			}
		});

		if (CollUtil.isNotEmpty(beforeSelect) || CollUtil.isNotEmpty(afterSelect)) {
			YhServiceChangeDto yhServiceChangeDto = new YhServiceChangeDto();
			yhServiceChangeDto.setSign(sign);
			yhServiceChangeDto.setIndex(index);
			yhServiceChangeDto.setDate(date);
			yhServiceChangeDto.setWorkType(workType);
			yhServiceChangeDto.setBeforeSelect(beforeSelect);
			yhServiceChangeDto.setAfterSelect(afterSelect);
			return yhServiceChangeDto;
		}
		return null;
	}

	@Override
	public void updateCorpFollowLinkConfig(List<Integer> updateFollowIndx) throws Exception {
		List<CorpFollowActiveCode> corpFollowActiveCodes = corpFollowActiveCodeMapper.selectActiveCodeByFollowIndx(updateFollowIndx);
		//去更新活码对应客服 成员id
		corpFollowActiveCodes.forEach(data -> {
			try {
				List<Integer> upUserIndxList = Jsons.parseList(data.getFollowStr(), Integer.class);
				List<String> up_followStrList = sysCorpServiceRelateService.getFollowIdsByRelateIds(upUserIndxList);
				String code_str = corpFollowDynamicConfigService.createCorpFollowActiveCode(up_followStrList, upUserIndxList, Constant.AC_CODE_KEY + data.getId(), data.getIsDuty());
				data.setCodeStr(code_str);
				Set<String> keys = redisService.keys(RedisService.key.CORP_FOLLOW_ACTIVE_CODE_KEY.getNameFormat(data.getId(), "*"));
				redisService.del(keys.toArray(String[]::new));
				corpFollowActiveCodeMapper.updateById(data);
			} catch (Exception e) {
				log.error("更换活码客服失败：{}", StringUtil.getErrorText(e));
			}
		});

		//去更新获客链接 成员id
		List<CorpCustomerAcquisitionLink> acquisitionLinks = corpCustomerAcquisitionLinkMapper.selectActiveCodeByFollowIndx(updateFollowIndx);
		AtomicBoolean isDutyTask = new AtomicBoolean(false);
		acquisitionLinks.forEach(link -> {
			try {
				WxCpLinkUpd wxCpLinkUpd = new WxCpLinkUpd();
				wxCpLinkUpd.setLinkName(link.getLinkName());
				wxCpLinkUpd.setLinkId(link.getLinkId());
				wxCpLinkUpd.setSkipVerify(link.getSkipVerify());
				Range range = new Range();
				//值班客服
				String userList;
				if (link.getIsDuty()) {
					userList = link.getChooseDutyUsers();
					if (!isDutyTask.get()) {
						isDutyTask.set(true);
					}
				} else {
					userList = link.getUserList();
				}
				List<String> followIds = sysCorpServiceRelateService.getFollowIdsByRelateIds(Jsons.parseList(userList, Integer.class));
				range.setUserList(followIds);
				wxCpLinkUpd.setRange(range);
				WxCpLinkAddResp wxCpLinkAddResp = corpOps.customerAcquisitionUpdateLink(null, wxCpLinkUpd);

				corpCustomerAcquisitionLinkMapper.updateById(link);

			} catch (Exception e) {

			}
		});
		if (isDutyTask.get()) {
			//立即执行客服值班定时任务
			XxlJobUtil.executeMarkDynamicRuleTagJob(XxlJobInfo.getExecuteTaskInstance(Constant.CORP_LINK_JOB_ID, StrUtil.EMPTY).toString());
		}
	}
}
