package com.qunzhixinxi.hnqz.admin.mq;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.qunzhixinxi.hnqz.admin.api.constant.CacheConstants;
import com.qunzhixinxi.hnqz.admin.api.constant.MqConstants;
import com.qunzhixinxi.hnqz.admin.api.dto.OladingCommonRequest;
import com.qunzhixinxi.hnqz.admin.api.entity.SysDept;
import com.qunzhixinxi.hnqz.admin.api.entity.SysUser;
import com.qunzhixinxi.hnqz.admin.entity.SysUserSub;
import com.qunzhixinxi.hnqz.admin.entity.dto.UserSignCertDTO;
import com.qunzhixinxi.hnqz.admin.enums.DelEnum;
import com.qunzhixinxi.hnqz.admin.enums.GigCallBackStatus;
import com.qunzhixinxi.hnqz.admin.enums.GigTypeEnum;
import com.qunzhixinxi.hnqz.admin.enums.LockEnum;
import com.qunzhixinxi.hnqz.admin.enums.OladingCertStatus;
import com.qunzhixinxi.hnqz.admin.enums.SubjectLocation;
import com.qunzhixinxi.hnqz.admin.service.SysDeptService;
import com.qunzhixinxi.hnqz.admin.service.SysUserService;
import com.qunzhixinxi.hnqz.admin.service.SysUserSubService;
import com.qunzhixinxi.hnqz.admin.service.gig.SysUserSignCertService;
import com.qunzhixinxi.hnqz.common.rabbitmq.annotation.RabbitMqComponent;
import com.qunzhixinxi.hnqz.common.rabbitmq.core.BaseRabbiMqHandler;
import com.qunzhixinxi.hnqz.common.rabbitmq.listenter.MqListener;
import com.qunzhixinxi.hnqz.common.taxhelper.enums.TaxHelperCertStatus;
import com.rabbitmq.client.Channel;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.messaging.handler.annotation.Header;

import java.time.LocalDateTime;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 接收用户签约认证的结果对列监听器
 */
@Slf4j
@AllArgsConstructor
@RabbitListener(queues = MqConstants.DIRECT_MODE_GIG_SIGN_CERT_RES_QUEUE)
@RabbitMqComponent(value = "gigSignCertReceiver")
public class GigSignCertReceiver extends BaseRabbiMqHandler<String> {

	private final SysDeptService sysDeptService;

	private final SysUserService sysUserService;

	private final SysUserSubService sysUserSubService;

	private final SysUserSignCertService sysUserSignCertService;

	private final RedisTemplate redisTemplate;

	/**
	 * 税邦云成功code
	 */
	private static final String TAXHELPER_SUCCESS_CODE = "2000";

	/**
	 * 易联成功code
	 */
	private static final String YEE_SUCCESS_CODE = "200";

