package org.springblade.payment.handle;

import cn.hutool.core.convert.Convert;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springblade.common.cache.PaymentCache;
import org.springblade.common.enums.*;
import org.springblade.common.utils.TradeException;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.gateway.shop_gateway.service.IAppShopService;
import org.springblade.ldt.bills.entity.Bills;
import org.springblade.ldt.bills.service.IBillsService;
import org.springblade.payment.entity.SuccessParams;
import org.springblade.payment.event.UserPayCsEvent;
import org.springblade.payment.handle.entity.HandleData;
import org.springblade.payment.handle.entity.Order;
import org.springblade.payment.handle.handler.*;
import org.springblade.payment.listener.sender.OrderSend;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

/**
 * @author: lianghanqiang
 * @description: 交易处理, 总控交易处理链
 * @since: 8/26/21 -- 5:53 PM
 */
@Component
@AllArgsConstructor
@Slf4j
public class Trade {

	private IBillsService billsService;
	private DataHandle dataHandle;
	private BalanceHandle balanceHandle;
	private ChannelPointHandle channelPointHandle;
	private DiscountHandle discountHandle;
	private WxPayHandle wxPayHandle;
	private IAppShopService appShopService;
	private ApplicationEventPublisher applicationEventPublisher;
	private OrderSend orderSend;

	//
//	@Transactional
//	public boolean tradeForPayCode(Order order, long channelId) throws Exception {
//		/**
//		 * 	交易处理链，每个handle处理负责一个业务节点
//		 * 	1、处理各种商家折扣,计算实际交易金额
//		 * 	2、用户渠道积分用以抵消交易金额
//		 * 	3、用户账户余额抵消交易金额
//		 * 	4、剩余金额用户微信支付
//		 * */
//		List<BaseHandle> chain = new ArrayList(){{
//			add(discountHandle);
//			add(channelPointHandle);
//			add(balanceHandle);
//			add(wxPayHandle);
//		}} ;
//
//	 	BigDecimal remain = order.getMoney();
//
//		//获取tenantId
//		String tenantId = appShopService.getTenantId(order.getShopId());
//		Bills bills = initBill(order,channelId,tenantId);
//
//		//支付参数
//		SuccessParams successParams  = SuccessParams.builder()
//			.orderType(OrderType.USER_PAY.name())
//			.status(AppConstant.BillPayStatus.待付款.name())
//			.userId(order.getLoginUser().getId())
//			.totalPrice(order.getMoney())
//			.bills(bills)
//			.shopId(order.getShopId())
//			.tenantId(tenantId)
//			.channelId(channelId)
//			.build();
//
//		//处理各个节点
//		for (BaseHandle node: chain) {
//			HandleData res = node.handle(remain, order,successParams);
//			Assert.isTrue(res.isSuccess(),()->{throw new ServiceException(ResCode.TRADE_ERROR);});
//			remain = res.getRemain();
//			successParams = res.getSuccessParams();
//
//			if(remain.compareTo(BigDecimal.ZERO)==0){
//				successParams.setStatus(AppConstant.BillPayStatus.付款成功.name());
//				dataHandle.saveOrUpdateEntity(billsService,successParams.getBills());
//				applicationEventPublisher.publishEvent(new UserPayCsEvent(successParams));
//				break;
//			}
//		}
//
//		//新建事务，保存订单信息，
//		Assert.isTrue(dataHandle.saveOrUpdateEntity(billsService,successParams.getBills()),()->{throw new ServiceException(ResCode.TRADE_ERROR);});
//		PaymentCache.putSuccessParams(Convert.toStr(successParams.getBills().getId()),successParams);
//	 	return true;
//	}
	@Transactional(rollbackFor = Exception.class)
	public SuccessParams tradeForScanPay(Order order, long channelId) {
		SuccessParams successParams = SuccessParams.builder().build();
		try {
			/**
			 * 	交易处理链，每个handle处理负责一个业务节点
			 * 	1、处理各种商家折扣,计算实际交易金额
			 * 	2、用户渠道积分用以抵消交易金额
			 * 	3、用户账户余额抵消交易金额
			 * 	4、保存订单信息
			 * */
			List<BaseHandle> chain = new ArrayList() {{
				add(discountHandle);
				add(channelPointHandle);
				add(balanceHandle);
				add(wxPayHandle);
			}};

			BigDecimal remain = order.getMoney();

			//获取tenantId
			String tenantId = appShopService.getTenantId(order.getShopId());
			Bills bills = initBill(order, channelId, tenantId);

			//支付参数
			successParams = SuccessParams.builder()
				.orderType(OrderType.USER_PAY.name())
				.status(AppConstant.BillPayStatus.待付款.name())
				.userId(order.getLoginUser().getId())
				.totalPrice(order.getMoney())
				.bills(bills)
				.shopId(order.getShopId())
				.tenantId(tenantId)
				.channelId(channelId)
				.build();

			//处理各个节点
			for (BaseHandle node : chain) {
				HandleData res = node.handle(remain, order, successParams);
				Assert.isTrue(res.isSuccess(), () -> {
					throw new TradeException(ResCode.TRADE_ERROR, res.getSuccessParams());
				});
				remain = res.getRemain();
				successParams = res.getSuccessParams();

				if (remain.compareTo(BigDecimal.ZERO) == 0) {
					successParams.setStatus(AppConstant.BillPayStatus.付款成功.name());
					bills.setPayStatus(AppConstant.BillPayStatus.付款成功.name());
					dataHandle.saveOrUpdateEntity(billsService, successParams.getBills());
					dataHandle.publishEvent(new UserPayCsEvent(successParams));
					break;
				}
			}

			//新建事务，保存订单信息，
			SuccessParams finalSuccessParams = successParams;
			Assert.isTrue(dataHandle.saveOrUpdateEntity(billsService, successParams.getBills()), () -> {
				throw new TradeException(ResCode.TRADE_ERROR, finalSuccessParams);
			});
			PaymentCache.putSuccessParams(Convert.toStr(successParams.getBills().getId()), successParams);

			//判断是否是待付款
			if (StringUtils.equals(successParams.getStatus(), AppConstant.BillPayStatus.待付款.name())) {
				//发送消息队列
				orderSend.sendOrderMessage(successParams);
			}
			return successParams;
		} catch (Exception e) {
			e.printStackTrace();
			throw new TradeException(ResCode.TRADE_ERROR, successParams);
		}

	}


