package com.m2pool.lease.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.m2pool.common.core.utils.StringUtils;
import com.m2pool.common.security.utils.SecurityUtils;
import com.m2pool.lease.controller.LeaseShopController;
import com.m2pool.lease.dto.*;
import com.m2pool.lease.dto.v2.PayWithdrawSellerRecordDto;
import com.m2pool.lease.dto.v2.ShopWalletInfoDto;
import com.m2pool.lease.entity.*;
import com.m2pool.lease.exception.MachineException;
import com.m2pool.lease.exception.PaymentException;
import com.m2pool.lease.mapper.*;
import com.m2pool.lease.mq.message.RabbitmqPayWithdrawMessage;
import com.m2pool.lease.service.LeaseShopConfigService;
import com.m2pool.lease.service.LeaseShopService;
import com.m2pool.lease.utils.HashUtils;
import com.m2pool.lease.utils.QrCodeUtils;
import com.m2pool.lease.utils.UuidGeneratorUtil;
import com.m2pool.lease.utils.WalletRuleCheckUtils;
import com.m2pool.lease.vo.*;
import com.m2pool.lease.vo.v2.ShopWalletInfoVo;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.m2pool.lease.constant.CoinCharge.getChargeByChainAndCoin;
import static com.m2pool.lease.constant.RabbitmqConstant.PAY_WITHDRAW_QUEUE;

/**
 * <p>
 * 店铺表 服务实现类
 * </p>
 *
 * @author yyb
 * @since 2025-08-05
 */
@Service
public class LeaseShopServiceImpl extends ServiceImpl<LeaseShopMapper, LeaseShop> implements LeaseShopService {

    @Resource
    private LeaseShopMapper leaseShopMapper;

    @Resource
    private LeaseShopConfigMapper leaseShopConfigMapper;

    @Resource
    private LeaseOrderItemMapper leaseOrderItemMapper;

    @Resource
    private LeaseShopConfigService leaseShopConfigService;

    @Resource
    private LeaseProductMapper leaseProductMapper;

    @Resource
    private LeaseProductMachineMapper leaseProductMachineMapper;


    @Resource
    private LeaseMachinePriceMapper leaseMachinePriceMapper;

    @Resource
    private LeaseUserMapper leaseUserMapper;

    @Resource
    private LeasePayWithdrawMessageMapper leasePayWithdrawMessageMapper;

    @Resource
    private RabbitTemplate rabbitTemplate;

    @Resource
    private LeaseAutoAddressMapper leaseAutoAddressMapper;

    @Resource
    private LeaseMachineMapper leaseMachineMapper;

    @Resource
    private LeaseMachineConfigMapper leaseMachineConfigMapper;

    @Override
    public Result<String> addShop(ShopVo shopVo) {
        LeaseShop leaseShop1 = leaseShopMapper.selectOne(new LambdaQueryWrapper<LeaseShop>()
                .eq(LeaseShop::getUserEmail, SecurityUtils.getUsername()));

        LeaseShop leaseShop = LeaseShop.builder()
                .userEmail(SecurityUtils.getUsername())
                .name(shopVo.getName())
                .image(shopVo.getImage())
                .description(shopVo.getDescription())
                .state(shopVo.getState())
                .feeRate(shopVo.getFeeRate())
                .build();

        if(leaseShop1 != null){
            if (!leaseShop1.getDel()){
                return Result.fail("当前已存在店铺，请勿重复添加");
            }
            leaseShop.setId(leaseShop1.getId());
            leaseShop.setDel(false);
            boolean b = updateById(leaseShop);
            return b ? Result.success("新增店铺成功") : Result.fail("新增店铺失败");
        }
        boolean save = save(leaseShop);
        return save ? Result.success("新增店铺成功") : Result.fail("新增店铺失败");

    }

    @Override
    public Result<String> updateShop(ShopVo shopVo) {

        if (shopVo.getId() == null || shopVo.getId() == 0){
            return Result.fail("id不能为空或0");
        }

        LeaseShop leaseShop = LeaseShop.builder()
                .id(shopVo.getId())
                .userEmail(SecurityUtils.getUsername())
                .name(shopVo.getName())
                .image(shopVo.getImage())
                .description(shopVo.getDescription())
                .state(shopVo.getState())
                .feeRate(shopVo.getFeeRate())
                .build();
        LeaseShop byId = getById(shopVo.getId());
        if (byId.getDel()){
            return Result.fail("修改失败,店铺已被删除");
        }
        boolean save = updateById(leaseShop);
        if (save) {
            return Result.success("修改店铺成功");
        }
        return Result.fail("修改店铺失败");
    }

