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.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.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.guosen.debtDaliyStat.entity.BusinessDeptDaliyStat;
import org.springblade.modules.guosen.debtDaliyStat.service.IBusinessDeptDaliyStatService;
import org.springblade.yeePay.entity.NotifyDto;
import org.springblade.yeePay.event.WithdrawOrderNotifyEvent;
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;

@Component
@Slf4j
public class WithdrawOrderNotifyListener {

    @Autowired
    private IBussinessUserInfoService userInfoService;
    @Autowired
    private IBussinessUserWithdrawService withdrawService;
    @Autowired
    private IBussinessService bussinessService;
    @Autowired
    private IBusinessDeptDaliyStatService businessDeptDaliyStatService;

    /**
     * 小微用户提现回调
     *
     * @param withdrawOrderNotifyEvent 回调事件
     */
    @EventListener
    @Async
    public void withdrawOrderNotify(WithdrawOrderNotifyEvent withdrawOrderNotifyEvent) {
        JSONObject decryptData = withdrawOrderNotifyEvent.getDecryptData(); //获取回调信息，解密后的数据

        String requestNo = decryptData.getString("requestNo");
        BussinessUserWithdraw withdraw = this.withdrawService.getByRequestNo(requestNo);
        if(withdraw == null){
            log.error("================小微用户提现回调，提现记录不存在=================");
            return;
        }
        //更新当天已代付金额
        Long userInfoId = withdraw.getUserInfoId();
        BussinessUserInfo userInfo = userInfoService.getById(userInfoId);
        Long bussinessId = userInfo.getBussinessId();
        Bussiness bussiness = bussinessService.getById(bussinessId);
        if(userInfo == null){
            log.error("================小微用户提现回调，userInfo不存在=================");
            return;
        }
        if(withdraw.getWithdrawStatus().intValue() == SystemConstant.WithdrawOrderStatus.SUCCESS.getValue()
                || withdraw.getWithdrawStatus().intValue() == SystemConstant.WithdrawOrderStatus.FAIL.getValue()) {
            return;
        }else{
            String status = decryptData.getString("status");
            if(status.equals("SUCCESS")){
                withdraw.setWithdrawStatus(SystemConstant.WithdrawOrderStatus.SUCCESS.getValue());
                withdraw.setFailReason("代付成功");
                BusinessDeptDaliyStat todayStat = businessDeptDaliyStatService.getTodayStat(bussinessId);
                todayStat.setStatAmount(todayStat.getStatAmount().add(withdraw.getOrderAmount()));
                businessDeptDaliyStatService.updateById(todayStat);
                //获取商户余额信息
                R<BigDecimal> newRemainR = this.bussinessService.queryBalance(bussiness.getMerchantNo());
                BigDecimal newRemain = newRemainR.getData();
                bussiness.setRemain(MoneyDesUtil.encrypt(newRemain.toString(), MoneyDesUtil.KEY_FOR_UC));
                //修改商户余额信息
                bussinessService.updateById(bussiness);
            } else if (status.equals("FAIL")){
                withdraw.setWithdrawStatus(SystemConstant.WithdrawOrderStatus.FAIL.getValue());
                withdraw.setFailReason("代付失败");
            }
            withdraw.setReturnMsg(decryptData.getString("failReason"));
            withdraw.setThirdOrderAmount(decryptData.getString("orderAmount"));
            withdraw.setThirdDebitAmount(decryptData.getString("debitAmount"));
            withdraw.setThirdReceiveAmount(decryptData.getString("receiveAmount"));
            withdraw.setFee(decryptData.getString("fee"));
            withdraw.setFeeUndertakerMerchantNo(decryptData.getString("feeUndertakerMerchantNo"));
            Boolean isReversed = decryptData.getBoolean("isReversed");
            if(isReversed != null){
                if(isReversed){
                    withdraw.setIsReversed(1);
                }else{
                    withdraw.setIsReversed(0);
                }
            }
            withdrawService.updateById(withdraw);

            this.callToBusiness(withdraw, bussinessId, status, decryptData);

        }
    }

    private void callToBusiness(BussinessUserWithdraw withdraw, Long bussinessId, String status, JSONObject decryptData){
        //通知回调给采购商
        NotifyDto dto = new NotifyDto();
        dto.setBussinessOrderId(withdraw.getBussinessOrderId());//商户提供的订单号
        dto.setStatus(status);
        dto.setBankCode(decryptData.getString("bankCode"));
        dto.setReceiverAccountName(decryptData.getString("receiverAccountName"));
        dto.setReceiveAmount(withdraw.getThirdReceiveAmount());
        dto.setReceiverAccountNo(withdraw.getBankAccountNo());
        dto.setFailReason(withdraw.getFailReason());
        dto.setBussinessId(bussinessId);
        this.toBusiness(dto);
    }

    private void toBusiness(NotifyDto notifyDto){
        log.info("===============回调商户==================");
        log.info(notifyDto.toString());
        Bussiness bussiness = bussinessService.getById(notifyDto.getBussinessId());
        if(bussiness == null){
            log.info("==============回调商户不存在===============");
        }
        notifyDto.setBussinessId(null);
        String bussinessUrl = bussiness.getRecallUrl();
        if(StringUtil.isNotBlank(bussinessUrl)){
            recallToBusiness(bussinessUrl, notifyDto);
        }
    }

    @Async
    void recallToBusiness(String url, NotifyDto notifyDto){
        try{
            RestTemplate restTemplate = new RestTemplate();
            HttpHeaders headers = new HttpHeaders();
            headers.add(HttpHeaders.CONTENT_TYPE, "application/json");
            HttpEntity<String> requestEntity = new HttpEntity<String>(JSONUtil.toJsonStr(notifyDto), headers);
            ParameterizedTypeReference<Object> reference = new ParameterizedTypeReference<Object>() {
            };
            URI uri = URI.create(url);
            restTemplate.exchange(uri, HttpMethod.POST, requestEntity, reference);
            log.info("===================================返回给商户的回调信息================================");
            log.info(JSONUtil.toJsonStr(notifyDto));
        }catch (Exception e){
            log.error("商户回调地址>>>>>>>>>>>>>> " + url);
            log.error("商户回调地址请求失败");
        }
    }
}
