package com.yc.ship.module.ota.service.distributorrecharge;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.yc.ship.framework.common.exception.ServiceException;
import com.yc.ship.framework.common.lang.Asserts;
import com.yc.ship.framework.common.pojo.CommonResult;
import com.yc.ship.framework.common.pojo.PageResult;
import com.yc.ship.framework.common.util.object.BeanUtils;
import com.yc.ship.framework.mybatis.core.util.MyBatisUtils;
import com.yc.ship.framework.tenant.core.aop.TenantIgnore;
import com.yc.ship.framework.tenant.core.util.TenantUtils;
import com.yc.ship.module.ota.controller.admin.distributor.vo.DistributorRespVO;
import com.yc.ship.module.ota.controller.admin.distributorrecharge.vo.DistributorRechargeAuditReqVO;
import com.yc.ship.module.ota.controller.admin.distributorrecharge.vo.DistributorRechargePageReqVO;
import com.yc.ship.module.ota.controller.admin.distributorrecharge.vo.DistributorRechargeRespVO;
import com.yc.ship.module.ota.controller.admin.distributorrecharge.vo.DistributorRechargeSaveReqVO;
import com.yc.ship.module.ota.controller.admin.tradelog.vo.TradeLogSaveReqVO;
import com.yc.ship.module.ota.api.dto.DistributorRechargeReqDTO;
import com.yc.ship.module.ota.api.dto.DistributorRechargeRespDTO;
import com.yc.ship.module.ota.dal.dataobject.distributor.DistributorDO;
import com.yc.ship.module.ota.dal.dataobject.distributorrecharge.DistributorRechargeDO;
import com.yc.ship.module.ota.dal.dataobject.tradelog.TradeLogDO;
import com.yc.ship.module.ota.dal.mysql.distributorrecharge.DistributorRechargeMapper;
import com.yc.ship.module.ota.enums.AuditStatusEnum;
import com.yc.ship.module.ota.enums.DistributorTradeTypeEnum;
import com.yc.ship.module.ota.enums.DistributorTypeEnum;
import com.yc.ship.module.ota.service.distributor.DistributorService;
import com.yc.ship.module.ota.service.tradelog.TradeLogService;
import com.yc.ship.module.otc.api.store.StoreApi;
import com.yc.ship.module.otc.api.store.dto.StoreInfoReqDTO;
import com.yc.ship.module.otc.api.store.dto.StoreReqDTO;
import com.yc.ship.module.otc.api.store.dto.StoreRespDTO;
import com.yc.ship.module.otc.enums.StoreBalanceTypeEnum;
import com.yc.ship.module.otc.enums.StoreCreditTypeEnum;
import com.yc.ship.module.otc.enums.TradeModeEnum;
import com.yc.ship.module.system.api.user.AdminUserApi;
import com.yc.ship.module.system.api.user.dto.AdminUserRespDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Supplier;
import java.util.stream.Stream;

import static com.yc.ship.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.yc.ship.framework.common.exception.util.ServiceExceptionUtil.exception0;
import static com.yc.ship.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static com.yc.ship.framework.security.core.util.SecurityFrameworkUtils.getLoginUserNickname;
import static com.yc.ship.module.ota.enums.ErrorCodeConstants.*;

/**
 * 分销商充值 Service 实现类
 *
 * @author 管理员
 */
@Service
@Validated
@Slf4j
public class DistributorRechargeServiceImpl implements DistributorRechargeService {


    @Resource
    private DistributorRechargeMapper distributorRechargeMapper;

    @Resource
    private DistributorService distributorService;

    @Resource
    private RedissonClient redissonClient;
    @Resource
    private TradeLogService tradeLogService;

    @Resource
    private StoreApi storeApi;

    @Resource
    private AdminUserApi adminUserApi;


    /**
     * 余额类型
     */
    private static final int RECHARGE_TYPE_BALANCE = 1;

    /**
     * 授信类型
     */
    private static final int RECHARGE_TYPE_CREDIT = 2;

    /**
     * 定向库存类型
     */
    private static final int RECHARGE_TYPE_INVENTORY = 3;

    @Override
    public Long createDistributorRecharge(DistributorRechargeSaveReqVO createReqVO) {
        // 插入
        DistributorRechargeDO distributorRecharge = BeanUtils.toBean(createReqVO, DistributorRechargeDO.class);
        Long id = IdWorker.getId(distributorRecharge);
        distributorRecharge.setId(id);
        distributorRecharge.setDeleted(false);
        //转账充值
        distributorRecharge.setRechargeMode(1);
        distributorRecharge.setStatus(AuditStatusEnum.PENDING.getValue());
        Long userId = getLoginUserId();
        String userName = getLoginUserNickname();
        distributorRecharge.setApplyUser(userId);
        distributorRecharge.setApplyUserName(userName);
        distributorRecharge.setApplyTime(LocalDateTime.now());
        distributorRechargeMapper.insert(distributorRecharge);
        // 返回
        return distributorRecharge.getId();
    }

    @Override
    public void updateDistributorRecharge(DistributorRechargeSaveReqVO updateReqVO) {
        // 校验存在
        validateDistributorRechargeExists(updateReqVO.getId());
        // 更新
        DistributorRechargeDO updateObj = BeanUtils.toBean(updateReqVO, DistributorRechargeDO.class);
        distributorRechargeMapper.updateById(updateObj);
    }