    @RabbitHandler
    public void onMessage(String jsonStr, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) {
        super.onMessageAck(jsonStr, deliveryTag, channel, (MqListener<String>) (String result, Channel channel1) -> {

			log.info("直接队列：接收用户签约认证的结果，手动ACK，接收消息TAG:{},消息内容：{}", deliveryTag, result);

			Map<String, String> resMap = MapUtil.newHashMap(2);
			try {
				JSONObject jsonResult = JSONUtil.parseObj(result);
				String username = jsonResult.getStr("username");
				String entpriseCode = jsonResult.getStr("enterpriseCode");
				JSONObject subjectTypes = jsonResult.getJSONObject("subjectTypes");

				if (StrUtil.isBlank(username) || StrUtil.isBlank(entpriseCode) || subjectTypes.isEmpty()) {
					log.error("必传参数空！");
					resMap.put("key", String.format("%s_%s_%s", CacheConstants.USER_SIGN_CERT_RESPONSE_MQ_KEY, username, entpriseCode));
					resMap.put("res", JSONUtil.toJsonStr(subjectTypes));
					return resMap;
				}

				List<SysDept> deptList = sysDeptService.list(Wrappers.<SysDept>lambdaQuery()
						.eq(SysDept::getTaxCode, entpriseCode)
						.eq(SysDept::getDelFlag, DelEnum.NOT_DEL.val())
						.orderByDesc(SysDept::getCreateTime));
				if (CollUtil.isNotEmpty(deptList)) {
					SysDept dept = deptList.get(0);
					SysUser user = sysUserService.getOne(Wrappers.<SysUser>lambdaQuery()
							.eq(SysUser::getDeptId, dept.getDeptId())
							.eq(SysUser::getUsername, username)
							.eq(SysUser::getDelFlag, DelEnum.NOT_DEL.val())
							.eq(SysUser::getLockFlag, LockEnum.UN_LOCK.val()));
					if (user == null) {
						log.error("用户不存在！");
						return null;
					}
					// 根据不同渠道，更新对应的签约认证状态
					subjectTypes.forEach((s, o) -> {
						GigTypeEnum gigTypeEnum = Enum.valueOf(GigTypeEnum.class, s);
						JSONObject subjectResult = (JSONObject) o;

						switch (gigTypeEnum) {
							case TAX_HELPOR:
								this.taxHelperHandler(user, dept, subjectResult);
//								// 本次结果存入redis
//								log.info("缓存认证结果到redis：{}", JSONUtil.toJsonStr(subjectTypes));
//								redisTemplate.opsForValue().set(CacheConstants.USER_SIGN_CERT_RESPONSE_KEY + user.getUserId(),
//										JSONUtil.toJsonStr(subjectTypes), 1, TimeUnit.MINUTES);
								break;
							case REN_LI_JIA:
								// TODO
								break;
							case OLADING:
								this.oladingHandler(user, dept, subjectResult);
								break;
							case YEE:
								this.yeeHandler(user, dept, subjectResult);
								break;
							default:
						}
					});

				}

				resMap.put("key", String.format("%s_%s_%s", CacheConstants.USER_SIGN_CERT_RESPONSE_MQ_KEY, username, entpriseCode));
				resMap.put("res", JSONUtil.toJsonStr(subjectTypes));
			} catch (Exception e) {
				log.error("mq回调处理失败", e);
			}

			return resMap;
        });
    }

