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.core.tool.api.R;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.modules.guosen.bussiness.entity.Bussiness;
import org.springblade.modules.guosen.bussiness.service.IBussinessService;
import org.springblade.modules.guosen.bussinessRegisterRequest.entity.BussinessRegisterRequest;
import org.springblade.modules.guosen.bussinessRegisterRequest.service.IBussinessRegisterRequestService;
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.common.YeePayConst;
import org.springblade.yeePay.entity.NotifyDto;
import org.springblade.yeePay.event.UserRegisterEvent;
import org.springblade.yeePay.service.BussinessPayService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import java.math.BigDecimal;
import java.net.URI;
import java.text.DecimalFormat;
import java.util.Timer;
import java.util.TimerTask;
import java.util.UUID;

@Component
@Slf4j
public class UserRegisterNotifyListener {

    @Autowired
    private IBussinessRegisterRequestService bussinessRegisterRequestService;
    @Autowired
    private IBussinessUserInfoService userInfoService;
    @Autowired
    private IBussinessUserWithdrawService withdrawService;
    @Autowired
    private IBussinessService bussinessService;
    @Autowired
    private IParamService paramService;
    @Autowired
    private IBussinessTransferOrderService bussinessTransferOrderService;
    @Autowired
    private BussinessPayService bussinessPayService;

    /**
     * 小微用户入网申请回调
     *
     * @param userRegisterEvent 回调事件
     */
    @EventListener
    @Async
    public void userRegisterNotify(UserRegisterEvent userRegisterEvent) {
        JSONObject decryptData = userRegisterEvent.getDecryptData(); //获取回调信息，解密后的数据

        String requestNo = decryptData.getString("requestNo");
        BussinessRegisterRequest registerRequest = bussinessRegisterRequestService.getByRequestNo(requestNo);
        BussinessUserInfo userInfo = userInfoService.getById(registerRequest.getUserInfoId());
        if(registerRequest.getApplicationStatus().intValue() == SystemConstant.BussinessRegisterStatus.SUCCESS.getValue()
                || registerRequest.getApplicationStatus().intValue() == SystemConstant.BussinessRegisterStatus.FAIL.getValue()) {
            return;
        }else{
            String applicationStatus = decryptData.getString("applicationStatus");
            if(applicationStatus.equals("REVIEW_BACK")){
                registerRequest.setApplicationStatus(SystemConstant.BussinessRegisterStatus.FAIL.getValue());
                userInfo.setRegisterStatus(SystemConstant.BussinessRegisterStatus.FAIL.getValue());
            } else if (applicationStatus.equals("AGREEMENT_SIGNING")){
                registerRequest.setApplicationStatus(SystemConstant.BussinessRegisterStatus.WAIT_SIGNING.getValue());
                userInfo.setRegisterStatus(SystemConstant.BussinessRegisterStatus.WAIT_SIGNING.getValue());
            } else if(applicationStatus.equals("AUTHENTICITY_VERIFYING")){
                registerRequest.setApplicationStatus(SystemConstant.BussinessRegisterStatus.WAIT_AUDIT.getValue());
                userInfo.setRegisterStatus(SystemConstant.BussinessRegisterStatus.WAIT_AUDIT.getValue());
            }else if(applicationStatus.equals("COMPLETED")){
                registerRequest.setApplicationStatus(SystemConstant.BussinessRegisterStatus.SUCCESS.getValue());
                userInfo.setRegisterStatus(SystemConstant.BussinessRegisterStatus.SUCCESS.getValue());
            }
            registerRequest.setAuditOpinion(decryptData.getString("auditOpinion"));
            registerRequest.setApplicationNo(decryptData.getString("applicationNo"));
            registerRequest.setMerchantNo(decryptData.getString("merchantNo"));
            userInfo.setAuditOpinion(decryptData.getString("auditOpinion"));
            userInfo.setMerchantNo(decryptData.getString("merchantNo"));
            bussinessRegisterRequestService.updateById(registerRequest);
            userInfoService.updateById(userInfo);
            //发送回调通知给采购商
            this.registerCallback(userInfo, decryptData.getString("auditOpinion"));

            if(applicationStatus.equals("COMPLETED")){
                BussinessUserWithdraw withdraw = withdrawService.getByUserRegisterRequestId(registerRequest.getId());
                if(withdraw != null){
                    withdraw.setMerchantNo(decryptData.getString("merchantNo"));
                    withdrawService.updateById(withdraw);
                    //发起提现前第一次转账
                    this.sendFirstTransferForWithdraw(withdraw);
                }
            }
        }
    }

