package org.springblade.payment.listener;

import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.yeepay.yop.sdk.service.common.response.YopResponse;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springblade.common.cache.PaymentCache;
import org.springblade.common.enums.AppConstant;
import org.springblade.common.enums.OrderType;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.tenant.annotation.TenantIgnore;
import org.springblade.gateway.common_gateway.entity.vo.BillSuccessEvent;
import org.springblade.ldt.bills.entity.BalanceBills;
import org.springblade.ldt.bills.entity.Bills;
import org.springblade.ldt.bills.service.IBalanceBillsService;
import org.springblade.ldt.bills.service.IBillsService;
import org.springblade.ldt.shop.entity.Shop;
import org.springblade.ldt.shop.service.IShopService;
import org.springblade.ldt.user.entity.LoginUser;
import org.springblade.ldt.user.entity.Member;
import org.springblade.ldt.user.service.ILoginUserService;
import org.springblade.ldt.user.service.IMemberService;
import org.springblade.payment.entity.SuccessParams;
import org.springblade.payment.handle.entity.HandleDivideData;
import org.springblade.yeePay.common.YeePayConst;
import org.springblade.yeePay.entity.saas.trade.DivideApplyDto;
import org.springblade.yeePay.entity.saas.trade.DivideCompleteDto;
import org.springblade.yeePay.entity.saas.trade.DivideQueryDto;
import org.springblade.yeePay.service.YeepaySaasService;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import java.math.BigDecimal;
import java.util.Collections;
import java.util.Objects;
import java.util.Set;

/**
 * @author: lianghanqiang
 * @description: 发起分账申请
 * @since: 10/11/21 -- 4:59 PM
 */
@Component
@AllArgsConstructor
@Slf4j
public class SubAccountHandle {

	private IBillsService billsService;
	private IBalanceBillsService balanceBillsService;
	private YeepaySaasService yeepaySaasService;
	private YeePayConst yeePayConst;
	private IShopService shopService;
	private ILoginUserService userService;
	private IMemberService memberService;
	private PlatformTransactionManager transactionManager;

	@EventListener
	@Async
	public void accountHandle(BillSuccessEvent billSuccessEvent) throws InterruptedException {

		//获取付款流水号数据
		SuccessParams successParams = billSuccessEvent.getSuccessParams();
		Bills bills = billsService.getById(successParams.getBills().getId());

		if (ObjectUtils.isEmpty(bills)) {
			throw new ServiceException("账单记录不存在！");
		}

		if(bills.getPrice().compareTo(BigDecimal.ZERO)==0){
			log.info(String.format("订单%s: 无需积分分账！",bills.getId()));
			return;
		}
		Shop shop = shopService.getById(bills.getReceiveId());

		//过5s再请求分账
		Thread.sleep(5000);

		//计算分账金额
//		BigDecimal amount = bills.getFee();
		BigDecimal amount = BigDecimal.ZERO;

		BalanceBills balanceBill = balanceBillsService.getOne(Wrappers.<BalanceBills>lambdaQuery().eq(BalanceBills::getTradeNo, bills.getId())
			.eq(BalanceBills::getType, OrderType.SHOP_SEND.name()));

		//计算赠送积分账单金额
		if (ObjectUtils.isNotEmpty(balanceBill)) {
//			amount = amount.add(balanceBill.getTotalPrice());
			amount = amount.add(balanceBill.getPrice().add(balanceBill.getFee()));
		}

		//分账
		if(amount.compareTo(BigDecimal.ZERO)>0){
			//申请分账
			String status = divideApply(shop, bills,amount);
			if (ObjectUtils.isNotEmpty(status)) {
				if (status.equals("SUCCESS")) {
					divideComplete(bills, shop);
				} else if (status.equals("PROCESSING")) {
					//放置队列中
					DivideQueryDto divideQueryDto = DivideQueryDto.builder()
						.parentMerchantNo(yeePayConst.getPlatformServiceNo())
						.merchantNo(shop.getMerchantNo())
						.orderId(String.valueOf(bills.getId()))
						.uniqueOrderNo(bills.getThirdOrderId())
						.divideRequestId(IdUtil.simpleUUID())
						.build();

					PaymentCache.addApply(HandleDivideData.builder()
						.divideQueryDto(divideQueryDto)
						.bills(bills).build());
				}
			}
		}else{
			divideComplete(bills,shop);
		}
	}

	/**
	 * 申请分账
	 */
	private String divideApply(Shop shop, Bills bills, BigDecimal amount) {

		//申请分账
		DivideApplyDto.DivideDetail divideDetail = DivideApplyDto.DivideDetail.builder()
			.ledgerNo(yeePayConst.getPlatformServiceNo())
			.amount(amount)
			.divideDetailDesc("商户赠送积分").build();

		String divideRequestId = IdUtil.simpleUUID();
		DivideApplyDto divideApplyDto = DivideApplyDto.builder()
			.parentMerchantNo(yeePayConst.getPlatformServiceNo())
			.merchantNo(shop.getMerchantNo())
			.orderId(String.valueOf(bills.getId()))
			.uniqueOrderNo(bills.getThirdOrderId())
			.divideRequestId(divideRequestId)
			.divideDetail(Collections.singletonList(divideDetail))
			.build();
		YopResponse yopResponse = yeepaySaasService.divideApply(divideApplyDto);
		JSONObject res = JSON.parseObject(yopResponse.getStringResult());
		if (!Objects.equals(res.getString("code"), "OPR00000")) {
			throw new ServiceException(res.getString("message"));
		}
		return res.getString("status");
	}

