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.entity.BussinessDebit;
import org.springblade.modules.guosen.bussiness.service.IBussinessDebitService;
import org.springblade.modules.guosen.bussiness.service.IBussinessService;
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.PayOrderNotifyEvent;
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.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.web.client.RestTemplate;

import java.math.BigDecimal;
import java.net.URI;

@Component
@Slf4j
public class PayOrderNotifyListener {

    @Autowired
    private IBussinessDebitService bussinessDebitService;
    @Autowired
    private IBussinessService bussinessService;
    @Autowired
    private IBusinessDeptDaliyStatService businessDeptDaliyStatService;
    @Autowired
    private PlatformTransactionManager platformTransactionManager;
    @Autowired
    private TransactionDefinition transactionDefinition;

    @EventListener
    @Async
    public void notify(PayOrderNotifyEvent payOrderNotifyEvent) {
        JSONObject decryptData = payOrderNotifyEvent.getDecryptData();
        String status = decryptData.getString("status");
        String requestNo = decryptData.getString("requestNo");
        BussinessDebit bussinessDebit = bussinessDebitService.getByRequestNo(requestNo);
        String bussinessId = bussinessDebit.getBussinessId().toString();
        Bussiness bussiness = bussinessService.getById(bussinessDebit.getBussinessId());
        if (bussinessDebit.getStatus() == SystemConstant.BussinessDebitStatus.SUCCESS.getValue()
                || bussinessDebit.getStatus() == SystemConstant.BussinessDebitStatus.FAIL.getValue()) {//2为已成功过，无需再重复处理
            return;
        } else {
            synchronized (bussinessId.intern()) {//为每个商户加锁，减小锁的粒度
                if ("SUCCESS".equals(status)) {
                    log.info("======================代付回调成功========================");
                    bussinessDebit.setStatus(SystemConstant.BussinessDebitStatus.SUCCESS.getValue());
                    bussinessDebit.setThirdPayLog(decryptData.toJSONString());
                    TransactionStatus transaction = platformTransactionManager.getTransaction(transactionDefinition);
                    //处理逻辑
                    try {
                        //更新当天已代付金额
                        BusinessDeptDaliyStat todayStat = businessDeptDaliyStatService.getTodayStat(Long.valueOf(bussinessId));
                        todayStat.setStatAmount(todayStat.getStatAmount().add(bussinessDebit.getPrice()));
                        boolean result = this.businessDeptDaliyStatService.updateById(todayStat);
                        if (result) {
                            //修改代付流水表的代付状态为成功
                            bussinessDebitService.updateById(bussinessDebit);
                            //更新商户余额信息
                            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);
                            //提交事务
                            platformTransactionManager.commit(transaction);
                        }
                    }catch (Exception e){
                        //回滚事务
                        platformTransactionManager.rollback(transaction);
                        e.printStackTrace();
                        bussinessDebit.setThirdPayLog(e.getMessage());
                        bussinessDebit.setFailReason(decryptData.getString("failReason"));
                        bussinessDebitService.updateById(bussinessDebit);
                    }
                } else {
                    //第三方支付回调结果为失败，记录分佣流水失败的原因
                    bussinessDebit.setStatus(SystemConstant.BussinessDebitStatus.FAIL.getValue());
                    bussinessDebit.setThirdPayLog(decryptData.toJSONString());
                    bussinessDebit.setFailReason(decryptData.getString("failReason"));
                    bussinessDebitService.updateById(bussinessDebit);
                }
            }
            //通知回调给采购商
            NotifyDto dto = new NotifyDto();
            dto.setBussinessOrderId(bussinessDebit.getBussinessOrderId());//商户订单号
            dto.setStatus(status);
            dto.setBankCode(decryptData.getString("bankCode"));
            dto.setReceiverAccountName(decryptData.getString("receiverAccountName"));
            dto.setReceiveAmount(bussinessDebit.getPrice().toString());
            dto.setReceiverAccountNo(bussinessDebit.getReceiverAccountNo());
            dto.setFailReason(bussinessDebit.getFailReason());
            dto.setBussinessOrderId(bussinessDebit.getBussinessOrderId());
            dto.setBussinessId(bussinessDebit.getBussinessId());
            this.toBussiness(dto);
        }
    }

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

    @Async
    void recallToBussiness(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("商户回调地址请求失败");
        }
    }

    /**
     * 订单失败，释放掉商户的相应冻结金额
     * @param debit
     * @param bussiness
     */
    private void subtractFreeze(BussinessDebit debit, Bussiness bussiness){
        //减掉相应的商户冻结金额
        BigDecimal bussinessFreeze = new BigDecimal(MoneyDesUtil.decrypt(bussiness.getFreeze(), MoneyDesUtil.KEY_FOR_UC));
        BigDecimal subtract = bussinessFreeze.subtract(debit.getPrice());
        bussiness.setFreeze(MoneyDesUtil.encrypt(subtract.toString(), MoneyDesUtil.KEY_FOR_UC));
    }
}