    /**
     * 发起提现前第一次转账
     * @param withdraw
     */
    private void sendFirstTransferForWithdraw(BussinessUserWithdraw withdraw){
        Long userInfoId = withdraw.getUserInfoId();
        BussinessUserInfo userInfo = this.userInfoService.getById(userInfoId);
        Long bussinessId = userInfo.getBussinessId();
        Bussiness bussiness = bussinessService.getById(bussinessId);
        Bussiness parentBussiness = bussinessService.getById(bussiness.getParentBussinessId());
        DecimalFormat debitDecimalFormat = new DecimalFormat("0.00");
        BigDecimal orderAmountBigDecimal = new BigDecimal(debitDecimalFormat.format(withdraw.getOrderAmount()));
        //检查商户是否有足够余额进行代付
        String transferRate = paramService.getValue("yee_transfer_rate");
        String withdrawRate = paramService.getValue("yee_withdraw_rate");
        BigDecimal transferFee = new BigDecimal(debitDecimalFormat.format(Double.parseDouble(transferRate))).multiply(new BigDecimal(2));
        BigDecimal withdrawFee = new BigDecimal(debitDecimalFormat.format(Double.parseDouble(withdrawRate)));
        BigDecimal transferAmount = orderAmountBigDecimal.add(transferFee).add(withdrawFee);
        BussinessTransferOrder firstBussinessTransferOrder = new BussinessTransferOrder();
        firstBussinessTransferOrder.setFromMerchantNo(bussiness.getMerchantNo());
        firstBussinessTransferOrder.setToMerchantNo(parentBussiness.getMerchantNo());
        firstBussinessTransferOrder.setTransferUsage("提现前转账到平台商");
        firstBussinessTransferOrder.setOrderAmount(transferAmount.toString());
        firstBussinessTransferOrder.setFeeChargeSide("OUTSIDE");
        firstBussinessTransferOrder.setRequestNo(UUID.randomUUID().toString().replaceAll("-","").toUpperCase());
        firstBussinessTransferOrder.setTransferScene(SystemConstant.TransferScene.FOR_WITHDRAW_FIRST_TRANSFER.getValue());
        firstBussinessTransferOrder.setTransferStatus(SystemConstant.TransferOrderStatus.WAIT.getValue());
        boolean transferSave = bussinessTransferOrderService.save(firstBussinessTransferOrder);
        if(transferSave){
            withdraw.setFirstTransferOrderId(firstBussinessTransferOrder.getId());
            this.withdrawService.updateById(withdraw);
            R firstTransferResult = bussinessTransferOrderService.transferOrder(firstBussinessTransferOrder, userInfo.getParentMerchantNo());
            if(firstTransferResult.isSuccess()){
                withdraw.setFailReason("受理成功，请等待结果");
                withdraw.setReturnMsg(firstTransferResult.getMsg());
                this.withdrawService.updateById(withdraw);
                if(firstTransferResult.getMsg().equals("REQUEST_RECEIVE")){
                    this.handleFirstTransferScene(firstBussinessTransferOrder.getId());
                }else if(firstTransferResult.getMsg().equals("SUCCESS")){
                    BussinessTransferOrder secondTransferOrder = new BussinessTransferOrder();
                    secondTransferOrder.setFromMerchantNo(firstBussinessTransferOrder.getToMerchantNo());
                    secondTransferOrder.setToMerchantNo(withdraw.getMerchantNo());
                    secondTransferOrder.setTransferUsage("提现前转账到小微");
                    secondTransferOrder.setOrderAmount((withdraw.getOrderAmount().add(new BigDecimal(withdrawRate))).toString());
                    secondTransferOrder.setFeeChargeSide("OUTSIDE");
                    secondTransferOrder.setRequestNo(UUID.randomUUID().toString().replaceAll("-","").toUpperCase());
                    secondTransferOrder.setTransferScene(SystemConstant.TransferScene.FOR_WITHDRAW_SECOND_TRANSFER.getValue());
                    secondTransferOrder.setTransferStatus(SystemConstant.TransferOrderStatus.WAIT.getValue());
                    this.bussinessTransferOrderService.save(secondTransferOrder);
                    withdraw.setSecondTransferOrderId(secondTransferOrder.getId());
                    withdraw.setFailReason("受理成功，请等待结果");
                    withdraw.setReturnMsg("提现前第一次转账成功");
                    this.withdrawService.updateById(withdraw);
                    R secondTransferResult = this.bussinessTransferOrderService.transferOrder(secondTransferOrder, firstBussinessTransferOrder.getToMerchantNo());
                    if(secondTransferResult.isSuccess()){
                        if(secondTransferResult.getMsg().equals("REQUEST_RECEIVE")){
                            this.handleSecondTransferScene(secondTransferOrder.getId());
                        }else if(secondTransferResult.getMsg().equals("SUCCESS")){
                            this.bussinessPayService.withdrawOrder(withdraw, userInfo.getParentMerchantNo());
                        }
                    }else{
                        withdraw.setFailReason("代付失败");
                        withdraw.setReturnMsg(secondTransferResult.getMsg());
                        withdraw.setWithdrawStatus(SystemConstant.WithdrawOrderStatus.FAIL.getValue());
                        this.withdrawService.updateById(withdraw);
                    }
                }
            }else{
                withdraw.setFailReason("代付失败");
                withdraw.setReturnMsg("提现前第一次转账发起失败：" + firstTransferResult.getMsg());
                withdraw.setWithdrawStatus(SystemConstant.WithdrawOrderStatus.FAIL.getValue());
                this.withdrawService.updateById(withdraw);
            }
        }else{
            log.error("=======================提现前第一次转账业务订单保存失败========================");
            log.error(JSONUtil.toJsonStr(firstBussinessTransferOrder));
        }
    }