	/**
	 * 完结分账
	 */
	@TenantIgnore
	private void divideComplete(Bills bills, Shop shop) {
		handleSendBalanceBills(bills,shop);
		DivideCompleteDto divideCompleteDto = DivideCompleteDto.builder()
			.parentMerchantNo(yeePayConst.getPlatformServiceNo())
			.merchantNo(shop.getMerchantNo())
			.divideRequestId(IdUtil.simpleUUID())
			.orderId(String.valueOf(bills.getId()))
			.divideDetailDesc("完结分账")
			.uniqueOrderNo(bills.getThirdOrderId())
			.build();
		YopResponse yopResponse = yeepaySaasService.divideComplete(divideCompleteDto);
		JSONObject res = JSON.parseObject(yopResponse.getStringResult());
		if (!Objects.equals(res.getString("code"), "OPR00000")) {
			throw new ServiceException(res.getString("message"));
		}
	}

	/**
	 * 查询分账结果
	 */
	private boolean divideQuery(DivideQueryDto divideQueryDto) {
		boolean flag = true;
		YopResponse yopResponse = yeepaySaasService.divideQuery(divideQueryDto);
		JSONObject res = JSON.parseObject(yopResponse.getStringResult());
		if (!Objects.equals(res.getString("code"), "OPR00000")) {
			throw new ServiceException(res.getString("message"));
		}
		String status = res.getString("status");
		if (ObjectUtils.isNotEmpty(status)) {
			if (!status.equals("SUCCESS")) {
				flag = false;
			}
		}
		return flag;
	}

	/**
	 * 商户赠送用户积分
	 * @return
	 */
	void handleSendBalanceBills(Bills bills, Shop shop) {
		BalanceBills balanceBills = balanceBillsService.getOne(new QueryWrapper<BalanceBills>().lambda().eq(BalanceBills::getTradeNo,bills.getId()).eq(BalanceBills::getType, OrderType.SHOP_SEND.name()));
		TransactionStatus transaction = transactionManager.getTransaction(new DefaultTransactionDefinition());
		try {
			LoginUser user = userService.getById(bills.getPayId());

			//赠送积分账单状态更新
			if(!Objects.isNull(balanceBills)&&balanceBills.getPrice().compareTo(BigDecimal.valueOf(0.01))>=0){
				if(ObjectUtils.isNotEmpty(bills.getActualIncome())){
					bills.setActualIncome(bills.getActualIncome().subtract(balanceBills.getPrice()));
				}
				shop.setBalance(shop.getBalance().subtract(balanceBills.getPrice()));
				balanceBills.setPayStatus(AppConstant.BillPayStatus.付款成功.name());
				user.setBalance(user.getBalance().add(balanceBills.getPrice()));
			}

			//店铺会员管理
			Member member = memberService.getOne(new QueryWrapper<Member>().lambda()
				.eq(Member::getShopId, shop.getId())
				.eq(Member::getType,AppConstant.PLATFORM.SHOP.name())
				.eq(Member::getUserId, user.getId()));
			if(Objects.isNull(member)){
				member = initMember(shop,user,bills);
			}
			member.setPayTotal(member.getPayTotal().add(bills.getPrice()));
			member.setPointTotal(member.getPointTotal().add(balanceBills.getSendNum()));
			member.setPointValue(member.getPointValue().add(balanceBills.getPrice()));

			transactionManager.getTransaction(new DefaultTransactionDefinition());
			memberService.saveOrUpdate(member);
			userService.saveOrUpdate(user);
			balanceBillsService.saveOrUpdate(balanceBills);
			transactionManager.commit(transaction);
			billsService.updateById(bills);
		}catch (Exception e){
			transactionManager.rollback(transaction);
			if(!Objects.isNull(balanceBills)){
				balanceBills.setBillDesc(e.getMessage());
			}
			balanceBillsService.saveOrUpdate(balanceBills);
		}

	}

	@Scheduled(cron = "0 */1 * * * ?")
	public void handleProcessing() {
		Set<HandleDivideData> queue = PaymentCache.getApplyList();
		if (queue.size()>0) {
			log.info("定时任务开始，查询队列中的待处理的分账记录！,队列数：{}", queue.size());
			queue.forEach(handleDivideData -> {
				//查询分账结果
				log.info("进行分账结果查询：{}", handleDivideData.getDivideQueryDto().getOrderId());
				boolean isSuccess = divideQuery(handleDivideData.getDivideQueryDto());
				//如果还是待处理，放回队列中，否则进行完结分账操作
				if (!isSuccess) {
					log.info("仍是处理中，放回队列：{}", handleDivideData.getDivideQueryDto().getOrderId());
				}

				log.info("分账申请成功，现进行完结分账：{}", handleDivideData.getDivideQueryDto().getOrderId());
				Shop shop = shopService.getById(handleDivideData.getBills().getReceiveId());

//				handleSendBalanceBills(handleDivideData.getBills(),shop);
				divideComplete(handleDivideData.getBills(), shop);
				PaymentCache.completeApply(handleDivideData);
			});
		}
	}

	/**
	 * 初始化店铺会员
	 * */
	private Member initMember(Shop shop, LoginUser user, Bills bills){
		Member member = new Member();
		member.setShopId(shop.getId());
		member.setMallId(shop.getMallId());
		member.setUserId(user.getId());
		member.setPointValue(BigDecimal.ZERO);
		member.setPointTotal(BigDecimal.ZERO);
		member.setPayTotal(BigDecimal.ZERO);
		member.setAvatar(user.getAvatar());
		member.setNickName(user.getNickName());
		member.setPhone(user.getPhone());
		member.setType(AppConstant.PLATFORM.SHOP.name());
		member.setTenantId(bills.getTenantId());
		return member;
	}

}
