
package com.tmerclub.cloud.distribution.service.impl;

import cn.hutool.core.lang.Snowflake;
import com.github.binarywang.wxpay.bean.merchanttransfer.TransferCreateRequest;
import com.github.binarywang.wxpay.bean.merchanttransfer.TransferCreateResult;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.tmerclub.cloud.api.platform.config.FeignShopConfig;
import com.tmerclub.cloud.api.user.feign.UserFeignClient;
import com.tmerclub.cloud.api.user.vo.UserApiVO;
import com.tmerclub.cloud.common.bean.WxMiniApp;
import com.tmerclub.cloud.common.constant.Constant;
import com.tmerclub.cloud.common.database.dto.PageDTO;
import com.tmerclub.cloud.common.database.util.PageUtil;
import com.tmerclub.cloud.common.database.vo.PageVO;
import com.tmerclub.cloud.common.exception.LuckException;
import com.tmerclub.cloud.common.response.ServerResponseEntity;
import com.tmerclub.cloud.config.WxConfig;
import com.tmerclub.cloud.distribution.mapper.EnterprisePayMapper;
import com.tmerclub.cloud.distribution.model.EnterprisePay;
import com.tmerclub.cloud.distribution.service.DistributionWithdrawCashService;
import com.tmerclub.cloud.distribution.service.EnterprisePayService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 商家转账
 *
 * @author tmerclub
 * @date 2023-02-22 15:58:50
 */
@Service
public class EnterprisePayServiceImpl implements EnterprisePayService {
    private static final Logger LOGGER = LoggerFactory.getLogger(EnterprisePayServiceImpl.class);

    @Autowired
    private EnterprisePayMapper enterprisePayMapper;

    @Autowired
    private FeignShopConfig feignShopConfig;

    @Autowired
    private WxConfig wxConfig;

    @Autowired
    private DistributionWithdrawCashService distributionWithdrawCashService;

    @DubboReference
    private UserFeignClient userFeignClient;

    @Override
    public PageVO<EnterprisePay> page(PageDTO pageDTO) {
        return PageUtil.doPage(pageDTO, () -> enterprisePayMapper.list());
    }

    @Override
    public EnterprisePay getByEntPayId(Long entPayId) {
        return enterprisePayMapper.getByEntPayId(entPayId);
    }

    @Override
    public void save(EnterprisePay enterprisePay) {
        enterprisePayMapper.save(enterprisePay);
    }

    @Override
    public void update(EnterprisePay enterprisePay) {
        enterprisePayMapper.update(enterprisePay);
    }

    @Override
    public void deleteById(Long entPayId) {
        enterprisePayMapper.deleteById(entPayId);
    }

    @Override
    public List<EnterprisePay> listApplyEnterprisePay() {
        return enterprisePayMapper.listApplyEnterprisePay();
    }

    @Override
    public void sendEnterprisePay(List<EnterprisePay> enterprisePayList) {
        if (CollectionUtils.isEmpty(enterprisePayList)) {
            return;
        }
        String outBatchNo = new Snowflake().nextIdStr();
        TransferCreateRequest transferCreateRequest = new TransferCreateRequest();
        WxMiniApp wxMiniApp = feignShopConfig.getWxMiniApp();
        transferCreateRequest.setAppid(wxMiniApp.getAppId());
        transferCreateRequest.setOutBatchNo(outBatchNo);
        transferCreateRequest.setBatchName("NO_CHECK");
        // 批次备注
        transferCreateRequest.setBatchRemark("商城分销提现");
        List<TransferCreateRequest.TransferDetailList> transferDetailList = new ArrayList<>(Constant.INITIAL_CAPACITY);
        int totalAmount = 0;
        Set<Long> userIds = enterprisePayList.stream().map(EnterprisePay::getUserId).collect(Collectors.toSet());
        ServerResponseEntity<List<UserApiVO>> response = userFeignClient.getUserByUserIds(new ArrayList<>(userIds));
        if (!response.isSuccess()) {
            throw new LuckException(response.getMsg());
        }
        Map<Long, UserApiVO> userMap = response.getData().stream().collect(Collectors.toMap(UserApiVO::getUserId, u -> u));
        for (EnterprisePay enterprisePay : enterprisePayList) {
            int amount = addAndGetAmount(transferDetailList, enterprisePay, userMap);
            totalAmount += amount;
        }
        transferCreateRequest.setTotalAmount(totalAmount);
        transferCreateRequest.setTotalNum(enterprisePayList.size());
        transferCreateRequest.setTransferDetailList(transferDetailList);
        try {
            TransferCreateResult transfer = wxConfig.getMerchantTransferService().createTransfer(transferCreateRequest);
            enterprisePayList.forEach(enterprisePay -> {
                enterprisePay.setOutBatchNo(transfer.getOutBatchNo());
            });
            updateBatch(enterprisePayList);
        } catch (WxPayException wxPayException) {
            LOGGER.error("异常：", wxPayException);
        }
    }

    private static int addAndGetAmount(List<TransferCreateRequest.TransferDetailList> transferDetailList, EnterprisePay enterprisePay, Map<Long, UserApiVO> userMap) {
        TransferCreateRequest.TransferDetailList transferDetail = new TransferCreateRequest.TransferDetailList();
        transferDetail.setOpenid(enterprisePay.getOpenId());
        transferDetail.setOutDetailNo(String.valueOf(enterprisePay.getEntPayOrderNo()));
        int amount = Integer.parseInt(enterprisePay.getAmount().toString());
        transferDetail.setTransferAmount(amount);
        UserApiVO user = userMap.get(enterprisePay.getUserId());
        // 转账备注
        if (Objects.isNull(user)) {
            transferDetail.setTransferRemark("分销用户已注销");
        } else {
            transferDetail.setTransferRemark(user.getNickName() + "(" + user.getPhone() + ")");
        }
        transferDetailList.add(transferDetail);
        return amount;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void paySuccess(EnterprisePay enterprisePay) {
        //更新商家转账信息
        if (enterprisePayMapper.paySuccess(enterprisePay.getEntPayOrderNo(), enterprisePay.getVersion()) != 1) {
            // 更新余额记录失败，请稍后再试
            throw new LuckException("更新余额记录失败，请稍后再试");
        }
        // 推送支付成功事件
        distributionWithdrawCashService.distributionWithdrawToSuccess(enterprisePay);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void payFailed(EnterprisePay enterprisePay) {
        //更新商家转账信息
        if (enterprisePayMapper.payFailed(enterprisePay.getEntPayOrderNo(), enterprisePay.getVersion()) != 1) {
            // 更新余额记录失败，请稍后再试
            throw new LuckException("更新余额记录失败，请稍后再试");
        }
        // 推送支付失败事件
        distributionWithdrawCashService.distributionWithdrawToFailed(enterprisePay);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateBatch(List<EnterprisePay> enterprisePayList) {
        enterprisePayMapper.updateBatch(enterprisePayList);
    }

    @Override
    public List<EnterprisePay> listEnterprisePay() {
        return enterprisePayMapper.listEnterprisePay();
    }
}