    public void handleFirstTransferScene(Long firstTransferOrderId){
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                BussinessTransferOrder firstTransferOrder = bussinessTransferOrderService.getById(firstTransferOrderId);
                if(firstTransferOrder.getTransferStatus().intValue() == SystemConstant.TransferOrderStatus.REQUEST_RECEIVE.getValue()){
                    try{
                        R result = bussinessTransferOrderService.transferQuery(firstTransferOrder.getId());
                        if(result.isSuccess()){
                            if(result.getData().equals("SUCCESS")){
                                String withdrawRate = paramService.getValue("yee_withdraw_rate");
                                BussinessUserWithdraw withdraw = withdrawService.getByFirstTransferOrderId(firstTransferOrderId);
                                BussinessTransferOrder secondTransferOrder = new BussinessTransferOrder();
                                secondTransferOrder.setFromMerchantNo(firstTransferOrder.getToMerchantNo());
                                secondTransferOrder.setToMerchantNo(withdraw.getMerchantNo());
                                secondTransferOrder.setTransferUsage("提现前转账");
                                secondTransferOrder.setOrderAmount((withdraw.getOrderAmount().add(new BigDecimal(withdrawRate))).toString());
                                secondTransferOrder.setFeeChargeSide("OUTSIDE");
                                secondTransferOrder.setRequestNo(UUID.randomUUID().toString().replaceAll("-","").toUpperCase());
                                secondTransferOrder.setTransferScene(SystemConstant.TransferScene.FOR_WITHDRAW_SECOND_TRANSFER.getValue());
                                secondTransferOrder.setTransferStatus(SystemConstant.TransferOrderStatus.WAIT.getValue());
                                bussinessTransferOrderService.save(secondTransferOrder);
                                withdraw.setSecondTransferOrderId(secondTransferOrder.getId());
                                withdrawService.updateById(withdraw);
                                R secondTransferResult = bussinessTransferOrderService.transferOrder(secondTransferOrder, firstTransferOrder.getToMerchantNo());
                                if(secondTransferResult.isSuccess()){
                                    if(secondTransferResult.getMsg().equals("REQUEST_RECEIVE")){
                                        handleSecondTransferScene(secondTransferOrder.getId());
                                    }else if(secondTransferResult.getMsg().equals("SUCCESS")){
                                        bussinessPayService.withdrawOrder(withdraw, secondTransferOrder.getFromMerchantNo());
                                    }
                                }else{
                                    withdraw.setFailReason("代付失败");
                                    withdraw.setReturnMsg(secondTransferResult.getMsg());
                                    withdrawService.updateById(withdraw);
                                }
                                this.cancel();
                                timer.cancel();
                            }
                        }
                    }catch (Exception e){
                        this.cancel();
                        timer.cancel();
                    }
                }else{
                    this.cancel();
                    timer.cancel();
                }
            }
        }, 500 , 10000);
    }

    public void handleSecondTransferScene(Long secondTransferOrderId){
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                BussinessTransferOrder secondTransferOrder = bussinessTransferOrderService.getById(secondTransferOrderId);
                if(secondTransferOrder.getTransferStatus().intValue() == SystemConstant.TransferOrderStatus.REQUEST_RECEIVE.getValue()){
                    try{
                        R result = bussinessTransferOrderService.transferQuery(secondTransferOrderId);
                        if(result.isSuccess()){
                            if(result.getData().equals("SUCCESS")){
                                BussinessUserWithdraw withdraw = withdrawService.getBySecondTransferOrderId(secondTransferOrderId);
                                Long userInfoId = withdraw.getUserInfoId();
                                BussinessUserInfo userInfo = userInfoService.getById(userInfoId);
                                withdraw.setReturnMsg("提现前第二次转账成功");
                                bussinessPayService.withdrawOrder(withdraw, userInfo.getParentMerchantNo());
                                this.cancel();
                                timer.cancel();
                            }
                        }
                    }catch (Exception e){
                        this.cancel();
                        timer.cancel();
                    }
                }else{
                    this.cancel();
                    timer.cancel();
                }
            }
        }, 500 , 5000);
    }

    @Async
    void registerCallback(BussinessUserInfo userInfo, String auditOpinion){
        Bussiness bussiness = this.bussinessService.getById(userInfo.getBussinessId());
        String registerNotifyUrl = bussiness.getRegisterNotifyUrl();
        if(StringUtil.isNotBlank(registerNotifyUrl)){
            JSONObject callbackData = new JSONObject();
            callbackData.put("userId", userInfo.getId().toString());
            if(userInfo.getRegisterStatus().intValue() == SystemConstant.BussinessRegisterStatus.SUCCESS.getValue()){
                callbackData.put("status", "SUCCESS");
            }else if(userInfo.getRegisterStatus().intValue() == SystemConstant.BussinessRegisterStatus.FAIL.getValue()){
                callbackData.put("status", "FAIL");
            }else{
                callbackData.put("status", "WAIT");
            }
            callbackData.put("auditOpinion", auditOpinion);
            try{
                RestTemplate restTemplate = new RestTemplate();
                HttpHeaders headers = new HttpHeaders();
                headers.add(HttpHeaders.CONTENT_TYPE, "application/json");
                HttpEntity<String> requestEntity = new HttpEntity<String>(JSONUtil.toJsonStr(callbackData), headers);
                ParameterizedTypeReference<Object> reference = new ParameterizedTypeReference<Object>() {
                };
                URI uri = URI.create(registerNotifyUrl);
                restTemplate.exchange(uri, HttpMethod.POST, requestEntity, reference);
                log.info("===================================返回给商户的进件回调信息================================");
                log.info(JSONUtil.toJsonStr(callbackData));
            }catch (Exception e){
                log.error("商户回调地址>>>>>>>>>>>>>> " + registerNotifyUrl);
                log.error("商户回调地址请求失败");
                log.error(JSONUtil.toJsonStr(callbackData));
            }
        }
    }
}