    @Override
    public Result<String> closeShop(BaseVo baseVo) {
        LeaseShop leaseShop = getById(baseVo.getId());
        if (leaseShop == null) {
            return Result.fail("店铺不存在");
        }
        //校验是否存在已售出的矿机
        if (leaseProductMachineMapper.checkHasSaleMachineByShopId(baseVo.getId()) >= 1 || leaseMachineMapper.checkHasSaleMachineByShopId(baseVo.getId()) >= 1){
            return Result.fail("关闭店铺失败,店铺存在租约中矿机");
        }


        if (leaseShop.getState() == 1){
            leaseShop.setState(2);
            boolean b = updateById(leaseShop);
            return b ? Result.success("关闭店铺成功") : Result.fail("关闭店铺失败");
        }
        if (leaseShop.getState() == 2){
            leaseShop.setState(1);
            boolean b = updateById(leaseShop);
            return b ? Result.success("开启店铺成功") : Result.fail("开启店铺失败");
        }
        return Result.fail("店铺正在审核中不能开启和关闭店铺");
    }

    @Override
    public Result<ShopDto> getShopByUserEmail() {
        LeaseShop leaseShop = leaseShopMapper.selectOne(new LambdaQueryWrapper<LeaseShop>()
                .eq(LeaseShop::getUserEmail, SecurityUtils.getUsername())
                .eq(LeaseShop::getDel, false));
        if (leaseShop != null){
            return Result.success(ShopDto.builder()
                    .id(leaseShop.getId())
                    .name(leaseShop.getName())
                    .image(leaseShop.getImage())
                    .feeRate(leaseShop.getFeeRate())
                    .description(leaseShop.getDescription())
                    .state(leaseShop.getState())
                    .del(leaseShop.getDel())
                    .build());
        }
        return Result.success(null);
    }

    @Override
    public Result<ShopDto> getShopById(BaseVo baseVo) {
        LeaseShop leaseShop = leaseShopMapper.selectById(baseVo.getId());
        if (leaseShop != null && !leaseShop.getDel()){
            return Result.success(ShopDto.builder()
                    .id(leaseShop.getId())
                    .name(leaseShop.getName())
                    .image(leaseShop.getImage())
                    .description(leaseShop.getDescription())
                    .state(leaseShop.getState())
                    .feeRate(leaseShop.getFeeRate())
                    .del(leaseShop.getDel())
                    .build());
        }
        return Result.fail("未找到商铺");
    }

    @Override
    @Transactional
    public Result<String> deleteShop(BaseVo baseVo) {
        LeaseShop byId = getById(baseVo.getId());
        if (byId.getDel()){
            return Result.fail("删除店铺失败,店铺已删除，请刷新页面");
        }
        updateMachineInfoV1(baseVo.getId());
        updateMachineInfoV2(baseVo.getId());
        boolean b = updateById(LeaseShop.builder().id(baseVo.getId()).del(true).build());
        if (b){
            return Result.success("删除成功");
        }
        return Result.fail("删除失败");
    }


    /**
     * 删除店铺时，将店铺下所有矿机和对应钱包删除  V1版本
     *
     * */
    public void updateMachineInfoV1(Long shopId){
        //校验是否存在已售出的矿机
        if (leaseProductMachineMapper.checkHasSaleMachineByShopId(shopId) >= 1){
            throw new MachineException("删除店铺失败,店铺存在租约中矿机");
        }
        leaseProductMapper.update(LeaseProduct.builder().del(true).build(), new LambdaUpdateWrapper<LeaseProduct>()
                .eq(LeaseProduct::getShopId, shopId));
        leaseProductMachineMapper.update(LeaseProductMachine.builder().del(true).build(), new LambdaUpdateWrapper<LeaseProductMachine>()
                .eq(LeaseProductMachine::getShopId, shopId));
    }

