package com.yc.ship.module.otc.service.store;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.yc.ship.framework.common.enums.CommonStatusEnum;
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.PageParam;
import com.yc.ship.framework.common.pojo.PageResult;
import com.yc.ship.framework.common.util.object.BeanUtils;
import com.yc.ship.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.yc.ship.framework.mybatis.core.query.MPJLambdaWrapperX;
import com.yc.ship.framework.mybatis.core.util.MyBatisUtils;
import com.yc.ship.framework.security.core.LoginUser;
import com.yc.ship.framework.security.core.util.SecurityFrameworkUtils;
import com.yc.ship.framework.tenant.core.aop.TenantIgnore;
import com.yc.ship.framework.tenant.core.context.TenantContextHolder;
import com.yc.ship.module.ota.api.OtaDistributorApi;
import com.yc.ship.module.ota.api.dto.DistributorRechargeReqDTO;
import com.yc.ship.module.ota.api.dto.DistributorRechargeRespDTO;
import com.yc.ship.module.ota.api.dto.DistributorRespDTO;
import com.yc.ship.module.ota.enums.DistributorTradeTypeEnum;
import com.yc.ship.module.otc.api.store.dto.StoreCardRespDTO;
import com.yc.ship.module.otc.api.store.dto.StoreMachineDTO;
import com.yc.ship.module.otc.api.store.dto.StoreProductReqDTO;
import com.yc.ship.module.otc.controller.admin.store.machine.SellerMachineRespVO;
import com.yc.ship.module.otc.controller.admin.store.vo.*;
import com.yc.ship.module.otc.controller.admin.storecard.vo.StoreCardSaveReqVO;
import com.yc.ship.module.otc.controller.admin.storecreditlog.vo.StoreCreditLogSaveReqVO;
import com.yc.ship.module.otc.controller.admin.storeplatcreditlog.vo.StorePlatCreditLogSaveReqVO;
import com.yc.ship.module.otc.controller.admin.storetradelog.vo.StoreTradeLogSaveReqVO;
import com.yc.ship.module.otc.convert.store.StoreConvert;
import com.yc.ship.module.otc.dal.dataobject.store.*;
import com.yc.ship.module.otc.dal.dataobject.storeaudit.StoreAuditDO;
import com.yc.ship.module.otc.dal.dataobject.storecard.StoreCardDO;
import com.yc.ship.module.otc.dal.mysql.store.*;
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.otc.enums.UseStatusEnum;
import com.yc.ship.module.otc.service.storecard.StoreCardService;
import com.yc.ship.module.otc.service.storecreditlog.StoreCreditLogService;
import com.yc.ship.module.otc.service.storecreditlog.StorePlatCreditLogService;
import com.yc.ship.module.otc.service.storetradelog.StoreTradeLogService;
import com.yc.ship.module.system.api.user.AdminUserApi;
import com.yc.ship.module.system.api.user.dto.AdminUserRespDTO;
import org.apache.commons.lang3.ObjectUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

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.getLoginUser;
import static com.yc.ship.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static com.yc.ship.module.otc.enums.ErrorCodeConstants.*;

/**
 * 旅行社门店 Service 实现类
 *
 * @author 管理员
 */
@Service
@Validated
public class StoreServiceImpl implements StoreService {

    @Resource
    private AdminUserApi adminUserApi;

    @Resource
    private StoreMapper storeMapper;
    @Resource
    private StoreUserMapper storeUserMapper;
    @Resource
    private StoreMachineMapper storeMachineMapper;
    @Resource
    private StoreProductMapper storeProductMapper;
    @Resource
    private StoreMachineProductMapper storeMachineProductMapper;

    @Resource
    private StoreCardService storeCardService;
    @Resource
    private OtaDistributorApi otaDistributorApi;
    @Resource
    private StorePlatCreditLogService platCreditLogService;

    @Override
    @Transactional
    public Long createStore(StoreSaveReqVO createReqVO) {
        LoginUser loginUser = getLoginUser();
        Long distributorId = null;
        DistributorRespDTO distributor = otaDistributorApi.getDistributorByLoginUserId(loginUser.getId());
        if(distributor == null) {
            throw new ServiceException(NOT_ASSOCIATED_DISTRIBUTOR);
        }else {
            distributorId = distributor.getId();
        }

        // 插入
        StoreDO store = BeanUtils.toBean(createReqVO, StoreDO.class);
        long id = IdWorker.getId(store);
        store.setId(id);
        store.setDeleted(false);
        store.setAgencyId(distributorId);
        if(store.getAuditStatus() == null) {
            store.setAuditStatus(0);
        }
        StoreCardSaveReqVO createCardReqVO = new StoreCardSaveReqVO();
        createCardReqVO.setStoreId(store.getId());
        createCardReqVO.setCredit(BigDecimal.ZERO);
        createCardReqVO.setBalanceType(createReqVO.getBalanceType());
        createCardReqVO.setCreditType(createReqVO.getCreditType());
        createCardReqVO.setBalance(BigDecimal.ZERO);
        createCardReqVO.setSurplus(BigDecimal.ZERO);
        storeCardService.createStoreCard(createCardReqVO);
        storeMapper.insert(store);
        // 返回
        return store.getId();
    }