	/**
	 * 税邦云数据处理
	 *
	 * @param user
	 * @param dept
	 * @param subjectResult
	 */
    private void taxHelperHandler(SysUser user, SysDept dept, JSONObject subjectResult) {
		String code = subjectResult.getStr("code");
		String certStatus = subjectResult.getStr("certStatus");
		LocalDateTime now = LocalDateTime.now();
		TaxHelperCertStatus taxHelperCertStatus = Enum.valueOf(TaxHelperCertStatus.class, certStatus);
		// 拼接更新条件
		LambdaUpdateWrapper<SysUserSub> updateWrapper = Wrappers.<SysUserSub>lambdaUpdate()
				.eq(SysUserSub::getUserId, user.getUserId())
				.eq(SysUserSub::getDeptId, dept.getDeptId())
				.eq(SysUserSub::getSubjectLocation, SubjectLocation.LUO_SHU_YUN)
				.eq(SysUserSub::getGigType, GigTypeEnum.TAX_HELPOR)
				.set(SysUserSub::getCallbackStatus, GigCallBackStatus.RETURNED)
				.set(SysUserSub::getUpdateTime, now)
				.set(SysUserSub::getUpdateUser, 0)
				.set(SysUserSub::getCertRemark, JSONUtil.toJsonStr(subjectResult))
				.set(SysUserSub::getCertStatus, taxHelperCertStatus.getCode());

		// 如果认证失败了， 置空身份证和合身视频
		if (TaxHelperCertStatus.UNCHECKED_BIND.equals(taxHelperCertStatus)){
			updateWrapper.set(SysUserSub::getCertVideo1Url, null);
			updateWrapper.set(SysUserSub::getCertVideo2Url, null);
			updateWrapper.set(SysUserSub::getIdCardFrontUrl, null);
			updateWrapper.set(SysUserSub::getIdCardBackUrl, null);
		}


//		if (TAXHELPER_SUCCESS_CODE.equals(code)) {
//			// 成功并且是换绑卡的情况，则更新银行卡号
//			String cacheKeyPrefix = String.format("%s_%s_%s", CacheConstants.BIND_CARD_CONFIRM_NEW_BANK_CARD,
//					user.getUserId(), GigTypeEnum.TAX_HELPOR.name());
//			UserSignCertDTO userSignCertDTO = (UserSignCertDTO) redisTemplate.opsForValue().get(cacheKeyPrefix);
//			if (userSignCertDTO != null) {
//				if (StrUtil.isNotBlank(userSignCertDTO.getBankCardNumber())) {
//					updateWrapper.set(SysUserSub::getBankCardNumber, userSignCertDTO.getBankCardNumber());
//					updateWrapper.set(SysUserSub::getBankPhone, userSignCertDTO.getBankPhone());
//					// 更新user表银行卡
//					SysUser sysUser = new SysUser();
//					sysUser.setUserId(user.getUserId());
//					sysUser.setBankCardNumber(userSignCertDTO.getBankCardNumber());
//					sysUser.setBankPhone(userSignCertDTO.getBankPhone());
//					sysUserService.updateById(sysUser);
//				}
//				// redis删除银行卡号
//				redisTemplate.delete(cacheKeyPrefix);
//			}
//		}
		sysUserSubService.update(updateWrapper);

		// 结果放到redis
		Map<String, Map<String, String>> resultMap = new HashMap<>(1);
		Map<String, String> subMap = new HashMap<>(1);
		subMap.put("certStatus", certStatus);
		resultMap.put("LUO_SHU_YUN", subMap);
		String key = CacheConstants.USER_SIGN_CERT_RESPONSE_KEY + user.getUserId();
		log.info("缓存认证结果到redis：{}", JSONUtil.toJsonStr(resultMap));
		redisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(resultMap), 1, TimeUnit.MINUTES);
	}

	/**
	 * 易联数据处理
	 *
	 * @param user
	 * @param dept
	 * @param subjectResult
	 */
	private void yeeHandler(SysUser user, SysDept dept, JSONObject subjectResult) {
		String certStatus = subjectResult.getStr("certStatus");
		String uploadTaxPayerAgreementStatus = subjectResult.getStr("uploadTaxPayerAgreementStatus");
		LocalDateTime now = LocalDateTime.now();

		// 查询当前认证状态
		SysUserSub userSub = sysUserSubService.getOne(Wrappers.<SysUserSub>lambdaQuery()
				.eq(SysUserSub::getDeptId, dept.getDeptId())
				.eq(SysUserSub::getUserId, user.getUserId())
				.eq(SysUserSub::getSubjectLocation, SubjectLocation.YI_LIAN)
				.eq(SysUserSub::getGigType, GigTypeEnum.YEE));
		// 拼接更新条件
		LambdaUpdateWrapper<SysUserSub> updateWrapper = Wrappers.<SysUserSub>lambdaUpdate()
				.eq(SysUserSub::getUserId, user.getUserId())
				.eq(SysUserSub::getDeptId, dept.getDeptId())
				.eq(SysUserSub::getGigType, GigTypeEnum.YEE)
				.eq(SysUserSub::getSubjectLocation, SubjectLocation.YI_LIAN)
				.set(SysUserSub::getUpdateTime, now)
				.set(SysUserSub::getUpdateUser, 0)
				.set(SysUserSub::getCertRemark, JSONUtil.toJsonStr(subjectResult));
		// 如果是已签约并且当前不是已认证，则设置一下状态（处理阿拉丁没有回调的情况）
		if (OladingCommonRequest.SignUpStatus.SIGN.name().equals(certStatus)
				&& !OladingCertStatus.CERT.getCode().equals(String.valueOf(userSub.getCertStatus()))) {
			// 如果是已上传协议成功，则设置为已认证，否则还是已签约
			SysUser updateUser = new SysUser();
			Map<String, String> subMap = new HashMap<>();
			if (OladingCommonRequest.UploadTaxpayerAgreementStatus.SUCCESS.name().equals(uploadTaxPayerAgreementStatus)) {
				updateWrapper.set(SysUserSub::getCertStatus, Integer.parseInt(OladingCertStatus.CERT.getCode()));
				subMap.put("certStatus", OladingCertStatus.CERT.name());
			} else {
				updateWrapper.set(SysUserSub::getCertStatus, Integer.parseInt(OladingCertStatus.SIGNED.getCode()));
				subMap.put("certStatus", OladingCertStatus.SIGNED.name());
			}
			updateWrapper.set(SysUserSub::getCallbackStatus, GigCallBackStatus.RETURNED);
			// 修改步进状态
			updateUser.setUserId(user.getUserId());
			updateUser.setUpdateTime(now);
			sysUserService.updateById(updateUser);
			// 结果放到redis
			String key = CacheConstants.USER_SIGN_CERT_RESPONSE_KEY + userSub.getUserId();
			Map<String, Object> result = MapUtil.newHashMap(1);
			result.put("YI_LIAN", subMap);
			redisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(result), 1, TimeUnit.MINUTES);
		}
		// 已认证，则设置回调状态
		if (OladingCertStatus.CERT.getCode().equals(String.valueOf(userSub.getCertStatus()))) {
			updateWrapper.set(SysUserSub::getCallbackStatus, GigCallBackStatus.RETURNED);
		}

		sysUserSubService.update(updateWrapper);
	}

	/**
	 * 自由职家数据处理(这里只保存mq回调结果，实际业务处理放到阿拉丁直接回调接口里了)
	 *
	 * @param user
	 * @param dept
	 * @param subjectResult
	 */
	private void oladingHandler(SysUser user, SysDept dept, JSONObject subjectResult) {

		// 查询redis是否有同时发起的标记
		String oladingRedisKey = CacheConstants.OLADING_CERT_SEND_CHANNEL + user.getUserId();
		String gigTypeJson = (String) redisTemplate.opsForValue().get(oladingRedisKey);
		if (JSONUtil.isJsonArray(gigTypeJson)) {
			log.info("redis同时发起的标记:key={}, value={}", oladingRedisKey, gigTypeJson);
		}

		JSONArray gigTypeArray = JSONUtil.parseArray(gigTypeJson);

		// 根据选择的渠道，分别更新并查询认证状态
		Map<String, Map<String, String>> certResultMap = new LinkedHashMap<>(3);
		gigTypeArray.forEach(o -> certResultMap.put(String.valueOf(o),
				this.oladingChannelHandler(user, dept, subjectResult, Enum.valueOf(SubjectLocation.class, String.valueOf(o)))));

		// 结果放到redis
		Map<String, Map<String, String>> resultMap = new HashMap<>(3);
		if (gigTypeArray.size() > 1) {
			// 同时发起的情况，且是前一个渠道（按照redis存的渠道顺序发送）的状态已返回，则刷新状态到redis
			List<SubjectLocation> subjectLocationList = gigTypeArray.stream()
					.map(o -> Enum.valueOf(SubjectLocation.class, String.valueOf(o)))
					.collect(Collectors.toList());
			List<SysUserSub> subList = sysUserSubService.list(Wrappers.<SysUserSub>lambdaQuery()
					.eq(SysUserSub::getUserId, user.getUserId())
					.eq(SysUserSub::getDeptId, dept.getDeptId())
					.in(SysUserSub::getSubjectLocation, subjectLocationList));
			Map<String, Map<String, String>> dbResultMap = subList.stream()
					.collect(Collectors.toMap(sysUserSub -> sysUserSub.getSubjectLocation().name(),
							sysUserSub -> MapUtil.builder("certStatus",
									OladingCertStatus.resolve(String.valueOf(sysUserSub.getCertStatus())).name()).build()));
			resultMap.putAll(dbResultMap);
		} else {
			// 只有一个渠道的情况
			resultMap.putAll(certResultMap);
		}
		String key = CacheConstants.USER_SIGN_CERT_RESPONSE_KEY + user.getUserId();
		log.info("缓存认证结果到redis：{}", JSONUtil.toJsonStr(resultMap));
		redisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(resultMap), 1, TimeUnit.MINUTES);

		// 处理同时发起时阿拉丁多个渠道的情况（补发）