    /**
     * 删除店铺时，将店铺下所有矿机和对应钱包删除 V2版本
     *
     * */
    public void updateMachineInfoV2(Long shopId){
        //校验是否存在已售出的矿机
        if (leaseMachineMapper.checkHasSaleMachineByShopId(shopId) >= 1){
            throw new MachineException("删除店铺失败,店铺存在租约中矿机");
        }
        //校验是否存在余额不为0的钱包
        List<LeaseShopConfig> leaseShopConfigs = leaseShopConfigMapper.selectList(new LambdaQueryWrapper<LeaseShopConfig>()
                .select(LeaseShopConfig::getId,LeaseShopConfig::getBalance)
                .eq(LeaseShopConfig::getShopId, shopId).eq(LeaseShopConfig::getDel, false));
        if (leaseShopConfigs.stream().anyMatch(leaseShopConfig -> leaseShopConfig.getBalance().compareTo(BigDecimal.ZERO) > 0)){
            throw new MachineException("删除店铺失败,店铺存在余额不为0的钱包");
        }
        leaseMachineMapper.update(LeaseMachine.builder().del(true).build(), new LambdaUpdateWrapper<LeaseMachine>()
                .eq(LeaseMachine::getShopId, shopId));

        List<Long> ids = leaseMachineMapper.selectList(new LambdaQueryWrapper<LeaseMachine>()
                .select(LeaseMachine::getId)
                .eq(LeaseMachine::getShopId, shopId))
                .stream().map(LeaseMachine::getId)
                .collect(Collectors.toList());
        leaseMachineConfigMapper.delete(new LambdaQueryWrapper<LeaseMachineConfig>().in(LeaseMachineConfig::getMachineId, ids));

        leaseShopConfigMapper.update(LeaseShopConfig.builder().del(true).build(), new LambdaUpdateWrapper<LeaseShopConfig>()
                .eq(LeaseShopConfig::getShopId, shopId));
    }



    @Override
    public Result<List<ShopNameDto>> getProductListById(BaseVo baseVo) {
        List<LeaseProduct> leaseProducts = leaseProductMapper.selectList(new LambdaQueryWrapper<LeaseProduct>().eq(LeaseProduct::getShopId, baseVo.getId()).eq(LeaseProduct::getDel, false));
        List<ShopNameDto> collect = leaseProducts.stream().map(leaseProduct ->
                ShopNameDto.builder()
                        .id(leaseProduct.getId())
                        .name(leaseProduct.getName()).build()
        ).collect(Collectors.toList());
        return Result.success(collect);
    }

    @Override
    public Result<List<ShopConfigDto>> getShopConfig(BaseVo baseVo) {
        List<LeaseShopConfig> leaseShopConfigs = leaseShopConfigMapper.selectList(new LambdaQueryWrapper<LeaseShopConfig>()
                .eq(LeaseShopConfig::getShopId, baseVo.getId())
                .eq(LeaseShopConfig::getDel, false));
        if (leaseShopConfigs.isEmpty()){
            return Result.fail("店铺暂未设置收款钱包");
        }
        Map<String, List<LeaseShopConfig>> collect = leaseShopConfigs.stream().collect(Collectors.groupingBy(LeaseShopConfig::getChain));
       List<ShopConfigDto> shopConfigDtos = new ArrayList<>();
        collect.forEach((chain, list) -> {
            LeaseShopConfig leaseShopConfig = list.get(0);

            List<ShopConfigDto.CoinDto> coinDtoList = list.stream().map(shopConfig -> {
                ShopConfigDto.CoinDto coinDto = new ShopConfigDto.CoinDto();
                coinDto.setPayCoin(shopConfig.getPayCoin());
                coinDto.setImage(shopConfig.getPayCoinImage());
                return coinDto;
            }).collect(Collectors.toList());

            ShopConfigDto build = ShopConfigDto.builder()
                    .shopId(leaseShopConfig.getShopId())
                    .chain(leaseShopConfig.getChain())
                    .payType(leaseShopConfig.getPayType())
                    .payAddress(leaseShopConfig.getPayAddress())
                    .children(coinDtoList)
                    .build();
            build.setId(leaseShopConfig.getId());
            shopConfigDtos.add( build);

        });

        return Result.success(shopConfigDtos);
    }