    @Override
    @Transactional
    public void updateStore(StoreSaveReqVO updateReqVO) {
        // 校验存在
        validateStoreExists(updateReqVO.getId());
        // 更新
        StoreDO updateObj = BeanUtils.toBean(updateReqVO, StoreDO.class);
        updateObj.setAuditStatus(null);//不更审核状态字段
        StoreCardSaveReqVO createCardReqVO = new StoreCardSaveReqVO();
        createCardReqVO.setStoreId(updateObj.getId());
        createCardReqVO.setBalanceType(updateReqVO.getBalanceType());
        createCardReqVO.setCreditType(updateReqVO.getCreditType());
//        createCardReqVO.setCredit(updateReqVO.getCredit());
        storeCardService.updateStoreCard(createCardReqVO);
        storeMapper.updateById(updateObj);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteStore(Long id) {
        // 校验存在
        validateStoreExists(id);
        // 删除
        storeMapper.deleteById(id);

        // 删除子表
        deleteStoreMachineByStoreId(id);
        deleteStoreUserByStoreId(id);
        deleteStoreProductByStoreId(id);
    }

    @Override
    @TenantIgnore
    public Long auditStore(StoreAuditReqVO auditReqVO) {
        StoreDO storeDO = storeMapper.selectById(auditReqVO.getStoreId());
        Asserts.isTrue(storeDO!=null,"门店信息不存在");
        StoreDO updateDO = new StoreDO();
        updateDO.setId(auditReqVO.getStoreId());
        if(auditReqVO.getAuditStatus() == 1){
            updateDO.setAuditStatus(1);
        }else{
            updateDO.setAuditStatus(2);
        }
        storeMapper.updateById(updateDO);
        return updateDO.getId();
    }

    private void validateStoreExists(Long id) {
        if (storeMapper.selectById(id) == null) {
            throw exception(STORE_NOT_EXISTS);
        }
    }

    @Override
    public StoreDO getStore(Long id) {
        return storeMapper.selectById(id);
    }

    @Override
    public StoreCardRespDTO getStoreByUserId(Long userId) {
        return storeMapper.getStoreByUserId(userId);
    }
    @Override
    public PageResult<StoreDO> getStorePage(StorePageReqVO pageReqVO) {
        Long loginUserId = getLoginUserId();
        DistributorRespDTO distributor = otaDistributorApi.getDistributorByLoginUserId(loginUserId);
        if(distributor == null) {
            throw new ServiceException(NOT_ASSOCIATED_DISTRIBUTOR);
        }
        pageReqVO.setAgencyId(distributor.getId());
        return storeMapper.selectPage(pageReqVO);
    }

    @Override
    @TenantIgnore
    public PageResult<StoreRespVO> getAuditStorePage(StoreAuditPageReqVO pageReqVO) {
        IPage<StoreRespVO> ipage = MyBatisUtils.buildPage(pageReqVO);
        IPage<StoreRespVO> result = storeMapper.selectAuditPage(ipage,pageReqVO);
        return new PageResult<>(result.getRecords(), result.getTotal());
    }

    @Override
    public void updateStoreStatus(Long id, Integer status) {
        // 校验用户存在
        validateStoreExists(id);
        // 更新状态
        StoreDO updateObj = new StoreDO();
        updateObj.setId(id);
        updateObj.setIsUse(status);
        storeMapper.updateById(updateObj);
    }

    @Override
    public List<StoreDO> getSotreList(Collection<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return Collections.emptyList();
        }
        return storeMapper.selectBatchIds(ids);
    }

    @Override
    public List<StoreDO> getStoreListByStatus(Integer status) {
        long tenantId = TenantContextHolder.getTenantId();
        return storeMapper.selectListByStatus(tenantId, status);
    }

    // ==================== 子表（关联设备） ====================

    @Override
    public PageResult<StoreMachineDO> getStoreMachinePage(PageParam pageReqVO, Long storeId) {
        return storeMachineMapper.selectPage(pageReqVO, storeId);
    }

    @Override
    public Long createStoreMachine(StoreMachineDO storeMachine) {
        storeMachine.setId(IdWorker.getId(storeMachine));
        storeMachine.setDeleted(false);
        verifyConflict(storeMachine);
        storeMachineMapper.insert(storeMachine);
        return storeMachine.getId();
    }

    @Override
    public void updateStoreMachine(StoreMachineDO storeMachine) {
        // 校验存在
        validateStoreMachineExists(storeMachine.getId());
        // 校验设备编码是否重复
        verifyConflict(storeMachine);
        // 更新
        storeMachineMapper.updateById(storeMachine);
    }

    @Override
    public void deleteStoreMachine(Long id) {
        // 校验存在
        validateStoreMachineExists(id);
        // 删除
        storeMachineMapper.deleteById(id);
    }

    @Override
    public StoreMachineDO getStoreMachine(Long id) {
        return storeMachineMapper.selectById(id);
    }

    @Override
    public List<StoreMachineDO> getStoreMachineListByStatus(Integer machineType) {
        if (machineType == null) {
            return storeMachineMapper.selectList(StoreMachineDO::getIsUse, 1);
        } else {
            return storeMachineMapper.selectList(StoreMachineDO::getIsUse, 1, StoreMachineDO::getMachineType, machineType);
        }
    }

    @Override
    public List<SellerMachineRespVO> getSellerMachine() {
        Long userId = SecurityFrameworkUtils.getLoginUserId();
        return storeMapper.getSellerMachine(userId);
    }

    private void validateStoreMachineExists(Long id) {
        if (storeMachineMapper.selectById(id) == null) {
            throw exception(STORE_MACHINE_NOT_EXISTS);
        }
    }

    private void verifyConflict(StoreMachineDO machine) {
        Long id = machine.getId();
        String machineId = machine.getMachineId();
        int machineType = machine.getMachineType();
        List<StoreMachineDO> machineList = storeMachineMapper.getStoreMachine(machineId);
        machineList = machineList != null && !machineList.isEmpty() ? machineList : new ArrayList<>(3);
        if (id != null) {
            machineList.removeIf(item -> ObjUtil.equal(item.getId(), id));
        }
        if (!machineList.isEmpty()) {
            throw exception(STORE_MACHINE_CODE_EXISTS);
        }
    }

