package org.springblade.yeePay.listener;

import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springblade.common.constant.SystemConstant;
import org.springblade.common.utils.MoneyDesUtil;
import org.springblade.core.tool.api.R;
import org.springblade.modules.guosen.bussiness.entity.Bussiness;
import org.springblade.modules.guosen.bussiness.entity.BussinessBonusAccount;
import org.springblade.modules.guosen.bussiness.entity.BussinessBonusRecords;
import org.springblade.modules.guosen.bussiness.entity.BussinessDebit;
import org.springblade.modules.guosen.bussiness.service.IBussinessBonusAccountService;
import org.springblade.modules.guosen.bussiness.service.IBussinessBonusRecordsService;
import org.springblade.modules.guosen.bussiness.service.IBussinessDebitService;
import org.springblade.modules.guosen.bussiness.service.IBussinessService;
import org.springblade.modules.guosen.bussinessInfo.entity.BussinessInfo;
import org.springblade.modules.guosen.bussinessInfo.service.IBussinessInfoService;
import org.springblade.modules.guosen.bussinessTransferOrder.entity.BussinessTransferOrder;
import org.springblade.modules.guosen.bussinessTransferOrder.service.IBussinessTransferOrderService;
import org.springblade.modules.guosen.bussinessuserinfo.entity.BussinessUserInfo;
import org.springblade.modules.guosen.bussinessuserinfo.service.IBussinessUserInfoService;
import org.springblade.modules.guosen.bussinessuserwithdraw.entity.BussinessUserWithdraw;
import org.springblade.modules.guosen.bussinessuserwithdraw.service.IBussinessUserWithdrawService;
import org.springblade.modules.system.service.IParamService;
import org.springblade.yeePay.event.TransferOrderEvent;
import org.springblade.yeePay.service.BussinessPayService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.Timer;
import java.util.TimerTask;
import java.util.UUID;

@Component
@Slf4j
public class TransferOrderNotifyListener {

    @Autowired
    private IBussinessTransferOrderService bussinessTransferOrderService;
    @Autowired
    private BussinessPayService bussinessPayService;
    @Autowired
    private IBussinessDebitService bussinessDebitService;
    @Autowired
    private IBussinessService bussinessService;
    @Autowired
    private IBussinessUserWithdrawService bussinessUserWithdrawService;
    @Autowired
    private IParamService paramService;
    @Autowired
    private IBussinessBonusRecordsService bussinessBonusRecordsService;
    @Autowired
    private IBussinessUserInfoService userInfoService;
    @Autowired
    private IBussinessBonusAccountService bussinessBonusAccountService;
    @Autowired
    private IBussinessInfoService bussinessInfoService;
    @Autowired
    private ApplicationEventPublisher eventPublisher;

    @EventListener
    @Async
    public void notify(TransferOrderEvent transferOrderEvent) {
        JSONObject decryptData = transferOrderEvent.getDecryptData();
        String requestNo = decryptData.getString("requestNo");
        String fromMerchantNo = decryptData.getString("fromMerchantNo");
        BussinessTransferOrder transferOrder = bussinessTransferOrderService.getByRequestNo(requestNo, fromMerchantNo);
        if(transferOrder != null){
            if(transferOrder.getTransferStatus().intValue() == SystemConstant.TransferOrderStatus.SUCCESS.getValue() ||
                transferOrder.getTransferStatus().intValue() == SystemConstant.TransferOrderStatus.FAIL.getValue()){
                return;
            }else{
                transferOrder.setTransferStatus(SystemConstant.TransferOrderStatus.SUCCESS.getValue());
                transferOrder.setFinishTime(decryptData.getString("finishTime"));
                transferOrder.setReceiveAmount(decryptData.getString("receiveAmount"));
                transferOrder.setThirdLog(JSONUtil.toJsonStr(decryptData));
                bussinessTransferOrderService.updateById(transferOrder);
                Integer transferScene = transferOrder.getTransferScene();
                if(transferScene.intValue() == SystemConstant.TransferScene.FOR_SERVICE_FEE.getValue()){ //充值后转账支付服务费场景
                    this.handleServiceFeeScene(fromMerchantNo);
                }else if(transferScene.intValue() == SystemConstant.TransferScene.FOR_PAY.getValue()){ //代付前转账场景
                    this.handlePayOrderScene(transferOrder.getId(), fromMerchantNo);
                }else if(transferScene.intValue() == SystemConstant.TransferScene.FOR_WITHDRAW_FIRST_TRANSFER.getValue()){ //提现前第一次转账成功
                    BussinessInfo bussinessInfo = this.bussinessInfoService.getByMerchantNo(transferOrder.getToMerchantNo());
                    this.handleFirstTransferScene(transferOrder.getId(), bussinessInfo.getParentMerchantNo());
                }else if(transferScene.intValue() == SystemConstant.TransferScene.FOR_WITHDRAW_SECOND_TRANSFER.getValue()){ //提现前第二次转账成功
                    this.handleSecondTransferScene(transferOrder.getId());
                }else if(transferScene.intValue() == SystemConstant.TransferScene.FOR_BONUS_TRANSFER.getValue()){ //分润前转账场景
                    this.handleBonusTransferScene(transferOrder.getId());
                }
            }
        }
    }