    @Override
    public Result<String> addShopConfig(ShopConfigVo shopConfigVo) {
        if (checkSystemctlAddress(shopConfigVo.getPayAddress(), shopConfigVo.getChain())){
            return Result.fail("收款钱包不能使用系统钱包");
        }
        //钱包地址校验
        if (!WalletRuleCheckUtils.checkAddress(shopConfigVo.getChain(),shopConfigVo.getPayAddress())){
            return Result.fail("钱包地址格式错误");
        }
        LeaseShop leaseShop = leaseShopMapper.selectOne(new LambdaQueryWrapper<LeaseShop>()
                .eq(LeaseShop::getUserEmail, SecurityUtils.getUsername()));

        List<String> payCoinsList = new ArrayList<>(Arrays.asList(shopConfigVo.getPayCoin().split(",")));

        LeaseShopConfig configList = leaseShopConfigMapper.selectOne(new LambdaQueryWrapper<LeaseShopConfig>()
                .eq(LeaseShopConfig::getPayAddress, shopConfigVo.getPayAddress())
                .eq(LeaseShopConfig::getPayCoin, shopConfigVo.getPayCoin())
                .eq(LeaseShopConfig::getChain, shopConfigVo.getChain())
                .eq(LeaseShopConfig::getDel, false)
        );
        if (configList != null){
            return  Result.fail("绑定"+shopConfigVo.getPayAddress()+"钱包失败!" + shopConfigVo.getChain()+"链"+ shopConfigVo.getPayCoin()+ "币种钱包,已被绑定");
        }

        //获取币种图标
        List<LeaseShopConfig> shopConfigList = leaseShopConfigMapper.getCoinIconByChainAndCoin(shopConfigVo.getChain(), payCoinsList);

        String payAddress = shopConfigVo.getPayAddress();
        String qrCode = QrCodeUtils.creatRrCode(payAddress, 200, 200);
        for (LeaseShopConfig leaseShopConfig : shopConfigList) {
            leaseShopConfig.setShopId(leaseShop.getId());
            leaseShopConfig.setPayType(shopConfigVo.getPayType());
            leaseShopConfig.setChain(shopConfigVo.getChain());
            leaseShopConfig.setPayAddress(payAddress);
            leaseShopConfig.setQrcode(qrCode);
        }
        boolean b = leaseShopConfigService.saveBatch(shopConfigList);
        if (b){
            return Result.success("添加成功");
        }
        return Result.fail("添加失败");
    }