    private void deleteStoreMachineByStoreId(Long storeId) {
        storeMachineMapper.deleteByStoreId(storeId);
    }

    // ==================== 子表（门店账号关联） ====================

    @Override
    public PageResult<StoreUserDO> getStoreUserPage(PageParam pageReqVO, Long storeId) {
        return storeUserMapper.selectPage(pageReqVO, storeId);
    }

    @Override
    @Transactional
    public Long createStoreUser(StoreUserDO storeUser) {
        StoreUserDO dbStoreUser;
        long storeId = storeUser.getStoreId();
        // 绑定过的账号
        List<StoreUserDO> boundStoreUserList = storeUserMapper.selectListByUserIds(storeUser.getCheckedValues());
        boundStoreUserList = boundStoreUserList.stream().filter(item -> !item.getStoreId().equals(storeId)).collect(Collectors.toList());
        if (!boundStoreUserList.isEmpty()) {
            List<AdminUserRespDTO> users = adminUserApi.getUserList(boundStoreUserList.stream().map(StoreUserDO::getUserId).collect(Collectors.toList()));
            List<StoreDO> stores = storeMapper.selectStoreByStoreIds(boundStoreUserList.stream().map(StoreUserDO::getStoreId).collect(Collectors.toList()));
            StringBuilder sb = new StringBuilder();
            for (StoreUserDO storeUserDO : boundStoreUserList) {
                String userName = users.stream().filter(item -> item.getId().equals(storeUserDO.getUserId())).findFirst().get().getNickname();
                String soreName = stores.stream().filter(item -> item.getId().equals(storeUserDO.getStoreId())).findFirst().get().getStoreName();
                sb.append("账号：").append(userName).append("，已被门店：").append(soreName).append("绑定;");
            }
            String msg = sb.toString();
            // todo 返回更详细信息（账号名+门店名）
            throw exception0(10_011, msg.substring(0, msg.length() - 1));
        }
        List<StoreUserDO> storeUserList = storeUserMapper.selectList(StoreUserDO::getStoreId, storeId);
        for (StoreUserDO storeUserDO : storeUserList) {
            boolean flag = false;
            for (long userId : storeUser.getCheckedValues()) {
                if (userId == storeUserDO.getUserId()) {
                    flag = true;
                    break;
                }
            }
            if (!flag) {
                deleteStoreUser(storeUserDO.getId());
            }
        }
        Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
        LocalDateTime localDateTime = LocalDateTime.now();
        for (long userId : storeUser.getCheckedValues()) {
            boolean flag = false;
            for (StoreUserDO storeUserDO : storeUserList) {
                if (userId == storeUserDO.getUserId()) {
                    flag = true;
                    break;
                }
            }
            if (!flag) {
                dbStoreUser = new StoreUserDO();
                dbStoreUser.setCreator(ObjectUtils.defaultIfNull(loginUserId + "", ""));
                dbStoreUser.setCreateTime(localDateTime);
                dbStoreUser.setUserId(userId);
                dbStoreUser.setStoreId(storeUser.getStoreId());
                dbStoreUser.setId(IdWorker.getId(dbStoreUser));
                storeUserMapper.insert(dbStoreUser);

                adminUserApi.updateUserStore(userId, storeUser.getStoreId());
            }
        }
        return storeUser.getId();
    }

    @Override
    public void updateStoreUser(StoreUserDO storeUser) {
        // 校验存在
        validateStoreUserExists(storeUser.getId());
        // 更新
        storeUserMapper.updateById(storeUser);
    }

    @Override
    public void deleteStoreUser(Long id) {
        // 校验存在
        validateStoreUserExists(id);
        // 删除
        storeUserMapper.deleteById(id);
    }

    @Override
    public void deleteStoreUserByUserId(Long userId, Long storeId) {
        storeUserMapper.deleteStoreUserByUserId(userId, storeId);
        adminUserApi.updateUserStore(userId, null);
    }

    @Override
    public List<StoreUserDO> getStoreUser(Long storeId) {
        return storeUserMapper.selectList(StoreUserDO::getStoreId, storeId);
    }

    @Override
    public List<StoreUserDO> getStoreUserList(int type, Collection<Long> ids) {
        // 0.忽略所有条件 1.根据主键ID查询 2.根据用户ID查询
        switch (type) {
            case 1:
                if (CollUtil.isEmpty(ids)) {
                    return Collections.emptyList();
                }
                return storeUserMapper.selectBatchIds(ids);
            case 2:
                if (CollUtil.isEmpty(ids)) {
                    return Collections.emptyList();
                }
                return storeUserMapper.selectListByUserIds((List<Long>) ids);
            default:
                return storeUserMapper.selectList();

        }

    }

    private void validateStoreUserExists(Long id) {
        if (storeUserMapper.selectById(id) == null) {
            throw exception(STORE_USER_NOT_EXISTS);
        }
    }

    private void deleteStoreUserByStoreId(Long storeId) {
        storeUserMapper.deleteByStoreId(storeId);
    }


    // ==================== 子表（门店产品关联） ====================

    @Override
    public PageResult<StoreProductDO> getStoreProductPage(PageParam pageReqVO, Long storeId) {
        return storeProductMapper.selectPage(pageReqVO, storeId);
    }