    @Override
    public void deleteDistributorRecharge(Long id) {
        // 校验存在
        validateDistributorRechargeExists(id);
        // 删除
        distributorRechargeMapper.deleteById(id);
    }

    private void validateDistributorRechargeExists(Long id) {
        if (distributorRechargeMapper.selectById(id) == null) {
            throw exception0(500,  "分销商充值不存在");
        }
    }

    @Override
    public DistributorRechargeDO getDistributorRecharge(Long id) {
        return distributorRechargeMapper.selectById(id);
    }

    @Override
    public DistributorRechargeRespVO get(Long id) {
        DistributorRechargeDO distributorRechargeDO = distributorRechargeMapper.selectById(id);
        DistributorRechargeRespVO respVO = BeanUtils.toBean(distributorRechargeDO, DistributorRechargeRespVO.class);
        DistributorDO distributor = distributorService.getDistributor(respVO.getDistributorId());
        respVO.setDistributorName(distributor.getName());
        return respVO;
    }

    @Override
    public PageResult<DistributorRechargeRespVO> getDistributorRechargePage(DistributorRechargePageReqVO pageReqVO) {
        IPage<DistributorRechargeDO> iPage = MyBatisUtils.buildPage(pageReqVO);
        IPage<DistributorRechargeRespVO> page = distributorRechargeMapper.queryPage(iPage, pageReqVO);
        PageResult<DistributorRechargeRespVO> result = new PageResult<>(page.getRecords(), page.getTotal());
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void auditDistributorRecharge(DistributorRechargeAuditReqVO reqVO) {
        validateDistributorRechargeExists(reqVO.getId());
        DistributorRechargeDO rechargeDO = this.getDistributorRecharge(reqVO.getId());
        if (!ObjectUtil.equal(rechargeDO.getStatus(), AuditStatusEnum.PENDING.getValue())) {
            throw exception(RECHARGE_HAVA_REVIEWED);
        }
        if (reqVO.getAuditStatus().equals(AuditStatusEnum.APPROVED.getValue())) {
            Long logId = this.backDistributorRecharge(rechargeDO);
            rechargeDO.setRechargeLogId(logId);
        }
        rechargeDO.setAuditRemark(reqVO.getAuditRemark());
        rechargeDO.setStatus(reqVO.getAuditStatus());
        rechargeDO.setAuditTime(LocalDateTime.now());
        Long userId = getLoginUserId();
        String userName = getLoginUserNickname();
        rechargeDO.setAuditUser(userId);
        rechargeDO.setAuditUserName(userName);
        distributorRechargeMapper.updateById(rechargeDO);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long backDistributorRecharge(DistributorRechargeDO rechargeDO) {
        if (rechargeDO == null) {
            throw exception(DISTRIBUTOR_RECHARGE_NOT_EXISTS);
        }
        //充值金额
        BigDecimal money = rechargeDO.getMoney();
        String key = "ota_" + rechargeDO.getDistributorId();
        switch (rechargeDO.getRechargeType()) {
            case RECHARGE_TYPE_BALANCE:
                key += "_balance";
                break;
            case RECHARGE_TYPE_CREDIT:
                key += "_credit";
                break;
            case RECHARGE_TYPE_INVENTORY:
                key += "_inventory";
                break;
            default:
                break;
        }
        RLock lock = redissonClient.getLock(key);
        try {
            if (lock.tryLock(10, 30, TimeUnit.SECONDS)) {
                DistributorDO distributorDO = distributorService.getDistributor(rechargeDO.getDistributorId());
                if (distributorDO == null) {
                    throw exception(DISTRIBUTOR_NOT_EXISTS);
                }
                boolean flag = false;
                BigDecimal beforeBalance = BigDecimal.ZERO;
                BigDecimal afterBalance = BigDecimal.ZERO;

                String tradeName = "";
                int tradeType = 1;
                //
                String payType = distributorDO.getPayType();
                if (StringUtils.isBlank(payType)) {

                }
                String[] payTypeArray = payType.split(",");
                Stream<String> typeStream = Arrays.stream(payTypeArray);
                if (ObjectUtil.equals(rechargeDO.getRechargeType(), DistributorTradeTypeEnum.BALANCE_RECHARGE.getType())) {
                    beforeBalance = distributorDO.getBalance();
                    afterBalance = beforeBalance.add(money);
                    tradeName = "余额充值金额：" + money + "元,充值后余额为" + afterBalance + "元;";
                    flag = distributorService.addBalance(distributorDO.getId(), money);
                } else if (ObjectUtil.equals(rechargeDO.getRechargeType(), DistributorTradeTypeEnum.CREDIT_RECHARGE.getType())) {
                    if (typeStream.noneMatch(element -> Integer.parseInt(element) == DistributorTradeTypeEnum.CREDIT_RECHARGE.getType())) {
                        throw exception(CREDIT_NOT_ENABLED);
                    }
                    // 授信额度 充值
                    if (distributorDO.getPayCredit() != null) {
                        beforeBalance = distributorDO.getSurplus();
                        afterBalance = distributorDO.getSurplus().subtract(money);
                        BigDecimal creditRemained = distributorDO.getPayCredit().subtract(afterBalance);
                        tradeName = "授信充值金额：" + money + "元,授信总额度" + distributorDO.getPayCredit() + "元,充值后剩余额度" + creditRemained + "元;已用额度" + afterBalance + "元";
                    } else {
                        tradeName = "授信充值金额：" + money + "元,授信总额度不限,充值后剩余额度不限;已用额度" + afterBalance + "元";
                    }
                    tradeType = DistributorTradeTypeEnum.CREDIT_RECHARGE.getType();
                    flag = distributorService.subSurplus(distributorDO.getId(), money);
                } else if (ObjectUtil.equals(rechargeDO.getRechargeType(), DistributorTradeTypeEnum.STOCK_DIRECT_RECHARGE.getType())) {
                    if (typeStream.noneMatch(element -> Integer.parseInt(element) == DistributorTradeTypeEnum.STOCK_DIRECT_RECHARGE.getType())) {
                        throw exception(CREDIT_NOT_INVENTORY);
                    }
                    beforeBalance = distributorDO.getInventory();
                    afterBalance = beforeBalance.add(money);
                    tradeName = "定向库存充值金额：" + money + "元,充值后余额为" + afterBalance + "元。";
                    tradeType = DistributorTradeTypeEnum.STOCK_DIRECT_RECHARGE.getType();
                    flag = distributorService.addInventory(distributorDO.getId(), money);
                }
                Long userId = getLoginUserId();
                if (flag) {
                    //添加交易记录数据
                    TradeLogSaveReqVO logVO = new TradeLogSaveReqVO();
                    logVO.setOperatorId(userId);
                    logVO.setRemark(tradeName);
                    logVO.setTradeMode(1);
                    logVO.setTradeType(tradeType);
                    // 余额表示交易前金额 授信表示交易前已使用额度
                    logVO.setBeforeBalance(beforeBalance);
                    // 余额表示交易后金额 授信表示交易后已使用额度
                    logVO.setAfterBalance(afterBalance);
                    logVO.setTradeAmount(money);
                    logVO.setTradeTime(LocalDateTime.now());
                    logVO.setDistributorId(rechargeDO.getDistributorId());

                    Long tradeId = tradeLogService.createTradeLog(logVO);
                    if (tradeId != null) {
                        return tradeId;
                    }
                }
            }
        } catch (ServiceException e) {
            log.error("[分销商充值]{}", e.getMessage());
            throw new ServiceException(e.getCode(), e.getMessage());
        } catch (Exception ex) {
            log.error("[分销商充值]", ex);
            throw exception(DISTRIBUTOR_RECHARGE_FAILED);
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
        return null;
    }

    @Override
    @Transactional(propagation = Propagation.NESTED,rollbackFor = Exception.class)
    @TenantIgnore
    public CommonResult<DistributorRechargeRespDTO> tradeRecharge(DistributorRechargeReqDTO rechargeReqDTO) {
        RLock lock = null;
        DistributorRechargeRespDTO respDTO = null;
        try {
            //交易类型(1 余额充值、2 授信充值、3定向库存充值、4 余额购票、5余额退票、7授信购票、8授信退款、9定向库存购买、10定向库存退款、11预付款自助充值、12定向库存购买、13定向库存回收)
            int tradeType = rechargeReqDTO.getTradeType();
            // 支付方式
            int payType = rechargeReqDTO.getRechargeType();
            if (payType == 1
                    && (tradeType == DistributorTradeTypeEnum.BALANCE_STOCK_DIRECT_RECHARGE.getType()
                    || tradeType == DistributorTradeTypeEnum.BALANCE_STOCK_DIRECT_BACK.getType())) {
                Long userId = getLoginUserId();
                Long tradeId = tradeLogService.distributorRecharge(Long.parseLong(rechargeReqDTO.getAccountId()), Long.parseLong(rechargeReqDTO.getOrderId()), tradeType, userId, "", rechargeReqDTO.getAmount());
                respDTO = new DistributorRechargeRespDTO();
                respDTO.setRechargeType(tradeType);
                respDTO.setTradeId(tradeId);
                return CommonResult.success(respDTO);
            }
            String key = "ota_" + rechargeReqDTO.getAccountId();
            if (payType == DistributorTradeTypeEnum.BALANCE_RECHARGE.getType()) {
                //预付款
                key += "_balance";
            } else if (payType == DistributorTradeTypeEnum.CREDIT_RECHARGE.getType()) {
                //授信
                key += "_credit";
            } else {
                //定向库存
                key += "_inventory";
            }
            lock = redissonClient.getLock(key);
            if (lock.tryLock(10, 30, TimeUnit.SECONDS)) {
                DistributorDO distributor = distributorService.getDistributorNew(Long.parseLong(rechargeReqDTO.getAccountId()));
                Asserts.isTrue(null != distributor, "分销商{}不存在", rechargeReqDTO.getAccountId());
                //判断是否自营分销商 若不是自营分销商则需扣除
                if (distributor.getSelfSupport() == 0 || ObjectUtil.equals(distributor.getType(), DistributorTypeEnum.OTC.getType())) {
                    //交易额
                    BigDecimal money = rechargeReqDTO.getAmount();
                    boolean flag = false;
                    String tradeName = "";
                    //交易前金额
                    BigDecimal beforeBalance = BigDecimal.ZERO;
                    //交易后金额
                    BigDecimal afterBalance = BigDecimal.ZERO;
                    int tradeMode = 1;
                    int originTradeType = tradeType;
                    Supplier<Stream<String>> streamSupplier = () -> Stream.of(distributor.getPayType().split(","));
                    boolean isUseBalance = streamSupplier.get().anyMatch(element -> Integer.parseInt(element) == DistributorTradeTypeEnum.BALANCE_RECHARGE.getType());
                    boolean isUseCredit = streamSupplier.get().anyMatch(element -> Integer.parseInt(element) == DistributorTradeTypeEnum.CREDIT_RECHARGE.getType());
                    //消费
                    switch (tradeType) {
                        case 4:

                            //交易前金额
                            beforeBalance = distributor.getBalance();
                            afterBalance = beforeBalance.subtract(money);
                            //是否可以切换到授信支付
                            tradeMode = 2;
                            boolean canChangeToCredit = true;
                            if (rechargeReqDTO.getIsFixed() == 1 || streamSupplier.get().noneMatch(element -> ObjectUtil.equals(element, DistributorTradeTypeEnum.CREDIT_RECHARGE.getType().toString()))) {
                                canChangeToCredit =false;
                            }
                            if (isUseBalance) {

                                AtomicBoolean isShareBalance = new AtomicBoolean(false);
                                AtomicReference<StoreRespDTO> storeRespDTO = new AtomicReference<>();
                                try{
                                    if (rechargeReqDTO.getStoreId() != null){
                                        isShareBalance.set(true);
                                    }else {
                                        isShareBalance.set(true);
                                    }

                                    if(isShareBalance.get()){
                                        Asserts.isTrue(afterBalance.compareTo(BigDecimal.ZERO)>=0,"平台余额不足额");
                                        tradeName = "消费金额：" + money + "元,消费后剩余余额" + afterBalance + "元；";
                                        flag = distributorService.subBalance(distributor.getId(), money);
                                    }else if(storeRespDTO.get()!=null){
                                        StoreRespDTO storeRsp = storeRespDTO.get();
                                        beforeBalance = storeRsp.getBeforeAmount();
                                        afterBalance = storeRsp.getAfterAmount();
                                        tradeName = "消费金额：" + money + "元,消费后门店账户剩余余额" + storeRsp.getAfterAmount() + "元；";
                                        flag = true;
                                    }

                                }catch (ServiceException e){
                                    if(!canChangeToCredit){
                                        throw e;
                                    }
                                }

                                if(!flag){
                                    //尝试授信
//                                    tradeType = DistributorTradeTypeEnum.CREDIT_TRANS.getType();
                                }
                            } else {
                                if (!canChangeToCredit) {
                                    throw exception0(11_028, "分销商无预付款交易权限！");
                                }
//                                tradeType = DistributorTradeTypeEnum.CREDIT_TRANS.getType();
                            }

                            if(tradeType == DistributorTradeTypeEnum.CREDIT_TRANS.getType()){

                                rechargeReqDTO.setRechargeType(DistributorTradeTypeEnum.CREDIT_RECHARGE.getType());
                                rechargeReqDTO.setTradeType(tradeType);
                                return tradeRecharge(rechargeReqDTO);
                            }

                            break;
                        case 5:

                        case 20:
                            //预付款退款 定向库存退款 导游代退失败回退预存款
                            beforeBalance = distributor.getBalance();
                            //交易后金额
                            afterBalance = beforeBalance.add(money);
                            AtomicBoolean isShareBalance = new AtomicBoolean(false);
                            AtomicReference<StoreRespDTO> storeRespDTO = new AtomicReference<>();
                            if(true){
                                tradeName =(tradeType==10?"定向库存":"")+"余额退款金额：" + money + "元,退款到账后剩余余额" + afterBalance + "元";
                                //操作账户资金
                                flag = distributorService.addBalance(distributor.getId(), money);
                            }else if(storeRespDTO.get()!=null){
                                StoreRespDTO storeRsp = storeRespDTO.get();
                                beforeBalance = storeRsp.getBeforeAmount();
                                afterBalance = storeRsp.getAfterAmount();
                                tradeName = (tradeType==10?"定向库存":"")+"余额退款金额：" + money + "元,退款到账后门店账户剩余余额" + storeRsp.getAfterAmount() + "元；";
                                flag = true;
                            }
                            break;
                        case 2:
                            AtomicBoolean isShareCredit = new AtomicBoolean(false);
                            storeRespDTO = new AtomicReference<>();
                            if (rechargeReqDTO.getStoreId() != null){
                                //只充门店
                                StoreReqDTO reqDTO = this.convertStorePlatCredit(rechargeReqDTO.getStoreId(), tradeMode, money, Long.parseLong(rechargeReqDTO.getOrderId()), tradeType, rechargeReqDTO.getRefundId());
                                TenantUtils.execute(distributor.getAccountTenantId(), () -> {
                                    StoreInfoReqDTO storeData = storeApi.getStoreById(rechargeReqDTO.getStoreId()).getCheckedData();
                                    if(ObjectUtil.equals(storeData.getCreditType(), StoreCreditTypeEnum.FIXED.getType())) {
                                        CommonResult<StoreRespDTO> storeResult = storeApi.storePlatTrade(reqDTO);
                                        Asserts.isTrue(storeResult.isSuccess(), storeResult.getMsg());
                                        storeRespDTO.set(storeResult.getCheckedData());
                                    }else{
                                        isShareCredit.set(true);
                                    }
                                });
                            }else{
                                isShareCredit.set(true);
                            }
                            if(isShareCredit.get()){
                                //充平台
                                beforeBalance = distributor.getSurplus();
                                //退款后已用额度 = 当前已用额度 - 退款金额
                                afterBalance = beforeBalance.subtract(money);
                                //分销商授信额度
                                BigDecimal payCredit = distributor.getPayCredit();
                                if (payCredit != null) {
                                    BigDecimal creditRemained = payCredit.subtract(afterBalance);
                                    tradeName = "授信账单还款充值金额：" + money + "元,授信总额度" + payCredit + "元,充值后剩余额度" + creditRemained + "元;已用额度" + afterBalance + "元";

                                } else {
                                    tradeName = "授信账单还款充值金额：" + money + "元,授信总额度不限,充值后剩余额度不限;已用额度" + afterBalance + "元";
                                }
                                flag = distributorService.subSurplus(distributor.getId(), money);
                            }else if(storeRespDTO.get()!=null){
                                StoreRespDTO storeRsp = storeRespDTO.get();
                                beforeBalance = storeRsp.getBeforeAmount();
                                afterBalance = storeRsp.getAfterAmount();
                                tradeName = "授信账单还款金额：" + money + "元,退款到账后门店已使用授信从" + storeRsp.getBeforeAmount() + "元；变为"+ storeRsp.getAfterAmount();
                                flag = true;
                            }
                            break;
                        case 8:
                            //授信退款
                            beforeBalance = distributor.getSurplus();
                            //退款后已用额度 = 当前已用额度 - 退款金额
                            afterBalance = beforeBalance.subtract(money);
                            //分销商授信额度
                            BigDecimal payCredit = distributor.getPayCredit();
                            isShareCredit = new AtomicBoolean(false);
                            storeRespDTO = new AtomicReference<>();
                            if (rechargeReqDTO.getStoreId() != null){
                                StoreReqDTO reqDTO = this.convertStorePlatCredit(rechargeReqDTO.getStoreId(), tradeMode, money, Long.parseLong(rechargeReqDTO.getOrderId()), tradeType, rechargeReqDTO.getRefundId());
                                TenantUtils.execute(distributor.getAccountTenantId(), () -> {
                                    StoreInfoReqDTO storeData = storeApi.getStoreById(rechargeReqDTO.getStoreId()).getCheckedData();
                                    if(ObjectUtil.equals(storeData.getCreditType(), StoreCreditTypeEnum.FIXED.getType())){
                                        CommonResult<StoreRespDTO> storeResult = storeApi.storePlatTrade(reqDTO);
                                        Asserts.isTrue(storeResult.isSuccess(), storeResult.getMsg());
                                        storeRespDTO.set(storeResult.getCheckedData());
                                    }else{
                                        isShareCredit.set(true);
                                    }
                                });
                            }else{
                                isShareCredit.set(true);
                            }

                            if(isShareCredit.get()){
                                if (payCredit != null) {
                                    BigDecimal creditRemained = payCredit.subtract(afterBalance);
                                    tradeName = "授信退款金额：" + money + "元,授信总额度" + payCredit + "元,退款后剩余额度" + creditRemained + "元;已用额度" + afterBalance + "元";
                                } else {
                                    tradeName = "授信退款金额：" + money + "元,授信总额度不限,退款后剩余额度不限;已用额度" + afterBalance + "元";
                                }
                                flag = distributorService.subSurplus(distributor.getId(), money);
                            }else if(storeRespDTO.get()!=null){
                                StoreRespDTO storeRsp = storeRespDTO.get();
                                beforeBalance = storeRsp.getBeforeAmount();
                                afterBalance = storeRsp.getAfterAmount();
                                tradeName = "授信退款金额：" + money + "元,退款到账后门店已使用授信从" + storeRsp.getBeforeAmount() + "元；变为"+ storeRsp.getAfterAmount();
                                flag = true;
                            }

                            break;
                        case 9:
                            //交易前金额
                            beforeBalance = distributor.getBalance();
                            afterBalance = beforeBalance.subtract(money);

                            break;
                        case 14:
                            //营销政策充值
                            beforeBalance = distributor.getBalance();
                            afterBalance = beforeBalance.add(money);
                            tradeName = "营销政策充值金额：" + money + "元,充值到账后剩余余额" + afterBalance + "元";
                            flag = distributorService.addBalance(distributor.getId(), money);
                            break;
                        case 15:
                            //营销政策撤回
                            beforeBalance = distributor.getBalance();
                            afterBalance = beforeBalance.subtract(money);
                            tradeName = "营销政策撤回金额：" + money + "元,营销政策撤回后剩余余额" + afterBalance + "元";
                            flag = distributorService.subBalance(distributor.getId(), money);
                            break;
                        case 16:
                            //预付款支付授信账单
                            beforeBalance = distributor.getBalance();
                            afterBalance = beforeBalance.subtract(money);
                            tradeMode = 2;
                            isShareBalance = new AtomicBoolean(true);
                            storeRespDTO = new AtomicReference<>();
                            if (rechargeReqDTO.getStoreId() != null){
                                isShareBalance.set(true);
                            }

                            if(isShareBalance.get()){
                                Asserts.isTrue(isUseBalance,"分销商无预付款交易权限");
                                Asserts.isTrue(afterBalance.compareTo(BigDecimal.ZERO)>=0,"平台余额不足额");
                                tradeName = "预付款支付授信账单金额：" + money + "元,支付后剩余余额" + afterBalance + "元";
                                flag = distributorService.subBalance(distributor.getId(), money);
                            }else if(storeRespDTO.get()!=null){
                                StoreRespDTO storeRsp = storeRespDTO.get();
                                beforeBalance = storeRsp.getBeforeAmount();
                                afterBalance = storeRsp.getAfterAmount();
                                tradeName = "门店预付款支付授信账单金额：" + money + "元,支付后剩余余额" + storeRsp.getAfterAmount() + "元；";
                                flag = true;
                            }
                            break;
                        case 17:
                            //给门店分配预付款
                            Asserts.isTrue(rechargeReqDTO.getStoreId()!=null,"门店预付款充值，门店ID必传");
                            tradeMode = rechargeReqDTO.getMode();
                            //预付款
                            beforeBalance = distributor.getBalance();
                            if(tradeMode == 1){
                                //分配后金额
                                Asserts.isTrue(isUseBalance,"分销商无预付款交易权限");
                                afterBalance = beforeBalance.subtract(money);
                                Asserts.isTrue(afterBalance.compareTo(BigDecimal.ZERO)>=0,"余额不足无法分配");
                                //充值
                                tradeName = "余额分配金额：" + money + "元,分配后剩余余额" + afterBalance + "元;";
                                //操作账户资金
                                flag = distributorService.subBalance(distributor.getId(), money);
                                if(flag){
                                    StoreReqDTO storeReqDTO = this.convertStorePlatBalance(rechargeReqDTO.getStoreId(), tradeMode, money, Long.parseLong(rechargeReqDTO.getOrderId()), tradeType, rechargeReqDTO.getRefundId());
                                    TenantUtils.execute(distributor.getAccountTenantId(), () -> {
                                        CommonResult<StoreRespDTO> storeResult = storeApi.storePlatTrade(storeReqDTO);
                                        if(!storeResult.isSuccess()){
                                            //扣除失败，平台回滚
                                            distributorService.addBalance(distributor.getId(), money);
                                        }
                                        Asserts.isTrue(storeResult.isSuccess(), storeResult.getMsg());
                                    });
                                }
                                tradeMode =2;//对于平台是减少
                            }else{
                                //先扣门店的
                                StoreReqDTO storeReqDTO = this.convertStorePlatBalance(rechargeReqDTO.getStoreId(), tradeMode, money, Long.parseLong(rechargeReqDTO.getOrderId()), tradeType, rechargeReqDTO.getRefundId());
                                TenantUtils.execute(distributor.getAccountTenantId(), () -> {
                                    CommonResult<StoreRespDTO> storeResult = storeApi.storePlatTrade(storeReqDTO);
                                    Asserts.isTrue(storeResult.isSuccess(), storeResult.getMsg());
                                });
                                //分配后金额
                                afterBalance = beforeBalance.add(money);
                                //充值
                                tradeName = "门店归还余额金额：" + money + "元,归还后余额" + afterBalance + "元;";
                                //操作账户资金
                                flag = distributorService.addBalance(distributor.getId(), money);
                                if(!flag){
                                    //门店回滚
                                    StoreReqDTO storeReqBackDTO = this.convertStorePlatBalance(rechargeReqDTO.getStoreId(), 1, money, Long.parseLong(rechargeReqDTO.getOrderId()), tradeType, rechargeReqDTO.getRefundId());
                                    TenantUtils.execute(distributor.getAccountTenantId(), () -> {
                                        CommonResult<StoreRespDTO> storeResult = storeApi.storePlatTrade(storeReqBackDTO);
                                        Asserts.isTrue(storeResult.isSuccess(), storeResult.getMsg());
                                    });

                                }
                                tradeMode =1;//对于平台是增加
                            }

                            break;
                        case 18:
                            Asserts.isTrue(rechargeReqDTO.getStoreId()!=null,"门店授信分配，门店ID必传");
                            tradeMode = rechargeReqDTO.getMode();
                            //平台给门店分配授信
                            beforeBalance = distributor.getPayCredit();
                            if(tradeMode == 1){
                                Asserts.isTrue(isUseCredit, "分销商无授信交易权限！");
                                //剩余授信
                                afterBalance = beforeBalance.subtract(money);
                                BigDecimal surplus = distributor.getSurplus().add(money);
                                Asserts.isTrue(surplus.compareTo(distributor.getPayCredit())<=0,"授信额度不足无法分配");
                                //充值
                                tradeName = "授信分配额度：" + money + "元,分配后剩余授信" + afterBalance + "元;";
                                //操作账户资金
                                flag = distributorService.subPayCredit(distributor.getId(), money);
                                if(flag){
                                    StoreReqDTO reqDTO = this.convertStorePlatCredit(rechargeReqDTO.getStoreId(), tradeMode, money, Long.parseLong(rechargeReqDTO.getOrderId()), tradeType, rechargeReqDTO.getRefundId());
                                    TenantUtils.execute(distributor.getAccountTenantId(), () -> {
                                        CommonResult<StoreRespDTO> storeResult = storeApi.storePlatTrade(reqDTO);
                                        if(!storeResult.isSuccess()){
                                            //扣除失败，平台回滚
                                            distributorService.addPayCredit(distributor.getId(), money);
                                        }
                                        Asserts.isTrue(storeResult.isSuccess(), storeResult.getMsg());
                                    });
                                }
                                tradeMode =2;//对于平台是减少
                            }else{
                                StoreReqDTO reqDTO = this.convertStorePlatCredit(rechargeReqDTO.getStoreId(), tradeMode, money, Long.parseLong(rechargeReqDTO.getOrderId()), tradeType, rechargeReqDTO.getRefundId());
                                TenantUtils.execute(distributor.getAccountTenantId(), () -> {
                                    CommonResult<StoreRespDTO> storeResult = storeApi.storePlatTrade(reqDTO);
                                    Asserts.isTrue(storeResult.isSuccess(), storeResult.getMsg());
                                });
                                afterBalance = beforeBalance.add(money);
                                //充值
                                tradeName = "门店归还授信额度：" + money + "元,归还后额度" + afterBalance + "元;";
                                //操作账户资金
                                flag = distributorService.addPayCredit(distributor.getId(), money);

                                tradeMode =1;//对于平台是增加
                            }
                            break;
                        default:
                            break;
                    }
                    // 授信付款
                    if (tradeType == DistributorTradeTypeEnum.CREDIT_TRANS.getType()) {

                        tradeMode = 2;
                        //门店平台授信
                        AtomicBoolean isShareCredit = new AtomicBoolean(false);
                        AtomicReference<StoreRespDTO> storeRespDTO = new AtomicReference<>();
//                        if (rechargeReqDTO.getStoreId() != null){
//                            StoreReqDTO reqDTO = this.convertStorePlatCredit(rechargeReqDTO.getStoreId(), tradeMode, money, Long.parseLong(rechargeReqDTO.getOrderId()), tradeType, null);
//                            TenantUtils.execute(distributor.getAccountTenantId(), () -> {
//                                StoreInfoReqDTO storeData = storeApi.getStoreById(rechargeReqDTO.getStoreId()).getCheckedData();
//                                if(ObjectUtil.equals(storeData.getCreditType(), StoreCreditTypeEnum.FIXED.getType())){
//                                    CommonResult<StoreRespDTO> storeResult = storeApi.storePlatTrade(reqDTO);
//                                    Asserts.isTrue(storeResult.isSuccess(), storeResult.getMsg());
//                                    storeRespDTO.set(storeResult.getCheckedData());
//                                }else if(ObjectUtil.equals(storeData.getCreditType(), StoreCreditTypeEnum.SHARE.getType())){
//                                    isShareCredit.set(true);
//                                }else {
//                                    Asserts.isTrue(true,"该门店禁用授信支付方式");
//                                }
//
//                            });
//                        }else{
//                            isShareCredit.set(true);
//                        }
                        if(true){
                            Asserts.isTrue(isUseCredit, "分销商无授信交易权限！");
                            // 授信总额
                            BigDecimal payCredit = distributor.getPayCredit();
                            // 交易前已使用额度
                            beforeBalance = distributor.getSurplus();
                            // 交易后已使用额度
                            afterBalance = beforeBalance.add(money);
                            if (payCredit != null) {
//                                if (afterBalance.compareTo(payCredit) > 0) {
//                                    if(originTradeType == DistributorTradeTypeEnum.BALANCE_TRANS.getType()){
//                                        throw exception0(11_028, "余额不足，交易失败！");
//                                    }else {
//                                        throw exception(CREDIT_INSUFFICIENT_FUNDS);
//                                    }
//
//                                }
                                BigDecimal creditRemained = payCredit.subtract(afterBalance);
                                tradeName = "授信消费金额：" + money + "元,授信总额度" + payCredit + "元,消费后剩余额度" + creditRemained + "元;已用额度" + afterBalance + "元";
                            } else {
                                tradeName = "授信消费金额：" + money + "元,授信总额度不限,消费后剩余额度不限;已用额度" + afterBalance + "元";
                            }
                            distributorService.addSurplus(distributor.getId(), money);
                            flag = true;
                        }else if(storeRespDTO.get()!=null){
                            StoreRespDTO storeRsp = storeRespDTO.get();
                            beforeBalance = storeRsp.getBeforeAmount();
                            afterBalance = storeRsp.getAfterAmount();
                            tradeName = "授信支付金额：" + money + "元,支付后门店已使用授信从" + storeRsp.getBeforeAmount() + "元；变为"+ storeRsp.getAfterAmount();
                            flag = true;
                        }
                    }

                    respDTO = new DistributorRechargeRespDTO();
                    respDTO.setRechargeType(tradeType);
                    if (flag) {

                        //添加ota消费记录数据
                        TradeLogDO logDO = new TradeLogDO();
                        logDO.setOperatorId(distributor.getId());
                        logDO.setOperatorName(distributor.getName());
                        logDO.setRemark(tradeName);
                        logDO.setTradeMode(tradeMode);
                        logDO.setTradeType(tradeType);
                        // 余额表示交易前金额 授信表示交易前已使用额度
                        logDO.setBeforeBalance(beforeBalance);
                        // 余额表示交易后金额 授信表示交易后已使用额度
                        logDO.setAfterBalance(afterBalance);
                        logDO.setTradeAmount(money);
                        logDO.setTradeTime(LocalDateTime.now());
                        logDO.setDistributorId(distributor.getId());
                        logDO.setTenantId(distributor.getTenantId());
                        logDO.setOrderId(rechargeReqDTO.getOrderId());
                        logDO.setStoreId(rechargeReqDTO.getStoreId());
                        Long tradeId = tradeLogService.saveTradeLog(logDO);
                        respDTO.setTradeId(tradeId);
                        respDTO.setRechargeType(tradeType);
                    } else {
                        if(!((tradeType == DistributorTradeTypeEnum.CREDIT_RECHARGE.getType() || tradeType == DistributorTradeTypeEnum.CREDIT_TRANS.getType() )&& rechargeReqDTO.getStoreId()!=null)){
                            throw exception(DISTRIBUTOR_PAY_FAILED);
                        }
                    }
                }
            }
        } catch (ServiceException e) {
            log.error("[分销商支付]{}", e);
            throw new ServiceException(e.getCode(), e.getMessage());
        } catch (Exception e) {
            log.error("[分销商支付]", e);
            throw exception(DISTRIBUTOR_PAY_FAILED);
        } finally {
            if (null != lock && lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
        return CommonResult.success(respDTO);
    }

    private StoreReqDTO convertStorePlatCredit(Long storeId, Integer mode, BigDecimal amount,Long orderId,Integer tradeType,Long refundId) {
        StoreReqDTO reqDTO = new StoreReqDTO();
        reqDTO.setOperateType(4);
        reqDTO.setStoreId(storeId);
        reqDTO.setAmount(amount);
        reqDTO.setOrderId(orderId);
        reqDTO.setOperateMode(mode);
        Integer type = null;
        if (ObjectUtil.equals(tradeType,DistributorTradeTypeEnum.CREDIT_TRANS.getType())){
            type = 9;
        }else if (ObjectUtil.equals(tradeType,DistributorTradeTypeEnum.CREDIT_REFUND.getType())){
            type = 10;
        }else if (ObjectUtil.equals(tradeType,DistributorTradeTypeEnum.CREDIT_RECHARGE.getType())){
            type = 11;
        }else if (ObjectUtil.equals(tradeType,DistributorTradeTypeEnum.CREDIT_DISTRIBUTE_STORE.getType())){
            type = mode==1?15:18;
        }
        TradeModeEnum tradeModeEnum = TradeModeEnum.valueOf(4, type, mode);
        reqDTO.setTradeModeEnum(tradeModeEnum);
        reqDTO.setRefundId(refundId);
        return reqDTO;
    }

    private StoreReqDTO convertStorePlatBalance(Long storeId, Integer mode, BigDecimal amount,Long orderId,Integer tradeType,Long refundId) {
        StoreReqDTO reqDTO = new StoreReqDTO();
        reqDTO.setOperateType(5);
        reqDTO.setStoreId(storeId);
        reqDTO.setAmount(amount);
        reqDTO.setOrderId(orderId);
        reqDTO.setOperateMode(mode);
        Integer type = null;
        if (ObjectUtil.equals(tradeType,DistributorTradeTypeEnum.BALANCE_TRANS.getType())){
            type = 12;
        }else if (ObjectUtil.equals(tradeType,DistributorTradeTypeEnum.BALANCE_REFUND.getType())){
            type = 13;
        }else if (ObjectUtil.equals(tradeType,DistributorTradeTypeEnum.BALANCE_DISTRIBUTE_STORE.getType())){
            type = mode == 1?14:16;
        }else if(ObjectUtil.equals(tradeType,DistributorTradeTypeEnum.BALANCE_PAY_CREDIT_BILL.getType())){
            type = 19;
        }else if(ObjectUtil.equals(tradeType,DistributorTradeTypeEnum.STOCK_DIRECT_TRANS.getType())){
            type = 20;
        }else if(ObjectUtil.equals(tradeType,DistributorTradeTypeEnum.STOCK_DIRECT_REFUND.getType())){
            type = 21;
        }else if(ObjectUtil.equals(tradeType,DistributorTradeTypeEnum.GUIDE_REFUND_BALANCE_TRANS.getType())){
            type = 22;
        }else if(ObjectUtil.equals(tradeType,DistributorTradeTypeEnum.GUIDE_REFUND_BALANCE_TRANS_CANCEL.getType())){
            type = 23;
        }
        TradeModeEnum tradeModeEnum = TradeModeEnum.valueOf(5, type, mode);
        reqDTO.setTradeModeEnum(tradeModeEnum);
        reqDTO.setRefundId(refundId);
        return reqDTO;
    }

}
