package org.springblade.flow.shop.task;

import cn.hutool.core.convert.Convert;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yeepay.yop.sdk.service.common.response.YopResponse;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.TaskService;
import org.flowable.task.api.Task;
import org.springblade.common.cache.FlowCache;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.flow.business.constant.AuditCandidate;
import org.springblade.flow.business.service.FlowBusinessService;
import org.springblade.flow.core.entity.BladeFlow;
import org.springblade.flow.shop.entity.AuthInfoData;
import org.springblade.flow.shop.entity.ShopEnum;
import org.springblade.gateway.shop_gateway.service.IAppShopService;
import org.springblade.ldt.shop.entity.Audit;
import org.springblade.ldt.shop.entity.Shop;
import org.springblade.ldt.shop.service.IAuditService;
import org.springblade.ldt.shop.service.IShopService;
import org.springblade.wx.config.ConfigForShop;
import org.springblade.wx.constant.MessageTemplate;
import org.springblade.wx.constant.MiniProgramType;
import org.springblade.wx.service.WeChatService;
import org.springblade.wx.utils.UrlTransform;
import org.springblade.yeePay.common.YeepayApiConstant;
import org.springblade.yeePay.service.YeepaySaasService;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

/**
 * @author: lianghanqiang
 * @description: 查询微信实名认证状态
 * @since: 9/17/21 -- 5:24 PM
 */
@Component
@AllArgsConstructor
@Slf4j
public class QueryAuthStatus {

	private YeepaySaasService yeepaySaasService;
	private FlowBusinessService flowBusinessService;
	private WeChatService weChatService;
	private ConfigForShop configForShop;
	private IAuditService auditService;
	private IShopService shopService;
	private TaskService taskService;
	private IAppShopService appShopService;

	/**
	 * 5分钟轮询微信认证列表
	 * 用户申请状态待认证就通知用户进行账户确认
	 */
	@Scheduled(cron = "0 */1 * * * ?")
	void queryStatus() {
		//查询当前微信认证队列各个状态
		Set<AuthInfoData> authList = FlowCache.authList();
		if (Objects.isNull(authList)) {
			log.info("暂无认证队列");
			return;
		}
		authList.parallelStream().forEach(item -> {
			try {
				YopResponse yopResponse = yeepaySaasService.wechatAuthQuery(item);
				JSONObject resObj = JSON.parseObject(yopResponse.getStringResult());
				String applymentState = resObj.getString("applymentState");

				//不操作状态
				boolean noOperate = Objects.equals(YeepayApiConstant.applymentState.APPLYMENT_STATE_WAITTING_FOR_AUDIT.name(), applymentState) ||
					Objects.equals(YeepayApiConstant.applymentState.APPLYMENT_STATE_EDITTING.name(), applymentState) ||
					Objects.equals(YeepayApiConstant.applymentState.APPLYMENT_STATE_WAITTING_FOR_CONFIRM_LEGALPERSON.name(), applymentState) ||
					Objects.equals(YeepayApiConstant.applymentState.APPLYMENT_STATE_CANCELED.name(), applymentState);
				if (noOperate) {
					return;
				}

				//状态为待用户验证
				boolean confirm = Objects.equals(YeepayApiConstant.applymentState.APPLYMENT_STATE_WAITTING_FOR_CONFIRM_CONTACT.name(), applymentState);
				if (confirm) {
					prepareForAuth(item, resObj);
				}

				//状态为已完成认证
				boolean passed = Objects.equals(YeepayApiConstant.applymentState.APPLYMENT_STATE_PASSED.name(), applymentState) ||
					Objects.equals(YeepayApiConstant.applymentState.APPLYMENT_STATE_FREEZED.name(), applymentState) ||
					Objects.equals(YeepayApiConstant.applymentState.COMPLETED.name(), applymentState);
				if (passed) {
					completeFlow(item, resObj.getString("rejectReason"));
				}

				//状态为驳回
				boolean rejected = Objects.equals(YeepayApiConstant.applymentState.APPLYMENT_STATE_REJECTED.name(), applymentState);
				if (rejected) {
					applyReject(item, resObj.getString("rejectReason"));
				}

			} catch (Exception e) {
				log.error(String.format("查询微信认证状态异常：%s", e.getMessage()));
				applyReject(item, String.format("查询微信认证状态异常：%s", e.getMessage()));
			}
		});
	}

	/***
	 * 用户申请驳回
	 * */
	public void applyReject(AuthInfoData item, String failReason) {
		log.info(String.format("商户实名申请驳回，商户:%s;驳回原因：%s", item.getAudit().getShortName(), failReason));
		Audit audit = auditService.getById(Convert.toLong(item.getVariables().get("auditId")));
		Shop shop = shopService.getById(Convert.toLong(item.getVariables().get("shopId")));
		audit.setAuditStatus(ShopEnum.FAIL.name());
		shop.setAuditStatus(ShopEnum.FAIL.name());
		List<Task> list = taskService.createTaskQuery().processInstanceId(audit.getProcessInstanceId()).taskAssignee(AuditCandidate.$INITIATOR.name()).active().list();
		Task task = list.get(0);
		taskService.addComment(task.getId(), task.getProcessInstanceId(), failReason);
		Assert.isTrue(auditService.saveOrUpdate(audit), () -> {
			throw new ServiceException("商户：\"+shop.getId()+\" 完成商户认证--》 更新资料失败！");
		});
		Assert.isTrue(shopService.saveOrUpdate(shop), () -> {
			throw new ServiceException("商户：\"+shop.getId()+\" 完成商户认证--》 更新审核状态失败！");
		});
		FlowCache.removeAuthMember(item);
	}