    /**
     * 处理转账服务费场景，主要是更新商户余额
     */
    private void handleServiceFeeScene(String merchantNo){
        Bussiness bussiness = bussinessService.getByMerchantNo(merchantNo);
        R<BigDecimal> newRemainR = bussinessService.queryBalance(bussiness.getMerchantNo());
        BigDecimal newRemain = newRemainR.getData();
        bussiness.setRemain(MoneyDesUtil.encrypt(newRemain.toString(), MoneyDesUtil.KEY_FOR_UC));
        bussinessService.updateById(bussiness);
    }

    /**
     * 处理代付前转账场景，主要发起代付
     */
    private void handlePayOrderScene(Long transferOrderId, String merchantNo){
        Bussiness bussiness = bussinessService.getByMerchantNo(merchantNo);
        if(bussiness != null){
            //发起代付
            BussinessDebit debit = bussinessDebitService.getByTransferOrderId(bussiness.getId(), transferOrderId);
            BussinessInfo bussinessInfo = this.bussinessInfoService.getByBussinessId(bussiness.getId());
            if(debit != null){
                bussinessPayService.payOrder(debit.getId(), bussinessInfo.getParentMerchantNo());
            }
        }
    }

    /**
     * 处理提现前第一次转账场景，主要是要发起第二次转账，转账到小微用户
     */
    private void handleFirstTransferScene(Long firstTransferOrderId, String parentMerchantNo){
        String withdrawRate = paramService.getValue("yee_withdraw_rate");
        BussinessUserWithdraw withdraw = this.bussinessUserWithdrawService.getByFirstTransferOrderId(firstTransferOrderId);
        BussinessTransferOrder transferOrder = new BussinessTransferOrder();
        transferOrder.setFromMerchantNo(parentMerchantNo);
        transferOrder.setToMerchantNo(withdraw.getMerchantNo());
        transferOrder.setTransferUsage("提现前转账");
        transferOrder.setOrderAmount((withdraw.getOrderAmount().add(new BigDecimal(withdrawRate))).toString());
        transferOrder.setFeeChargeSide("OUTSIDE");
        transferOrder.setRequestNo(UUID.randomUUID().toString().replaceAll("-","").toUpperCase());
        transferOrder.setTransferScene(SystemConstant.TransferScene.FOR_WITHDRAW_SECOND_TRANSFER.getValue());
        transferOrder.setTransferStatus(SystemConstant.TransferOrderStatus.WAIT.getValue());
        boolean transferSave = bussinessTransferOrderService.save(transferOrder);
        if(transferSave){
            withdraw.setSecondTransferOrderId(transferOrder.getId());
            R transferResult = bussinessPayService.transferOrder(transferOrder, parentMerchantNo);
            if(transferResult.isSuccess()){
                if(transferResult.getMsg().equals("REQUEST_RECEIVE")){
                    this.bussinessPayService.handleFirstTransferScene(firstTransferOrderId);
                }else if(transferResult.getMsg().equals("SUCCESS")){
                    withdraw.setFailReason("受理成功，请等待结果");
                    withdraw.setReturnMsg("提现前第二次转账发起成功");
                    this.bussinessUserWithdrawService.updateById(withdraw);
                    //发起提现
                    this.handleSecondTransferScene(transferOrder.getId());
                }
            }else{
                withdraw.setFailReason("代付失败");
                withdraw.setReturnMsg("提现前第二次转账发起失败：" + transferResult.getMsg());
                withdraw.setWithdrawStatus(SystemConstant.WithdrawOrderStatus.FAIL.getValue());
                this.bussinessUserWithdrawService.updateById(withdraw);
            }
        }else{
            log.error("====================提现前第一次转账回调转账业务订单保存失败====================");
            log.error(JSONUtil.toJsonStr(transferOrder));
            withdraw.setFailReason("代付失败");
            withdraw.setReturnMsg("提现前第二次转账发起失败：转账单保存失败");
            withdraw.setWithdrawStatus(SystemConstant.WithdrawOrderStatus.FAIL.getValue());
            this.bussinessUserWithdrawService.updateById(withdraw);
        }
    }