	/**
	 * 初始化交易账单
	 */
	private Bills initBill(Order order, long channelId, String tenantId) {
		Bills bills = new Bills();
		bills.setPayStatus(AppConstant.BillPayStatus.待付款.name());
		bills.setAppid(order.getAppId());
		bills.setCost(order.getMoney());
		bills.setOpenid(order.getOpenId());
		bills.setChannelId(Convert.toStr(channelId));
		bills.setType(OrderType.USER_PAY.name());
		bills.setPrice(BigDecimal.ZERO);
		bills.setOpenid(order.getLoginUser().getOpenid());
		bills.setFee(BigDecimal.ZERO);
		bills.setPointFee(BigDecimal.ZERO);
		bills.setTitle(order.getBillsTitle());
		bills.setPayId(order.getLoginUser().getId());
		bills.setReceiveId(order.getShopId());
		bills.setPayScene(PaymentScene.MINI_PROGRAM.name());
		bills.setMallId(order.getMallId());
		bills.setTenantId(tenantId);
		bills.setCsFlag(CsFlag.UN_CHECK);
		bills.setTotalPrice(order.getMoney());
		Assert.isTrue(dataHandle.saveOrUpdateEntity(billsService, bills), () -> {
			throw new ServiceException(ResCode.TRADE_ERROR);
		});
		return bills;
	}
}