    @Override
    public Result<String> updateShopConfig(ShopConfigVo shopConfigVo) {
        if (checkSystemctlAddress(shopConfigVo.getPayAddress(), shopConfigVo.getChain())){
            return Result.fail("收款钱包不能使用系统钱包");
        }
        if ( !WalletRuleCheckUtils.checkAddress(shopConfigVo.getChain(),shopConfigVo.getPayAddress())){
            return Result.fail("提现地址格式不符合"+shopConfigVo.getChain()+"节点");
        }
        LeaseShop leaseShop = leaseShopMapper.selectOne(new LambdaQueryWrapper<LeaseShop>().eq(LeaseShop::getUserEmail, SecurityUtils.getUsername()));
        List<String> payCoinsList = new ArrayList<>(Arrays.asList(shopConfigVo.getPayCoin().split(",")));
        String payAddress = shopConfigVo.getPayAddress();
        String qrCode = QrCodeUtils.creatRrCode(payAddress, 200, 200);
        List<LeaseShopConfig> configList = leaseShopConfigMapper.selectList(new LambdaQueryWrapper<LeaseShopConfig>()
                .eq(LeaseShopConfig::getShopId, leaseShop.getId())
                .eq(LeaseShopConfig::getChain, shopConfigVo.getChain())
                .eq(LeaseShopConfig::getDel, false)
        );
        //比较已绑定币种 和 本次修改币种的差异
        List<LeaseShopConfig> insertOrUpdateList = new ArrayList<>();
        List<LeaseShopConfig> deleteList = new ArrayList<>();

        for (LeaseShopConfig leaseShopConfig : configList) {
            if(!payCoinsList.contains(leaseShopConfig.getPayCoin())){
                leaseShopConfig.setDel( true);
                deleteList.add(leaseShopConfig);
            }else if (shopConfigVo.getPayAddress().equalsIgnoreCase(leaseShopConfig.getPayAddress())){
                insertOrUpdateList.add(LeaseShopConfig.builder()
                        .id(leaseShopConfig.getId())
                        .shopId(leaseShop.getId())
                        .payType(shopConfigVo.getPayType())
                        .chain(shopConfigVo.getChain())
                        .qrcode(qrCode)
                        .payCoin(leaseShopConfig.getPayCoin())
                        .payAddress(payAddress)
                        .build());
            }else{
                //如果修改了地址 那么就是新增一个 旧的删除
                insertOrUpdateList.add(LeaseShopConfig.builder()
                        .shopId(leaseShop.getId())
                        .payType(shopConfigVo.getPayType())
                        .chain(shopConfigVo.getChain())
                        .qrcode(qrCode)
                        .payCoin(leaseShopConfig.getPayCoin())
                        .payAddress(payAddress)
                        .build());
                leaseShopConfig.setDel( true);
                deleteList.add(leaseShopConfig);
            }
        }
        List<String> alreadyExistCoinList = configList.stream().map(LeaseShopConfig::getPayCoin).collect(Collectors.toList());
        for (String coin : payCoinsList) {
            //不存在新增
            if (!alreadyExistCoinList.contains(coin)){
                insertOrUpdateList.add(LeaseShopConfig.builder()
                        .shopId(leaseShop.getId())
                        .payCoin(coin)
                        .payType(shopConfigVo.getPayType())
                        .chain(shopConfigVo.getChain())
                        .qrcode(qrCode)
                        .payAddress(payAddress)
                        .build());
            }
        }

        if (!deleteList.isEmpty()){
            boolean delete = leaseShopConfigService.updateBatchById(deleteList);
        }
        List<String> coinList = insertOrUpdateList.stream().map(LeaseShopConfig::getPayCoin).collect(Collectors.toList());
        //获取币种对应的图片
        List<LeaseShopConfig> coinIconByChainAndCoin = leaseShopConfigMapper.getCoinIconByChainAndCoin(shopConfigVo.getChain(), coinList);

        for (LeaseShopConfig leaseShopConfig : insertOrUpdateList) {
            for (LeaseShopConfig configImage : coinIconByChainAndCoin) {
                if (leaseShopConfig.getPayCoin().equals(configImage.getPayCoin())){
                    leaseShopConfig.setPayCoinImage(configImage.getPayCoinImage());
                }
            }

        }

        boolean save = leaseShopConfigService.saveOrUpdateBatch(insertOrUpdateList);
        if (save){
            return Result.success("修改成功");
        }
        return Result.fail("修改失败");
    }

    /**
     * 校验卖家收款钱包是否为本系统钱包
     * @param address
     * @param chain
     * @return
     */
    public boolean checkSystemctlAddress(String address, String chain){
        LeaseAutoAddress leaseAutoAddress = leaseAutoAddressMapper.selectOne(new LambdaQueryWrapper<LeaseAutoAddress>()
                .eq(LeaseAutoAddress::getAddress, address)
                .eq(LeaseAutoAddress::getFromChain, chain));
        if (leaseAutoAddress != null){
            return true;
        }
        return false;
    }

    @Override
    public Result<String> deleteShopConfig(BaseVo baseVo) {
        LeaseShopConfig config = leaseShopConfigMapper.selectById(baseVo.getId());
        Long configNums = leaseShopConfigMapper.selectCount(new LambdaQueryWrapper<LeaseShopConfig>()
                .eq(LeaseShopConfig::getShopId, config.getShopId()).eq(LeaseShopConfig::getDel, false));

        List<Long> ids = leaseProductMachineMapper.getIdsForShopId(config.getShopId());
        Long productNums = leaseProductMapper.selectCount(new LambdaQueryWrapper<LeaseProduct>()
                .eq(LeaseProduct::getShopId, config.getShopId())
                .eq(LeaseProduct::getDel, false));
        if (configNums <= 1 && productNums != 0){
            return Result.fail("删除失败,店铺若存在商品,至少需要一个收款钱包");
        }
        //校验是否能够删除
        Long l = leaseOrderItemMapper.selectCount(new LambdaQueryWrapper<LeaseOrderItem>()
                .eq(LeaseOrderItem::getChain, config.getChain())
                .ne(LeaseOrderItem::getStatus, 0)
        );
        if (l > 0){
            return Result.fail("删除钱包失败,该钱包存在交易中的订单");
        }
        List<LeaseShopConfig> leaseShopConfigs = leaseShopConfigMapper.selectList(new LambdaQueryWrapper<LeaseShopConfig>()
                .eq(LeaseShopConfig::getShopId, config.getShopId())
                .eq(LeaseShopConfig::getChain, config.getChain())
                .eq(LeaseShopConfig::getDel, false));
        List<LeaseShopConfig> collect = leaseShopConfigs.stream().peek(leaseShopConfig -> leaseShopConfig.setDel(true)).collect(Collectors.toList());
        boolean b = leaseShopConfigService.updateBatchById(collect);
        if (b){
            leaseMachinePriceMapper.update(LeaseMachinePrice.builder().del(true).build(),
                    new LambdaQueryWrapper<LeaseMachinePrice>()
                            .eq(LeaseMachinePrice::getChain, config.getChain())
                            .in(LeaseMachinePrice::getMachineId,ids)
            );
            return Result.success("删除成功");
        }
        return Result.fail("删除失败");
    }