	/**
	 * 用户已完成授权，流程完成
	 */
	@Transactional
	public void completeFlow(AuthInfoData item, String failReason) {
		Audit audit = auditService.getById(Convert.toLong(item.getVariables().get("auditId")));
		Shop shop = shopService.getById(Convert.toLong(item.getVariables().get("shopId")));
		BladeFlow bladeFlow = new BladeFlow();
		bladeFlow.setAssignee("$INITIATOR");
		bladeFlow.setProcessInstanceId(audit.getProcessInstanceId());

		IPage<BladeFlow> bladeFlowIPage = flowBusinessService.selectTodoPage(new Page<BladeFlow>(), bladeFlow);
		BladeFlow task = bladeFlowIPage.getRecords().get(0);
		Assert.notNull(task, () -> {
			throw new ServiceException("商户：" + shop.getId() + " 完成商户认证--》 查询流程任务失败！");
		});

		task.setPass(Boolean.TRUE);
		task.setComment("商户入驻成功！");
		task.getVariables().put("applyPass", Boolean.TRUE);
		task.getVariables().put("failReason", failReason);
		audit.setAuditStatus(ShopEnum.PASS.name());
		shop.setAuditStatus(ShopEnum.PASS.name());

		//配置小程序信息
		appShopService.configApp(shop);

		Assert.isTrue(flowBusinessService.completeTask(task), () -> {
			throw new ServiceException("商户：\"+shop.getId()+\" 完成商户认证--》 执行任务失败！");
		});
		Assert.isTrue(auditService.saveOrUpdate(audit), () -> {
			throw new ServiceException("商户：\"+shop.getId()+\" 完成商户认证--》 更新资料失败！");
		});
		Assert.isTrue(shopService.saveOrUpdate(shop), () -> {
			throw new ServiceException("商户：\"+shop.getId()+\" 完成商户认证--》 更新审核状态失败！");
		});

		FlowCache.removeAuthMember(item);
	}


	/**
	 * 通知用户
	 */
	private void sendMessageToUser(AuthInfoData item) {
		try {

			//短信通知
//			String phone = item.getShop().getPersonTel();
//			SmsData smsData = new SmsData(new HashMap(4){{ put("",configForShop.getAppName());}});
//			SmsUtil.getBuilder().template(SmsCodeEnum.NOTIFY_SIGN.name()).sendSingle(smsData,phone);

			//微信模板消息
			String openId = item.getShop().getOpenId();
			String contentStr = String.format(MessageTemplate.INVITATION_SIGN.getContentString(), configForShop.getAppName(), "进入小程序完成认证");
			JSONObject content = JSON.parseObject(contentStr);
			weChatService.sendTemplateMessage(openId, MessageTemplate.INVITATION_SIGN, content, configForShop.getAuthPage(), MiniProgramType.SHOP);

		} catch (Exception e) {
			e.printStackTrace();
		}
	}


	/**
	 * 认证二维码写进流程变量
	 */
	private void notifyUserTask(AuthInfoData item, JSONObject resObj) {
		Audit audit = auditService.getById(Convert.toLong(item.getVariables().get("auditId")));
		Shop shop = shopService.getById(audit.getEntityId());
		BladeFlow bladeFlow = new BladeFlow();
		bladeFlow.setAssignee("$INITIATOR");
		bladeFlow.setProcessInstanceId(audit.getProcessInstanceId());

		IPage<BladeFlow> bladeFlowIPage = flowBusinessService.selectTodoPage(new Page<BladeFlow>(), bladeFlow);
		BladeFlow task = bladeFlowIPage.getRecords().get(0);

		Map<String, Object> variables = task.getVariables();
		String authUrl = resObj.getString("qrcodeUrl");
		variables.put("qrcodeUrl", UrlTransform.cheakUrl(authUrl));
		taskService.setVariables(task.getTaskId(), variables);
		shop.setAuditStatus(ShopEnum.WAITING_AUTH.name());
		audit.setAuditStatus(ShopEnum.WAITING_AUTH.name());
		shopService.saveOrUpdate(shop);
		auditService.saveOrUpdate(audit);
	}


	private void prepareForAuth(AuthInfoData item, JSONObject resObj) {
//		if( Objects.isNull(item.getIsNotify()) || !item.getIsNotify()){
//
//		}
		FlowCache.removeAuthMember(item);
		try {
			notifyUserTask(item, resObj);
			sendMessageToUser(item);
			item.setIsNotify(Boolean.TRUE);
		} catch (Exception e) {
			log.error("通知用户认证异常：" + e.getMessage());
		} finally {
			FlowCache.addAuthMember(item);
		}
	}


}