    @Override
    @Transactional
    public Long createStoreProduct(StoreProductDO storeProduct) {
        StoreProductDO dbStoreProduct;
        long storeId = storeProduct.getStoreId();
        List<StoreProductDO> storeProductList = storeProductMapper.selectList(StoreProductDO::getStoreId, storeId);
        List<Long> productIds = new ArrayList<>();
        List<Long> deleteProductIds = new ArrayList<>();
        for (StoreProductDO storeProductDO : storeProductList) {
            boolean flag = false;
            for (long productId : storeProduct.getCheckedValues()) {
                if (productId == storeProductDO.getProductId()) {
                    List<Long> fiterProductIds = productIds.stream().filter(item -> item.equals(productId)).collect(Collectors.toList());
                    if(fiterProductIds!=null && fiterProductIds.size()>0){
                        flag = false;
                    }else {
                        flag = true;
                        productIds.add(productId);
                        break;
                    }
                }
            }
            if (!flag) {
//                deleteStoreProduct(storeProductDO.getId());
                deleteProductIds.add(storeProductDO.getId());
            }
        }
        if(deleteProductIds!=null && deleteProductIds.size()>0) {
            storeProductMapper.deleteBatchIds(deleteProductIds);
        }
        LocalDateTime localDateTime = LocalDateTime.now();
        List<StoreProductDO> insertStoreProduct = new ArrayList<>();
        for (long productId : storeProduct.getCheckedValues()) {
            boolean flag = false;
            for (StoreProductDO storeProductDO : storeProductList) {
                if (productId == storeProductDO.getProductId()) {
                    flag = true;
                    break;
                }
            }
            if (!flag) {
                dbStoreProduct = new StoreProductDO();
                dbStoreProduct.setCreateTime(localDateTime);
                dbStoreProduct.setProductId(productId);
                dbStoreProduct.setStoreId(storeProduct.getStoreId());
                dbStoreProduct.setId(IdWorker.getId(dbStoreProduct));
                insertStoreProduct.add(dbStoreProduct);
//                storeProductMapper.insert(dbStoreProduct);
            }
        }
        storeProductMapper.insertBatch(insertStoreProduct);
        return storeProduct.getId();
    }

    @Override
    public void updateStoreProduct(StoreProductDO storeProduct) {
        // 校验存在
        validateStoreProductExists(storeProduct.getId());
        // 更新
        storeProductMapper.updateById(storeProduct);
    }

    @Override
    public void deleteStoreProduct(Long id) {
        // 校验存在
        validateStoreProductExists(id);
        // 删除
        storeProductMapper.deleteById(id);
    }

    public void deleteStoreProductByStoreId(Long storeId) {
        // 删除
        storeProductMapper.deleteByStoreId(storeId);
    }

    @Override
    public List<StoreProductDO> getStoreProduct(Long storeId) {
        return storeProductMapper.selectList(StoreProductDO::getStoreId, storeId);
    }

    private void validateStoreProductExists(Long id) {
        if (storeProductMapper.selectById(id) == null) {
            throw exception(STORE_PRODUCT_NOT_EXISTS);
        }
    }


    @Override
    @Transactional
    public Long createStoreMachineProduct(StoreMachineProductDO storeMachineProduct) {
        StoreMachineProductDO dbStoreMachineProduct;
        long storeId = storeMachineProduct.getStoreId();
        long machineId = storeMachineProduct.getMachineId();
        List<StoreMachineProductDO> storeMachineProductList = storeMachineProductMapper.selectList(StoreMachineProductDO::getStoreId, storeId, StoreMachineProductDO::getMachineId, machineId);
        for (StoreMachineProductDO storeMachineProductDO : storeMachineProductList) {
            boolean flag = false;
            for (long productId : storeMachineProduct.getCheckedValues()) {
                if (productId == storeMachineProductDO.getProductId()) {
                    flag = true;
                    break;
                }
            }
            if (!flag) {
                deleteStoreMachineProduct(storeMachineProductDO.getId());
            }
        }
        LocalDateTime localDateTime = LocalDateTime.now();
        for (long productId : storeMachineProduct.getCheckedValues()) {
            boolean flag = false;
            for (StoreMachineProductDO storeMachineProductDO : storeMachineProductList) {
                if (productId == storeMachineProductDO.getProductId()) {
                    flag = true;
                    break;
                }
            }
            if (!flag) {
                dbStoreMachineProduct = new StoreMachineProductDO();
                dbStoreMachineProduct.setCreateTime(localDateTime);
                dbStoreMachineProduct.setProductId(productId);
                dbStoreMachineProduct.setMachineId(storeMachineProduct.getMachineId());
                dbStoreMachineProduct.setStoreId(storeMachineProduct.getStoreId());
                dbStoreMachineProduct.setId(IdWorker.getId(dbStoreMachineProduct));
                storeMachineProductMapper.insert(dbStoreMachineProduct);
            }
        }
        // 插入
//        storeMachineProductMapper.insert(storeMachineProduct);
        // 返回
        return storeMachineProduct.getId();
    }

    @Override
    public void updateStoreMachineProduct(StoreMachineProductDO storeMachineProduct) {
        // 校验存在
        validateStoreMachineProductExists(storeMachineProduct.getId());
        // 更新
        storeMachineProductMapper.updateById(storeMachineProduct);
    }

    @Override
    public void deleteStoreMachineProduct(Long id) {
        // 校验存在
        validateStoreMachineProductExists(id);
        // 删除
        storeMachineProductMapper.deleteById(id);
    }

    private void validateStoreMachineProductExists(Long id) {
        if (storeMachineProductMapper.selectById(id) == null) {
            throw exception(STORE_MACHINE_PRODUCT_NOT_EXISTS);
        }
    }

    @Override
    public List<StoreMachineProductDO> getStoreMachineProduct(Long storeId, Long machineId) {
        return storeMachineProductMapper.selectList(StoreMachineProductDO::getStoreId, storeId, StoreMachineProductDO::getMachineId, machineId);
    }

    @Resource
    private RedissonClient redissonClient;

    @Resource
    private StoreTradeLogService storeTradeLogService;

    @Resource
    private StoreCreditLogService storeCreditLogService;