//		if (gigTypeArray.size() > 1) {
//			String firstChannel = String.valueOf(gigTypeArray.get(0));
//			// 查询阿拉丁第一个渠道的认证状态
//			Map<String, String> certStatusMap = resultMap.get(firstChannel);
//			// 查询阿拉钉第一个未签约的渠道
//			String toSendChannel = "";
//			for (Map.Entry<String, Map<String, String>> entry : resultMap.entrySet()) {
//				if (OladingCertStatus.UN_SIGNED.name().equals(entry.getValue().get("certStatus"))) {
//					toSendChannel = entry.getKey();
//					break;
//				}
//			}
//			// 校验需要补发的渠道，是否为第一个
//			if (StrUtil.isNotBlank(toSendChannel) && !StrUtil.equals(firstChannel, toSendChannel)) {
//				// 如果阿拉丁第一个渠道是已认证的，则补发下一个阿拉丁的渠道(由于阿拉钉同一人不同渠道的回调只有一次，所以这里出现多个渠道需要依次补发)
//				if (CollUtil.isNotEmpty(certStatusMap) && OladingCertStatus.CERT.name().equals(certStatusMap.get("certStatus"))) {
//					log.info("=============================补发阿拉钉另一渠道MQ:{}==================================", toSendChannel);
//					UserSignCertDTO reCertDTO = new UserSignCertDTO();
//					reCertDTO.setUserId(user.getUserId());
//					reCertDTO.setGigTypeList(Collections.singletonList(Enum.valueOf(GigTypeEnum.class, toSendChannel)));
//					sysUserSignCertService.batchChannelCert(reCertDTO);
//				}
//			}
//		}
	}

	/**
	 * 自由职家渠道的数据处理
	 *
	 * @param user
	 * @param dept
	 * @param subjectResult
	 * @param subjectLocation
	 * @return
	 */
	private Map<String, String> oladingChannelHandler(SysUser user, SysDept dept, JSONObject subjectResult, SubjectLocation subjectLocation) {
		String certStatus = subjectResult.getStr("certStatus");
		String uploadTaxPayerAgreementStatus = subjectResult.getStr("uploadTaxPayerAgreementStatus");
		LocalDateTime now = LocalDateTime.now();
		Map<String, String> certStatusMap = new HashMap<>();
		certStatusMap.put("certStatus", OladingCertStatus.UN_SIGNED.name());

		// 查询当前认证状态
		SysUserSub userSub = sysUserSubService.getOne(Wrappers.<SysUserSub>lambdaQuery()
				.eq(SysUserSub::getDeptId, dept.getDeptId())
				.eq(SysUserSub::getUserId, user.getUserId())
				.eq(SysUserSub::getCallbackStatus, GigCallBackStatus.IN_PROGRESS)
				.eq(SysUserSub::getGigType, subjectLocation.getGigType())
				.eq(SysUserSub::getSubjectLocation, subjectLocation));
		if (userSub == null) {
			return certStatusMap;
		}

		// 拼接更新条件
		LambdaUpdateWrapper<SysUserSub> updateWrapper = Wrappers.<SysUserSub>lambdaUpdate()
				.eq(SysUserSub::getUserId, user.getUserId())
				.eq(SysUserSub::getDeptId, dept.getDeptId())
				.eq(SysUserSub::getGigType, subjectLocation.getGigType())
				.eq(SysUserSub::getSubjectLocation, subjectLocation)
				.set(SysUserSub::getUpdateTime, now)
				.set(SysUserSub::getUpdateUser, 0)
				.set(SysUserSub::getCertRemark, JSONUtil.toJsonStr(subjectResult));
		// 如果是已签约并且当前不是已认证，则设置一下状态（处理阿拉丁没有回调的情况）
		if (OladingCommonRequest.SignUpStatus.SIGN.name().equals(certStatus)
				&& !OladingCertStatus.CERT.getCode().equals(String.valueOf(userSub.getCertStatus()))) {
			// 如果是已上传协议成功，则设置为已认证，否则还是已签约
			if (OladingCommonRequest.UploadTaxpayerAgreementStatus.SUCCESS.name().equals(uploadTaxPayerAgreementStatus)) {
				updateWrapper.set(SysUserSub::getCertStatus, Integer.parseInt(OladingCertStatus.CERT.getCode()));
				updateWrapper.set(SysUserSub::getCallbackStatus, GigCallBackStatus.RETURNED);
				certStatusMap.put("certStatus", OladingCertStatus.CERT.name());
			} else {
				updateWrapper.set(SysUserSub::getCertStatus, Integer.parseInt(OladingCertStatus.SIGNED.getCode()));
				certStatusMap.put("certStatus", OladingCertStatus.SIGNED.name());
			}
		}
		// 如果是签约中，则判断'阿拉丁签约方法'状态
		if (OladingCommonRequest.SignUpStatus.SIGNING.name().equals(certStatus)) {
			JSONObject stageResult = subjectResult.getJSONObject("stageResult");
			JSONObject oladingSignUpResult = stageResult.getJSONObject("阿拉丁签约方法");
			if (oladingSignUpResult != null && StrUtil.equals("1005", oladingSignUpResult.getStr("code"))) {
				updateWrapper.set(SysUserSub::getCallbackStatus, GigCallBackStatus.RETURNED);
			}
		}
		// 已认证，则设置回调状态
		// 此处实际是处理核身视频的回调
		if (OladingCertStatus.CERT.getCode().equals(String.valueOf(userSub.getCertStatus()))) {
			updateWrapper.set(SysUserSub::getCallbackStatus, GigCallBackStatus.RETURNED);
			certStatusMap.put("certStatus", OladingCertStatus.CERT.name());
		}

		sysUserSubService.update(updateWrapper);

		return certStatusMap;
	}

}