    @Override
    public Result<List<ChainListDto>> getChainAndList() {
        //LeaseShop leaseShop = leaseShopMapper.selectOne(new LambdaQueryWrapper<LeaseShop>().eq(LeaseShop::getUserEmail, SecurityUtils.getUsername())
        //        .eq(LeaseShop::getDel, false));
        //获取本系统支持的所有链和币种
        List<CoinFullDto> chainAndList = leaseShopConfigMapper.getChainAndList(null);
        //获取卖家已绑定的币种
        //List<LeaseShopConfig> leaseShopConfigs = leaseShopConfigMapper.selectList(new LambdaQueryWrapper<LeaseShopConfig>()
        //        .eq(LeaseShopConfig::getShopId, leaseShop.getId())
        //);
        //for (CoinFullDto coinFullDto : chainAndList) {
        //    for (LeaseShopConfig leaseShopConfig : leaseShopConfigs) {
        //        if (coinFullDto.getChainValue().equals(leaseShopConfig.getChain()) && coinFullDto.getCoinValue().equals(leaseShopConfig.getPayCoin())){
        //            coinFullDto.setHasBind(1);
        //        }
        //    }
        //}
        return Result.success(buildChainList(chainAndList));
    }


    @Override
    public Result<List<ChainListDto>> getChainAndListForSeller(BaseVo baseVo) {
        //LeaseShop leaseShop = leaseShopMapper.selectById(baseVo.getId());
        if (baseVo.getId() == null){
            return Result.fail("未检测到该店铺");
        }
        List<CoinFullDto> chainAndListForSeller = leaseShopConfigMapper.getChainAndListForSeller(baseVo.getId());
        return Result.success(buildChainList(chainAndListForSeller));
    }


    @Override
    public Result<ChainListDto> getChainAndCoin(BaseVo baseVo) {
        LeaseShopConfig config = leaseShopConfigMapper.selectOne(new LambdaQueryWrapper<LeaseShopConfig>().eq(LeaseShopConfig::getId, baseVo.getId()));
       if (config == null){
           return Result.fail("未检测到该币种");
       }
        //商家链已绑定的币种
        List<LeaseShopConfig> leaseShopConfigs = leaseShopConfigMapper.selectList(new LambdaQueryWrapper<LeaseShopConfig>()
                .eq(LeaseShopConfig::getChain, config.getChain())
                .eq(LeaseShopConfig::getShopId, config.getShopId())
        );
        //获取本系统该链支持的所有币种
        List<CoinFullDto> chainAndList = leaseShopConfigMapper.getChainAndList(config.getChain());
        for (CoinFullDto coinFullDto : chainAndList) {
            for (LeaseShopConfig leaseShopConfig : leaseShopConfigs) {
                if (coinFullDto.getChainValue().equals(leaseShopConfig.getChain()) && coinFullDto.getCoinValue().equals(leaseShopConfig.getPayCoin())){
                    coinFullDto.setHasBind(1);
                }
            }
        }
        ChainListDto chainListDto = buildChainList(chainAndList).get(0);
        chainListDto.setAddress(config.getPayAddress());
        return Result.success(chainListDto);
    }