    /**
     * @param storeId    门店ID
     * @param tradeMode  交易类型 0.不变 1.增加、2.减少 3.回滚
     * @param amount     充值金额/交易金额/额度变更金额
     * @param userId     用户ID
     * @param orderId    订单ID
     * @param tradeLogId 支付记录ID 回滚使用
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long updateStoreCard(Long storeId, TradeModeEnum tradeMode, BigDecimal amount, Long userId, Long orderId, Long refundId, Long tradeLogId) {
        String key = "[store-in]" + storeId;
        StoreDO store = getStore(storeId);
        RLock lock = redissonClient.getLock(key);
        BigDecimal beforeBigDecimal;
        BigDecimal afterBigDecimal = null;
        try {
            Long logId;
            StoreCardDO cardDO;
            if (lock.tryLock(30, 60, TimeUnit.SECONDS)) {
                try {
                    cardDO = storeCardService.getStoreCardByStoreId(storeId);
                    Assert.notNull(cardDO, "门店资金卡不存在！");
                    StoreCardSaveReqVO saveReqVO = new StoreCardSaveReqVO();
                    saveReqVO.setId(cardDO.getId());
                    saveReqVO.setStoreId(cardDO.getStoreId());
                    switch (tradeMode.getOperateType()) {
                        case 1:
                        case 5:
                            // 余额交易流水
                            beforeBigDecimal = cardDO.getBalance();
                            if (tradeMode.getMode() == 1) {
                                // 增加
                                afterBigDecimal = beforeBigDecimal.add(amount);
                            } else if (tradeMode.getMode() == 2) {
                                // 减少
                                afterBigDecimal = beforeBigDecimal.subtract(amount);
                                if (afterBigDecimal.compareTo(BigDecimal.ZERO) < 0) {
                                    throw exception(STORE_REQUEST_BALANCE);
                                }
                            } else {
                                // 回滚
                                afterBigDecimal = beforeBigDecimal.add(amount);
                            }
                            saveReqVO.setBalance(afterBigDecimal);
                            break;
                        case 2:
                        case 4:
                            if (cardDO.getCreditType() == 0) {
                                throw exception(STORE_REQUEST_NOT_ENABLE);
                            }
                            // 授信交易流水
                            BigDecimal credit = cardDO.getCredit();
                            beforeBigDecimal = cardDO.getSurplus();
                            if (tradeMode.getMode() == 1) {
                                // 增加 使用额度减少
                                afterBigDecimal = beforeBigDecimal.subtract(amount);
                            } else if (tradeMode.getMode() == 2) {
                                // 减少 使用额度增加
                                afterBigDecimal = beforeBigDecimal.add(amount);
                                if (afterBigDecimal.compareTo(credit) > 0) {
                                    throw exception(STORE_REQUEST_SURPLUS);
                                }
                            } else {
                                // 回滚
                                afterBigDecimal = beforeBigDecimal.subtract(amount);
                            }
                            saveReqVO.setSurplus(afterBigDecimal);
                            break;
                        case 3:
                            if (cardDO.getCreditType() == 0) {
                                throw exception(STORE_REQUEST_NOT_ENABLE);
                            }
                            // 额度变更流水
                            beforeBigDecimal = cardDO.getCredit();
                            if (tradeMode.getMode() == 1) {
                                // 增加
                                afterBigDecimal = beforeBigDecimal.add(amount);
                            } else if (tradeMode.getMode() == 2) {
                                // 减少
                                afterBigDecimal = beforeBigDecimal.subtract(amount);
                                if (afterBigDecimal.compareTo(BigDecimal.ZERO) < 0) {
                                   throw exception(STORE_REQUEST_CREDIT);
                                }
                            }
                            saveReqVO.setCredit(afterBigDecimal);
                            break;
                        default:
                            throw exception(STORE_REQUEST_ERROR);

                    }
                    storeCardService.updateStoreCard(saveReqVO);
                    if (tradeMode.getMode() == 3) {
                        // 删除交易记录
                        int num = storeTradeLogService.deleteStoreTradeLogById(tradeLogId);
                        logId = (long) num;
                    } else {
                        logId = saveLog(store, tradeMode, beforeBigDecimal, afterBigDecimal, amount, userId, orderId, refundId);
                    }
                } catch (Exception ex) {
                    throw ex;
                } finally {
                    if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                        lock.unlock();
                    }
                }
                return logId;
            } else {
                throw exception(STORE_REQUEST_TIMEOUT);
            }
        } catch (Exception e) {
            if(e instanceof ServiceException) {
                throw (ServiceException)e;
            }
            throw exception(STORE_REQUEST_FAIL);
        }
    }

    @Override
    public StoreMachineDTO getMachineByMachineId(String machineId) {
        MPJLambdaWrapper<StoreMachineDO> wrapper = new MPJLambdaWrapperX<StoreMachineDO>()
                .selectAll(StoreMachineDO.class)
                .selectAs(StoreDO::getStoreName, StoreMachineDTO::getStoreName)
                .innerJoin(StoreDO.class, StoreDO::getId, StoreMachineDO::getStoreId)
                .eq(StoreMachineDO::getMachineId, machineId);
        return storeMachineMapper.selectJoinOne(StoreMachineDTO.class, wrapper);
    }

    /**
     * 回滚资金卡
     *
     * @param lock
     * @param cardId
     */
    private void fallbackCard(RLock lock, Long cardId) {
        try {
            if (lock.tryLock(30, 60, TimeUnit.SECONDS)) {
                StoreCardDO cardDO = storeCardService.getStoreCard(cardId);
                StoreCardSaveReqVO originalReqVO = new StoreCardSaveReqVO();
                originalReqVO.setId(cardDO.getId());
                originalReqVO.setStoreId(cardDO.getStoreId());
                originalReqVO.setBalance(cardDO.getBalance());
                originalReqVO.setCredit(cardDO.getCredit());
                originalReqVO.setSurplus(cardDO.getSurplus());
                storeCardService.updateStoreCard(originalReqVO);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }

    }

    private Long saveLog(StoreDO store, TradeModeEnum tradeMode, BigDecimal beforeBigDecimal, BigDecimal afterBigDecimal, BigDecimal amount, Long userId, Long orderId, Long refundId) {
        if (tradeMode.getOperateType() == 3) {
            // 授信额度变更
            StoreCreditLogSaveReqVO saveReqVO = new StoreCreditLogSaveReqVO();
            saveReqVO.setStoreId(store.getId());
            saveReqVO.setBeforeCredit(beforeBigDecimal);
            saveReqVO.setAfterCredit(afterBigDecimal);
            saveReqVO.setCreditAmount(amount);
            saveReqVO.setUserId(userId + "");
            saveReqVO.setTenantId(store.getTenantId());
            int mode = tradeMode.getMode();
            saveReqVO.setCreditMode(mode);
            String remark;
            if (mode == 1) {
                remark = "提额申请通过！额度提升" + amount.setScale(2) + "元，提升后授信额度为" + afterBigDecimal.setScale(2);
            } else {
                remark = "降额申请通过！额度降低" + amount.setScale(2) + "元，降低后授信额度为" + afterBigDecimal.setScale(2);
            }
            saveReqVO.setRemark(remark);
            return storeCreditLogService.createStoreCreditLog(saveReqVO);
        } else {
            // 交易流水
            StoreTradeLogSaveReqVO saveReqVO = new StoreTradeLogSaveReqVO();
            saveReqVO.setStoreId(store.getId());
            saveReqVO.setBeforeBalance(beforeBigDecimal);
            saveReqVO.setAfterBalance(afterBigDecimal);
            saveReqVO.setTradeAmount(amount);
            saveReqVO.setCreator(userId == null ? "" : userId.toString());
            saveReqVO.setTenantId(store.getTenantId());
            int mode = tradeMode.getMode();
            saveReqVO.setTradeMode(mode);
            // 1.管理员余额充值、2.管理员授信充值、3.余额购票、4.授信购票、5.余额退款、6.授信退款
            String remark = "";
            switch (tradeMode.getType()) {
                case 1:
                    remark = tradeMode.getName() + "申请通过！充值金额为" + amount + "元，充值后可用余额为" + afterBigDecimal + "元。";
                    break;
                case 2:
                    remark = tradeMode.getName() + "申请通过！充值金额为" + amount + "元，充值后已用授信额度为" + afterBigDecimal + "元。";
                    break;
                case 5:
                case 7:
                case 12:
                case 13:
                case 14:
                case 16:
                case 19:
                case 20:
                case 21:
                case 22:
                case 23:
                    remark = tradeMode.getName() + "成功！交易金额为" + amount + "元，交易后可用余额为" + afterBigDecimal + "元。";
                    break;
                case 6:
                case 8:
                    remark = tradeMode.getName() + "成功！交易金额为" + amount + "元，交易后已用授信额度为" + afterBigDecimal + "元。";
                    break;
                case 9:
                case 10:
                case 11:
                case 15:
                case 18:
                    remark = tradeMode.getName() + "成功！交易金额为" + amount + "元，交易后已用平台授信额度为" + afterBigDecimal + "元。";
                    break;

            }
            saveReqVO.setRemark(remark);
            saveReqVO.setOrderId(orderId == null ? "" : orderId.toString());
            saveReqVO.setRefundId(refundId == null ? "" : refundId.toString());
            saveReqVO.setTradeType(tradeMode.getType());
            saveReqVO.setDistributorId(store.getAgencyId());
            return storeTradeLogService.createStoreTradeLog(saveReqVO);
        }
    }

    @Override
    public List<StoreDO> getStoreListByDistributor(Long distributorId) {
//        CommonResult<DistributorRespDTO> distributorRes = otaDistributorApi.getDistributorById(distributorId);
//        Asserts.isTrue(distributorRes.isSuccess(), distributorRes.getMsg());
//        DistributorRespDTO distributorRespDTO = distributorRes.getCheckedData();
//        TenantContextHolder.setIgnore(true);
//        List<StoreDO> storeList = storeMapper.selectListByStatus(distributorRespDTO.getAccountTenantId(), UseStatusEnum.ENABLE.getStatus());
//        TenantContextHolder.setIgnore(false);
//        return storeList;
        //TODO: 后续完善
        return null;
    }

    @Override
    public Long changePlatCredit(StorePlatCreditSaveReqVO reqVO) {
//        Long tenantId = TenantContextHolder.getTenantId();
//        String key = "[store-in]" + reqVO.getStoreId();
//        RLock lock = redissonClient.getLock(key);
//        lock.lock();
//        try {
//            CommonResult<DistributorRespDTO> distributorRes = otaDistributorApi.getDistributorById(reqVO.getDistributorId());
//            Asserts.isTrue(distributorRes.isSuccess(), distributorRes.getMsg());
//            DistributorRespDTO distributorRespDTO = distributorRes.getCheckedData();
//            TenantContextHolder.setTenantId(distributorRespDTO.getAccountTenantId());
//
//            //增加
//            StoreCardDO storeCard = storeCardService.getStoreCard(reqVO.getStoreId());
//            Asserts.isTrue(null != storeCard, "门店资金卡不存在");
//            Asserts.isTrue(storeCard.getCreditType() == 1 || storeCard.getCreditType() == 2, "门店未启用授信");
//            BigDecimal beforeBigDecimal = Optional.ofNullable(storeCard.getCredit()).orElse(BigDecimal.ZERO);
//            BigDecimal afterBigDecimal;
//            if (reqVO.getOperateMode() == 1) {
//                //增加
//                List<StoreCardDO> cardDOList = storeCardService.selectListByAgency();
//                BigDecimal dbCredit = cardDOList.stream()
//                        .map(StoreCardDO::getCredit).filter(Objects::nonNull)
//                        .reduce(BigDecimal::add)
//                        .orElse(BigDecimal.ZERO);
//
//                Asserts.isTrue(distributorRespDTO.getPayCredit().compareTo(dbCredit.add(reqVO.getAmount())) >= 0, "该旅行社门店授信额度大于旅行社授信总额度");
//                afterBigDecimal = beforeBigDecimal.add(reqVO.getAmount());
//            } else {
//                // 减少
//                afterBigDecimal = beforeBigDecimal.subtract(reqVO.getAmount());
//                if (afterBigDecimal.compareTo(BigDecimal.ZERO) < 0) {
//                    throw exception(STORE_REQUEST_CREDIT);
//                }
//            }
//            StoreCardSaveReqVO saveReqVO = new StoreCardSaveReqVO();
//            saveReqVO.setId(storeCard.getId());
//            saveReqVO.setStoreId(storeCard.getStoreId());
//            saveReqVO.setCredit(afterBigDecimal);
//            storeCardService.updateStoreCard(saveReqVO);
//            //旅行社端记录
//            StoreCreditLogSaveReqVO storeCreditLogSaveReqVO = new StoreCreditLogSaveReqVO();
//            storeCreditLogSaveReqVO.setStoreId(storeCard.getStoreId());
//            storeCreditLogSaveReqVO.setBeforeCredit(beforeBigDecimal);
//            storeCreditLogSaveReqVO.setAfterCredit(afterBigDecimal);
//            storeCreditLogSaveReqVO.setCreditAmount(reqVO.getAmount());
//            int mode =  reqVO.getOperateMode();
//            storeCreditLogSaveReqVO.setCreditMode(mode);
//            String remark;
//            if (mode == 1) {
//                remark = "平台操作提额，额度提升" + reqVO.getAmount().setScale(2) + "元，提升后授信额度为" + afterBigDecimal.setScale(2);
//            } else {
//                remark = "平台操作降额，额度降低" + reqVO.getAmount().setScale(2) + "元，降低后授信额度为" + afterBigDecimal.setScale(2);
//            }
//            storeCreditLogSaveReqVO.setRemark(remark);
//            storeCreditLogService.createStoreCreditLog(storeCreditLogSaveReqVO);
//
//            // 平台授信额度记录
//            TenantContextHolder.setTenantId(tenantId);
//            StorePlatCreditLogSaveReqVO logSaveReqVO = new StorePlatCreditLogSaveReqVO();
//            logSaveReqVO.setStoreId(storeCard.getStoreId());
//            logSaveReqVO.setBeforeCredit(beforeBigDecimal);
//            logSaveReqVO.setAfterCredit(afterBigDecimal);
//            logSaveReqVO.setCreditAmount(reqVO.getAmount());
//            logSaveReqVO.setDistributorId(reqVO.getDistributorId());
//
//            mode = reqVO.getOperateMode();
//            logSaveReqVO.setCreditMode(mode);
//            if (mode == 1) {
//                remark = "额度提升" + reqVO.getAmount().setScale(2) + "元，提升后授信额度为" + afterBigDecimal.setScale(2);
//            } else {
//                remark = "额度降低" + reqVO.getAmount().setScale(2) + "元，降低后授信额度为" + afterBigDecimal.setScale(2);
//            }
//            logSaveReqVO.setRemark(remark);
//            return platCreditLogService.createStorePlatCreditLog(logSaveReqVO);
//
//        } finally {
//            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
//                lock.unlock();
//            }
//        }
        //TODO: 待完善
        return null;
    }

    @Override
    public Long updateStoreCardWithPlat(StoreCardDO storeCardDO , StoreAuditDO storeAudit, TradeModeEnum tradeMode, Long userId){
        Asserts.isTrue(storeAudit.getDistributorId()!=null,"旅行社ID不能为空");
        DistributorRechargeReqDTO reqDTO = new DistributorRechargeReqDTO();
        reqDTO.setAccountId(storeAudit.getDistributorId().toString());
        reqDTO.setAccountType(0);
        reqDTO.setStoreId(storeAudit.getStoreId());
        if(tradeMode == TradeModeEnum.BALANCE_ADMIN_RECHARGE_1 || tradeMode == TradeModeEnum.BALANCE_ADMIN_RECHARGE_2){
            if(ObjectUtil.notEqual(storeCardDO.getBalanceType(), UseStatusEnum.ENABLE.getStatus())) {
                throw exception(STORE_DISABLED_BALANCE);
            }
            reqDTO.setRechargeType(DistributorTradeTypeEnum.BALANCE_RECHARGE.getType());
            reqDTO.setTradeType(DistributorTradeTypeEnum.BALANCE_DISTRIBUTE_STORE.getType());
        }else if(tradeMode == TradeModeEnum.QUOTA_1 || tradeMode == TradeModeEnum.QUOTA_2){
            if(ObjectUtil.notEqual(storeCardDO.getCreditType(), UseStatusEnum.ENABLE.getStatus())) {
                throw exception(STORE_DISABLED_CREDIT);
            }
            reqDTO.setRechargeType(DistributorTradeTypeEnum.CREDIT_RECHARGE.getType());
            reqDTO.setTradeType(DistributorTradeTypeEnum.CREDIT_DISTRIBUTE_STORE.getType());
        }
        reqDTO.setRechargeDistributeType(storeAudit.getRechargeDistributeType());
        reqDTO.setAmount(storeAudit.getAmount());
        reqDTO.setOrderId(storeAudit.getId().toString());
        if(tradeMode == TradeModeEnum.BALANCE_ADMIN_RECHARGE_1 || tradeMode == TradeModeEnum.QUOTA_1){
            reqDTO.setMode(1);
        }else if(tradeMode == TradeModeEnum.BALANCE_ADMIN_RECHARGE_2 || tradeMode == TradeModeEnum.QUOTA_2){
            reqDTO.setMode(2);
        }

        DistributorRechargeRespDTO checkedData = otaDistributorApi.tradeRecharge(reqDTO).getCheckedData();
        return checkedData.getTradeId();
    }

    @Override
    @TenantIgnore
    public void updateStoreProductStatus(StoreProductReqDTO reqDTO) {
        List<StoreDO> storeList = storeMapper.selectByDistributorId(reqDTO.getDistributorId());
        for (StoreDO storeDO : storeList) {
            List<StoreProductDO> storeProductList = storeProductMapper.selectList(new LambdaQueryWrapperX<StoreProductDO>()
                    .eqIfPresent(StoreProductDO::getStoreId, storeDO.getId()).eq(StoreProductDO::getDeleted, 0)
                    .inIfPresent(StoreProductDO::getProductId, reqDTO.getIdList())
            );
            // 筛选不存在的productId
            List<Long> collect = storeProductList.stream().map(StoreProductDO::getProductId).collect(Collectors.toList());
            List<Long> ids = BeanUtil.copyToList(reqDTO.getIdList(), Long.class);
            ids.removeAll(collect);
            if (ids.isEmpty()) {
                storeMapper.updateStoreProductIsUse(storeDO.getId(), reqDTO.getIsUse(), reqDTO.getIdList());
            } else {
                List<StoreProductDO> insertList = new ArrayList<>();
                reqDTO.getIdList().forEach(id -> {
                    StoreProductDO storeProductDO = new StoreProductDO();
                    storeProductDO.setId(IdWorker.getId(storeProductDO));
                    storeProductDO.setStoreId(storeDO.getId());
                    storeProductDO.setProductId(id);
                    storeProductDO.setIsUse(Long.valueOf(reqDTO.getIsUse()));
                    storeProductDO.setTenantId(storeDO.getTenantId());
                    insertList.add(storeProductDO);
                });
                storeProductMapper.insertBatch(insertList);
            }
        }

        List<StoreMachineDO> storeMachineList = storeMachineMapper.selectByDistributorId(reqDTO.getDistributorId());
        for (StoreMachineDO storeMachineDO : storeMachineList) {
            List<StoreMachineProductDO> machineProductList = storeMachineProductMapper.selectList(
                    new LambdaQueryWrapperX<StoreMachineProductDO>().eq(StoreMachineProductDO::getDeleted, 0)
                    .eqIfPresent(StoreMachineProductDO::getStoreId, storeMachineDO.getStoreId())
                    .eqIfPresent(StoreMachineProductDO::getMachineId, storeMachineDO.getMachineId())
                    .inIfPresent(StoreMachineProductDO::getProductId, reqDTO.getIdList())
            );
            // 筛选不存在的productId
            List<Long> collect = machineProductList.stream().map(StoreMachineProductDO::getProductId).collect(Collectors.toList());
            reqDTO.getIdList().removeAll(collect);
            if (!reqDTO.getIdList().isEmpty()) {
                List<StoreMachineProductDO> insertList = new ArrayList<>();
                reqDTO.getIdList().forEach(id -> {
                    StoreMachineProductDO storeMachineProductDO = new StoreMachineProductDO();
                    storeMachineProductDO.setId(IdWorker.getId(storeMachineProductDO));
                    storeMachineProductDO.setStoreId(storeMachineDO.getStoreId());
                    storeMachineProductDO.setMachineId(storeMachineDO.getId());
                    storeMachineProductDO.setProductId(id);
                    storeMachineProductDO.setTenantId(storeMachineDO.getTenantId());
                    insertList.add(storeMachineProductDO);
                });
                storeMachineProductMapper.insertBatch(insertList);
            }
        }
    }

    @Override
    public StoreBalanceRespVO queryStoreCreditAndBalance(Integer whetherShow) {
        long loginUserId = getLoginUserId();
        StoreCardRespDTO store = this.getStoreByUserId(loginUserId);
        StoreBalanceRespVO respVO = StoreConvert.INSTANCE.convertStoreType(store);
        DistributorRespDTO  distributor = otaDistributorApi.getDistributorByLoginUserId(loginUserId);
        if (Objects.equals(store.getBalanceType(), StoreBalanceTypeEnum.SHARE.getType())) {
            //当门店授信和预付款为共享时是否显示旅行社的余额（1-是，0-否）
            if (whetherShow!=null && whetherShow ==1){
                respVO.setPaymentBalance(distributor.getBalance());
            }
        }else if (Objects.equals(store.getBalanceType(), StoreBalanceTypeEnum.FIXED.getType())){
            respVO.setPaymentBalance(store.getBalance());
        }
        if (Objects.equals(store.getCreditType(), StoreBalanceTypeEnum.SHARE.getType())) {
            //当门店授信和预付款为共享时是否显示旅行社的余额（1-是，0-否）
            if (whetherShow!=null && whetherShow ==1){
                respVO.setCreditBalance(distributor.getPayCredit().subtract(distributor.getSurplus()));
            }
        }else if (Objects.equals(store.getCreditType(), StoreBalanceTypeEnum.FIXED.getType())){
            respVO.setCreditBalance(store.getCredit().subtract(store.getSurplus()));
        }
        return respVO;
    }

    @Override
    public List<StoreDO> getStoreList(StoreSimpleReqVO reqVO) {
        return storeMapper.selectList(reqVO);
    }
}