    /**
     * 处理提现前第二次转账场景，主要是要小微用户发起提现下单
     */
    private void handleSecondTransferScene(Long secondTransferOrderId){
        BussinessUserWithdraw withdraw = this.bussinessUserWithdrawService.getBySecondTransferOrderId(secondTransferOrderId);
        Long userInfoId = withdraw.getUserInfoId();
        BussinessUserInfo userInfo = this.userInfoService.getById(userInfoId);
        BussinessTransferOrder transferOrder = this.bussinessTransferOrderService.getById(secondTransferOrderId);
        withdraw.setReturnMsg("提现前第二次转账回调成功");
        R<BigDecimal> remainR = this.bussinessService.queryBalance(userInfo.getMerchantNo());
        if(remainR.isSuccess()){
            BigDecimal remain = remainR.getData();
            if(remain.compareTo(new BigDecimal(transferOrder.getOrderAmount())) == 1){
                this.bussinessPayService.withdrawOrder(withdraw, userInfo.getParentMerchantNo());
            }else{
                log.error("=====================分润失败，用户资金账户余额不足===============");
                log.error(String.format("============分润金额：%s, 用户资金账户余额：%s", withdraw.getOrderAmount().toString(), remain.toString()));
            }
        }
    }

    /**
     * 处理分润前转账场景，主要是要小微用户发起提现下单
     */
    private void handleBonusTransferScene(Long transferOrderId){
        BussinessBonusRecords records = this.bussinessBonusRecordsService.getByTransferOrderId(transferOrderId);
        BussinessBonusAccount account = this.bussinessBonusAccountService.getById(records.getBonusAccountId());
        BussinessTransferOrder transferOrder = this.bussinessTransferOrderService.getById(transferOrderId);
        Long userInfoId = records.getUserInfoId();
        BussinessUserInfo userInfo = this.userInfoService.getById(userInfoId);
        BussinessUserWithdraw withdraw = new BussinessUserWithdraw();
        withdraw.setMerchantNo(userInfo.getMerchantNo());
        withdraw.setWithdrawStatus(SystemConstant.TransferOrderStatus.WAIT.getValue());
        withdraw.setOrderAmount(records.getPrice());
        withdraw.setRequestNo(UUID.randomUUID().toString().replaceAll("-", "").toUpperCase());
        withdraw.setReceiveType("REAL_TIME");
        withdraw.setBankAccountNo(account.getReceiverAccountNo());
        withdraw.setBussinessId(userInfo.getBussinessId());
        withdraw.setReceiverAccountName(userInfo.getUserName());
        withdraw.setBankCode(userInfo.getBankCode());
        withdraw.setBussinessId(userInfo.getBussinessId());
        this.bussinessUserWithdrawService.save(withdraw);
        R<BigDecimal> remainR = this.bussinessService.queryBalance(userInfo.getMerchantNo());
        if(remainR.isSuccess()){
            BigDecimal remain = remainR.getData();
            if(remain.compareTo(new BigDecimal(transferOrder.getOrderAmount())) == 1){
                this.bussinessPayService.withdrawOrder(withdraw, userInfo.getParentMerchantNo());
            }else{
                log.error("=====================分润失败，用户资金账户余额不足===============");
                log.error(String.format("============分润金额：%s, 用户资金账户余额：%s", withdraw.getOrderAmount().toString(), remain.toString()));
            }
        }
    }
}