    private  List<ChainListDto> buildChainList(List<CoinFullDto> chainAndList){
        Map<String, List<CoinFullDto>> chainGroup = chainAndList.stream()
                .collect(Collectors.groupingBy(CoinFullDto::getChainValue));

        List<ChainListDto> result = new ArrayList<>();
        for (Map.Entry<String, List<CoinFullDto>> entry : chainGroup.entrySet()) {
            String chainValue = entry.getKey();
            List<CoinFullDto> group = entry.getValue();
            // 取第一个元素获取链标签
            String chainLabel = group.get(0).getChainLabel();

            List<ChainListDto.CoinListDto> coinList = group.stream()
                    .map(coinFullDto -> {
                        ChainListDto.CoinListDto coinDto = new ChainListDto.CoinListDto();
                        coinDto.setValue(coinFullDto.getCoinValue());
                        coinDto.setLabel(coinFullDto.getCoinLabel());
                        coinDto.setHasBind(coinFullDto.getHasBind());
                        return coinDto;
                    })
                    .collect(Collectors.toList());

            ChainListDto chainListDto = ChainListDto.builder()
                    .value(chainValue)
                    .label(chainLabel)
                    .children(coinList)
                    .build();
            result.add(chainListDto);
        }
        return result;
    }

    @Override
    public Result<List<ShopWalletInfoDto>> getShopConfigV2(BaseVo baseVo) {
        List<ShopWalletInfoDto> list =  leaseShopConfigMapper.getShopWalletInfoList(baseVo.getId());
        for (ShopWalletInfoDto shopWalletInfoDto : list) {
            BigDecimal chargeByChainAndCoin = getChargeByChainAndCoin(shopWalletInfoDto.getChain(), shopWalletInfoDto.getPayCoin());
            shopWalletInfoDto.setServiceCharge(chargeByChainAndCoin);
        }
        return Result.success(list);
    }

    @Override
    public Result<String> withdrawBalanceForSeller(BalanceVo balanceVo) {
        //校验地址
        if (StringUtils.isEmpty(balanceVo.getToAddress()) || StringUtils.isEmpty(balanceVo.getToChain()) || StringUtils.isEmpty(balanceVo.getToSymbol()) ){
            return Result.fail("提现地址,链,币种 不能为空");
        }
        if (!WalletRuleCheckUtils.checkAddress(balanceVo.getToChain(),balanceVo.getToAddress())){
            return Result.fail("提现收款地址格式不正确");
        }
        LeaseShop leaseShop = leaseShopMapper.selectOne(new LambdaQueryWrapper<LeaseShop>()
                        .select(LeaseShop::getId).eq(LeaseShop::getUserEmail, SecurityUtils.getUsername()).eq(LeaseShop::getDel, false));
        ShopWalletInfoDto shopWalletInfo = leaseShopConfigMapper.getShopWalletInfo(leaseShop.getId(), balanceVo.getFromAddress(), balanceVo.getToChain(), balanceVo.getToSymbol());
        if (StringUtils.isNull(shopWalletInfo) || StringUtils.isEmpty(shopWalletInfo.getPayAddress())){
            return Result.fail("提现地址不属于您,请登录正确的账号");
        }
        GoogleInfo googleInfo = leaseUserMapper.getGoogleInfoByEmail(SecurityUtils.getUsername());
        //开发环境
        //if(googleInfo == null || StringUtils.isBlank(googleInfo.getSecret())){
        //    //未绑定定谷歌验证器
        //    return Result.fail("您的账号未开启双重验证,请先开启验证!");
        //}
        //if(!GoogleAuthenticator.checkCode(googleInfo.getSecret(), balanceVo.getCode(), System.currentTimeMillis())){
        //    return Result.fail("谷歌验证码错误");
        //}

        //同一个from只能存在一笔提现中的订单
        Integer recentlyOneData = leasePayWithdrawMessageMapper.getRecentlyOneData(balanceVo.getFromAddress(), balanceVo.getToChain());
        if (recentlyOneData != null && recentlyOneData == 2){
            return Result.fail("提现申请失败,已存在一笔金额正在提现中...");
        }
        BigDecimal serviceCharge = getChargeByChainAndCoin(balanceVo.getToChain(), balanceVo.getToSymbol());
        String queueId = UuidGeneratorUtil.generateUuidWithoutHyphen();
        Long timestamp = System.currentTimeMillis()/1000;
        //验证通过存储提现记录
        int insert = leasePayWithdrawMessageMapper.insert(LeasePayWithdrawMessage.builder()
                .queueId(queueId)
                .shopId(leaseShop.getId())
                .toChain(balanceVo.getToChain())
                .toSymbol(balanceVo.getToSymbol())
                .fromChain(shopWalletInfo.getChain())
                .fromSymbol(shopWalletInfo.getPayCoin())
                .fromAddress(shopWalletInfo.getPayAddress())
                .serviceCharge(serviceCharge)
                .toAddress(balanceVo.getToAddress())
                .amount(balanceVo.getAmount())
                .build());
        LeaseShopConfig build = LeaseShopConfig.builder()
                .id(shopWalletInfo.getId())
                .balance(shopWalletInfo.getBalance().subtract(balanceVo.getAmount()))
                .build();
        int update = leaseShopConfigMapper.update(build,new LambdaUpdateWrapper<LeaseShopConfig>()
                .eq(LeaseShopConfig::getBalance, shopWalletInfo.getBalance()));

        if (insert > 0 && update > 0){
            //发送mq消息到队列
            RabbitmqPayWithdrawMessage message = RabbitmqPayWithdrawMessage.builder()
                    .queue_id(queueId)
                    .from_address(shopWalletInfo.getPayAddress())
                    .to_address(balanceVo.getToAddress())
                    .amount(balanceVo.getAmount().subtract(serviceCharge))
                    .chain(balanceVo.getToChain())
                    .symbol(balanceVo.getToSymbol())
                    .fee(serviceCharge)
                    .timestamp(timestamp)
                    .sign(HashUtils.sha256(timestamp))
                    .build();
            try {
                //发送提现消息
                rabbitTemplate.convertAndSend(PAY_WITHDRAW_QUEUE,message);
                return Result.success("手续费=" + serviceCharge.toString() + ";消息ID=" + queueId,"提现申请成功");
            } catch (Exception e) {
                throw new PaymentException("提现失败,失败原因"+e.getMessage());
            }
        }
        throw new PaymentException("提现失败,余额已变化,请重新提现！");

    }

    @Override
    public Result<String> updateShopConfigV2(ShopWalletInfoVo shopWalletInfoVo) {
        if ( !WalletRuleCheckUtils.checkAddress(shopWalletInfoVo.getChain(),shopWalletInfoVo.getPayAddress())){
            return Result.fail("提现地址格式不符合"+shopWalletInfoVo.getChain()+"节点");
        }
        LeaseShopConfig byId = leaseShopConfigService.getById(shopWalletInfoVo.getId());
        if (byId.getBalance().compareTo(BigDecimal.ZERO) > 0){
            return Result.fail("钱包地址余额不为0,请先提现,否则会造成财产丢失");
        }
        LeaseShopConfig leaseShopConfig = leaseShopConfigMapper.selectOne(new LambdaQueryWrapper<LeaseShopConfig>()
                .eq(LeaseShopConfig::getPayAddress, shopWalletInfoVo.getPayAddress())
                .eq(LeaseShopConfig::getChain, shopWalletInfoVo.getChain())
                .eq(LeaseShopConfig::getPayCoin, byId.getPayCoin())
                .eq(LeaseShopConfig::getDel, false)
        );
        if (leaseShopConfig != null){
            return Result.fail("修改失败,该钱包地址下链和币种已被绑定,请重新输入地址或先解绑后重新绑定");
        }
        boolean b = leaseShopConfigService.updateById(LeaseShopConfig.builder()
                .id(shopWalletInfoVo.getId())
                .payAddress(shopWalletInfoVo.getPayAddress())
                .build());
        if (b){
            return Result.success("修改成功");
        }
        return Result.fail("修改失败");
    }


    @Override
    public PageResult<PayWithdrawSellerRecordDto> balanceWithdrawList(PageVo pageVo) {
        String userEmail = SecurityUtils.getUsername();
        LeaseShop leaseShop = leaseShopMapper.selectOne(new LambdaQueryWrapper<LeaseShop>().eq(LeaseShop::getUserEmail, userEmail));
        PageHelper.startPage(pageVo.getPageNum(), pageVo.getPageSize());
        List<PayWithdrawSellerRecordDto> payWithdrawMessageDtoList = leasePayWithdrawMessageMapper.getSellerWithdrawRecord(leaseShop.getId());
        PageInfo<PayWithdrawSellerRecordDto> pageInfo = new PageInfo<>(payWithdrawMessageDtoList);
        PageResult<PayWithdrawSellerRecordDto> success = PageResult.success(payWithdrawMessageDtoList);
        success.setTotal(pageInfo.getTotal());
        success.setTotalPage(pageInfo.getPages());
        PageHelper.clearPage();
        return success;
    }
}
