package com.m2pool.lease.service.impl;

import com.baomidou.dynamic.datasource.annotation.DSTransactional;
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.DateUtils;
import com.m2pool.common.core.utils.StringUtils;
import com.m2pool.common.security.utils.SecurityUtils;
import com.m2pool.lease.dto.*;
import com.m2pool.lease.entity.*;
import com.m2pool.lease.exception.PaymentException;
import com.m2pool.lease.mapper.*;
import com.m2pool.lease.mq.message.RabbitmqPayRechargeMessage;
import com.m2pool.lease.mq.message.RabbitmqPayWithdrawMessage;
import com.m2pool.lease.service.LeaseUserService;
import com.m2pool.lease.utils.*;
import com.m2pool.lease.vo.*;
import org.apache.commons.io.FileUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.*;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

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

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author yyb
 * @since 2025-07-23
 */
@Service
public class LeaseUserServiceImpl extends ServiceImpl<LeaseUserMapper, LeaseUser> implements LeaseUserService {

    @Resource
    private LeaseUserMapper leaseUserMapper;

    @Resource
    private LeaseUserWalletDataMapper leaseUserWalletDataMapper;

    @Resource
    private LeaseAutoAddressMapper leaseAutoAddressMapper;

    @Resource
    private RabbitTemplate  rabbitTemplate;

    @Resource
    private LeasePayWithdrawMessageMapper leasePayWithdrawMessageMapper;

    @Resource
    private LeasePayRechargeMessageMapper leasePayRechargeMessageMapper;


    @Resource
    private LeasePayRecordMessageMapper leasePayRecordMessageMapper;

    @Resource
    private LeaseShopConfigMapper leaseShopConfigMapper;

    @Resource
    private LeaseShopMapper leaseShopMapper;



    @Value("${client.download.client.linux}")
    private String downloadClientLinux;

    @Value("${client.download.client.windows}")
    private String downloadClientWindows;

    @Value("${client.download.version}")
    private String version;





    @Override
    public Result<UserDto> login(UserURDVo userURDVo) {
        LeaseUser leaseUser = leaseUserMapper.selectOne(new LambdaQueryWrapper<LeaseUser>()
                .eq(LeaseUser::getUserId, userURDVo.getUserId()));
        if (leaseUser != null){
            return Result.success(UserDto.builder()
                    .id(leaseUser.getId())
                    .userId(leaseUser.getUserId())
                    .password(leaseUser.getPassword())
                    .build());
        }
        LeaseUser build = LeaseUser.builder().password(userURDVo.getPassword()).userId(userURDVo.getUserId()).build();
        int insert = leaseUserMapper.insert(build);

        if (insert > 0){
            return Result.success(UserDto.builder()
                    .id(build.getId())
                    .userId(build.getUserId())
                    .password(build.getPassword())
                    .build());
        }else {
           return Result.fail("登录失败");
        }
    }

    @Override
    @Transactional
    public Result<UserWalletDataDto> bindWallet(ChainAndCoinVo chainAndCoinVo) {
        //同一用户同一个链只会存在一个钱包
        List<UserWalletDataDto> userWalletDataDtoList = leaseUserWalletDataMapper.getWalletInfoByChain(chainAndCoinVo.getChain(), SecurityUtils.getUsername());
        UserWalletDataDto result;
        //如果某个链 未查找到钱包地址 去新绑定一个
        if (userWalletDataDtoList.isEmpty()){
            LeaseAutoAddress bindAddress = getBindAddress(chainAndCoinVo.getChain(), chainAndCoinVo.getCoin());
            if (bindAddress != null){
                        String address = bindAddress.getAddress();
                        String qrcode = QrCodeUtils.creatRrCode(bindAddress.getAddress(), 200, 200);
                        String username = SecurityUtils.getUsername();
                        String queueId = UuidGeneratorUtil.generateUuidWithoutHyphen();
                result = UserWalletDataDto.builder()
                                .queueId(queueId)
                                .fromAddress(address)
                                .fromChain(chainAndCoinVo.getChain())
                                .fromSymbol(chainAndCoinVo.getCoin())
                                .balance(BigDecimal.ZERO)
                                .userId(username)
                                .qrcode(qrcode)
                                .id(bindAddress.getId())
                                .build();
                leaseUserWalletDataMapper.insert(LeaseUserWalletData.builder()
                        .queueId(queueId)
                        .fromChain(chainAndCoinVo.getChain())
                        .fromAddress(address)
                        .fromSymbol(chainAndCoinVo.getCoin())
                        .qrcode(qrcode)
                        .userId( username)
                        .balance(BigDecimal.ZERO)
                        .build());
                bindAddress.setStatus(1);
                leaseAutoAddressMapper.updateById(bindAddress);
                //监听钱包
                sendMessage(result);
            }else{
                return Result.fail("没有可用的地址,请联系管理员生成可用的钱包地址");
            }
        }else{
            for (UserWalletDataDto userWalletDataDto : userWalletDataDtoList) {
                if (userWalletDataDto.getFromSymbol().equals(chainAndCoinVo.getCoin())){
                    //开发环境
                    //sendMessage(UserWalletDataDto.builder()
                    //        .queueId(userWalletDataDto.getQueueId())
                    //        .fromAddress(userWalletDataDto.getFromAddress())
                    //        .fromChain(chainAndCoinVo.getChain())
                    //        .fromSymbol(chainAndCoinVo.getCoin())
                    //        .balance(BigDecimal.ZERO)
                    //        .userId(userWalletDataDto.getUserId())
                    //        .qrcode(userWalletDataDto.getQrcode())
                    //        .build());
                  return  Result.success(userWalletDataDto);
                }
            }
            UserWalletDataDto userWalletDataDto = userWalletDataDtoList.get(0);
            result = UserWalletDataDto.builder()
                    .queueId(userWalletDataDto.getQueueId())
                    .fromAddress(userWalletDataDto.getFromAddress())
                    .fromChain(chainAndCoinVo.getChain())
                    .fromSymbol(chainAndCoinVo.getCoin())
                    .balance(BigDecimal.ZERO)
                    .userId(userWalletDataDto.getUserId())
                    .qrcode(userWalletDataDto.getQrcode())
                    .build();

            LeaseUserWalletData build = LeaseUserWalletData.builder()
                    .queueId(userWalletDataDto.getQueueId())
                    .fromChain(userWalletDataDto.getFromChain())
                    .fromAddress(userWalletDataDto.getFromAddress())
                    .fromSymbol(chainAndCoinVo.getCoin())
                    .qrcode(userWalletDataDto.getQrcode())
                    .userId(userWalletDataDto.getUserId())
                    .balance(BigDecimal.ZERO)
                    .build();
            //链钱包存在 但是新增币种
            leaseUserWalletDataMapper.insert(build);
        }

        return Result.success(result);
    }


    @Override
    @Transactional
    public Result<List<UserWalletDataDto>> getWalletInfo() {
        List<UserWalletDataDto> userWalletDataDto = leaseUserWalletDataMapper.selectByUserId(SecurityUtils.getUsername());
        //获取手续费
        for (UserWalletDataDto walletDataDto : userWalletDataDto) {
            BigDecimal chargeByChainAndCoin = getChargeByChainAndCoin(walletDataDto.getFromChain(), walletDataDto.getFromSymbol());
            walletDataDto.setCharge(chargeByChainAndCoin);
        }

        if (!userWalletDataDto.isEmpty()){
            List<UserWalletDataDto> collect = userWalletDataDto.stream().peek(item -> item.setBalance(item.getBalance().subtract(item.getBlockedBalance()))).collect(Collectors.toList());
            return Result.success(collect);
        }
        return Result.fail("未绑定钱包");
    }

    /**
     * 检查地址是否半年没有操作（支付，充值，提现）  这个方法可以改成监测 钱包（提现和充值都会修改钱包） 的最近修改时间 + 支付操作
     * @param fromAddress
     * @return
     */
    public boolean checkAddress(String fromAddress){
        //支付操作
        boolean b = leasePayRecordMessageMapper.checkPayOperator(fromAddress);
        //提现操作
        boolean b1 = leasePayWithdrawMessageMapper.checkWithdrawOperator(fromAddress);
        //充值操作
        boolean b2 = leasePayRechargeMessageMapper.checkRechargeOperator(fromAddress);
        if (b || b1 || b2){
            return true;
        }
        return false;
    }

    /**
     * 获取一个未使用的地址
     * @return
     */
    public LeaseAutoAddress getBindAddress(String chain, String coin){
        LeaseAutoAddress leaseAutoAddress = leaseAutoAddressMapper.selectOne(new LambdaQueryWrapper<LeaseAutoAddress>()
                .eq(LeaseAutoAddress::getStatus, 0)
                .eq(LeaseAutoAddress::getFromChain, chain)
                .last("limit 1"));
        return leaseAutoAddress;
    }

    /**
     * 发送mq 消息，从而启动钱包监听
     */
   public void sendMessage(UserWalletDataDto userWalletDataDto){
       try {
           System.out.println("发送mq消息");
           long l = System.currentTimeMillis()/1000;
           RabbitmqPayRechargeMessage build = RabbitmqPayRechargeMessage.builder()
                   .queue_id(userWalletDataDto.getQueueId())
                   .address(userWalletDataDto.getFromAddress())
                   .chain(userWalletDataDto.getFromChain())
                   .symbol(userWalletDataDto.getFromSymbol())
                   .timestamp(l)
                   .sign(HashUtils.sha256(l))
                   .build();
           rabbitTemplate.convertAndSend(PAY_RECHARGE_QUEUE,build);
       }catch (Exception e){
           throw new PaymentException("获取钱包信息失败,请刷新重试");
       }
   }


    @Override
    @DSTransactional
    public Result<String> withdrawBalance(BalanceVo balanceVo) {
        String username = SecurityUtils.getUsername();
        UserWalletDataDto userWalletDataDto = leaseUserWalletDataMapper.
                getWalletInfoByAddress(balanceVo.getFromAddress(),balanceVo.getToSymbol(),username);
        if (balanceVo.getAmount().compareTo(BigDecimal.valueOf(2)) < 0){
            return Result.fail("提现失败:提现金额不能小于 2 USDT");
        }

        if (StringUtils.isNull(userWalletDataDto) || StringUtils.isEmpty(userWalletDataDto.getFromAddress())){
            return Result.fail("未查询到需要提现的钱包地址");
        }
        //校验地址
        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("提现收款地址格式不正确");
        }

        //获取未冻结余额
        BigDecimal noBlockedBalance = userWalletDataDto.getBalance().subtract(userWalletDataDto.getBlockedBalance());

        //校验余额是否足够
        if (noBlockedBalance.compareTo(balanceVo.getAmount()) < 0){
            return Result.fail("提现失败:当前未冻结余额:"+noBlockedBalance+"USDT,需提现金额："+balanceVo.getAmount()+"USDT");
        }

        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)
                        .toChain(balanceVo.getToChain())
                        .toSymbol(balanceVo.getToSymbol())
                        .fromChain(userWalletDataDto.getFromChain())
                        .fromSymbol(userWalletDataDto.getFromSymbol())
                        .fromAddress(userWalletDataDto.getFromAddress())
                        .serviceCharge(serviceCharge)
                        .toAddress(balanceVo.getToAddress())
                        .amount(balanceVo.getAmount())
                .build());

        LeaseUserWalletData build = LeaseUserWalletData.builder()
                .id(userWalletDataDto.getId())
                .blockedBalance(userWalletDataDto.getBlockedBalance().add(balanceVo.getAmount()))
                .build();
        //toAddress 为空，或则与这次请求的钱包地址不同，修改表中toAddress 的值为本次请求参数的钱包地址
        if (userWalletDataDto.getToAddress().isEmpty() || !userWalletDataDto.getToAddress().equals(balanceVo.getToAddress())){
            build.setToAddress(balanceVo.getToAddress());
            build.setToChain(balanceVo.getToChain());
            build.setToSymbol(balanceVo.getToSymbol());
        }
        //修改钱包冻结余额 乐观锁
        int i = leaseUserWalletDataMapper.update(build, new LambdaUpdateWrapper<LeaseUserWalletData>()
                .eq(LeaseUserWalletData::getBlockedBalance, userWalletDataDto.getBlockedBalance()));
        if (insert > 0 && i > 0){
            //发送mq消息到队列
            RabbitmqPayWithdrawMessage message = RabbitmqPayWithdrawMessage.builder()
                    .queue_id(queueId)
                    .from_address(userWalletDataDto.getFromAddress())
                    .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);
                System.out.println("发送提现消息成功"+queueId);
                return Result.success("提现申请成功");
            } catch (Exception e) {
                throw new PaymentException(("提现失败,失败原因"+e.getMessage()));
            }
        }
        throw new PaymentException("提现失败,冻结金额已变化,请重新提现！");
    }

    @Override
    public PageResult<PayWithdrawMessageDto> balanceWithdrawList(BalancePageVo balancePageVo) {

        String userEmail = SecurityUtils.getUsername();
        System.out.println("用户"+userEmail+"提现列表");
        List<LeaseUserWalletData> walletList = leaseUserWalletDataMapper.selectList(new LambdaQueryWrapper<LeaseUserWalletData>()
                .eq(LeaseUserWalletData::getUserId,userEmail));
        PageHelper.startPage(balancePageVo.getPageNum(), balancePageVo.getPageSize());
        List<PayWithdrawMessageDto> payWithdrawMessageDtos = leasePayWithdrawMessageMapper
                .balanceWithdrawList(
                        walletList,
                        balancePageVo.getStatus());
        PageInfo<PayWithdrawMessageDto> pageInfo = new PageInfo<>(payWithdrawMessageDtos);
        System.out.println(userEmail + "用户提现" + payWithdrawMessageDtos);
        PageResult<PayWithdrawMessageDto> success = PageResult.success(payWithdrawMessageDtos);
        success.setTotal(pageInfo.getTotal());
        success.setTotalPage(pageInfo.getPages());
        PageHelper.clearPage();
        return success;
    }

    @Override
    public PageResult<PayRechargeMessageDto> balanceRechargeList(BalancePageVo balancePageVo) {

        List<LeaseUserWalletData> walletList = leaseUserWalletDataMapper.selectList(new LambdaQueryWrapper<LeaseUserWalletData>()
                .eq(LeaseUserWalletData::getUserId, SecurityUtils.getUsername()));
        PageHelper.startPage(balancePageVo.getPageNum(), balancePageVo.getPageSize());
        List<PayRechargeMessageDto> payWithdrawMessageDtos = leasePayRechargeMessageMapper.balanceRechargeList(walletList,balancePageVo.getStatus());
        PageInfo<PayRechargeMessageDto> pageInfo = new PageInfo<>(payWithdrawMessageDtos);
        PageResult<PayRechargeMessageDto> success = PageResult.success(payWithdrawMessageDtos);
        success.setTotal(pageInfo.getTotal());
        success.setTotalPage(pageInfo.getPages());
        PageHelper.clearPage();
        return success;
    }

    @Override
    public PageResult<PayRecordMessageDto> balancePayList(BalancePageVo balancePageVo) {
       //获取店铺信息
        LeaseShop leaseShop = leaseShopMapper.selectOne(new LambdaQueryWrapper<LeaseShop>().eq(LeaseShop::getUserEmail, SecurityUtils.getUsername()));
        if (leaseShop == null){
            return PageResult.fail(null,"查看交易信息失败");
        }
        //获取卖家的自定义钱包地址
        List<LeaseShopConfig> leaseShopConfigs = leaseShopConfigMapper.selectList(new LambdaQueryWrapper<LeaseShopConfig>()
                .eq(LeaseShopConfig::getShopId, leaseShop.getId()));
        if(leaseShopConfigs.isEmpty()){
            return PageResult.fail(null,"未绑定钱包,不存在交易流水");
        }
        PageHelper.startPage(balancePageVo.getPageNum(), balancePageVo.getPageSize());
        List<PayRecordMessageDto> payRecordMessageDtos = leasePayRecordMessageMapper.balancePayList(leaseShopConfigs,balancePageVo.getStatus());
        PageInfo<PayRecordMessageDto> pageInfo = new PageInfo<>(payRecordMessageDtos);
        PageResult<PayRecordMessageDto> success = PageResult.success(payRecordMessageDtos);
        success.setTotal(pageInfo.getTotal());
        success.setTotalPage(pageInfo.getPages());
        PageHelper.clearPage();
        return success;
    }

    @Override
    public PageResult<TransactionRecordDto> transactionRecord(RecordTypePageVo recordTypePageVo) {
        Integer status = recordTypePageVo.getStatus();
        //先查到用户绑定的所有钱包
        List<LeaseUserWalletData> walletList = leaseUserWalletDataMapper.selectList(new LambdaQueryWrapper<LeaseUserWalletData>()
                .eq(LeaseUserWalletData::getUserId, SecurityUtils.getUsername()));
        if (walletList.isEmpty()){
            return PageResult.fail(null,"未绑定钱包,不存在交易流水");
        }
        PageHelper.startPage(recordTypePageVo.getPageNum(), recordTypePageVo.getPageSize());
        List<TransactionRecordDto> transactionRecordDtoList = new ArrayList<>();
        //查询支付记录
        if (status == 0){
            transactionRecordDtoList = leasePayRecordMessageMapper.transactionRecord(walletList);
        }
        //查询提现记录
        if (status == 1){
            transactionRecordDtoList = leasePayWithdrawMessageMapper.transactionRecord(walletList);
        }
        //查询充值记录
        if (status == 2){
            transactionRecordDtoList = leasePayRechargeMessageMapper.transactionRecord(walletList);
        }

        PageInfo<TransactionRecordDto> pageInfo = new PageInfo<>(transactionRecordDtoList);
        PageResult<TransactionRecordDto> success = PageResult.success(transactionRecordDtoList);
        success.setTotal(pageInfo.getTotal());
        success.setTotalPage(pageInfo.getPages());
        PageHelper.clearPage();
        return success;
    }

    @Override
    public Result<List<RecentlyTransactionDto>> getRecentlyTransaction() {
        List<LeaseUserWalletData> walletList = leaseUserWalletDataMapper.selectList(new LambdaQueryWrapper<LeaseUserWalletData>()
                .eq(LeaseUserWalletData::getUserId, SecurityUtils.getUsername()));
        if (!walletList.isEmpty()){
            List<RecentlyTransactionDto> recentlyTransaction = leasePayRecordMessageMapper.getRecentlyTransaction(walletList);
            recentlyTransaction.addAll(leasePayWithdrawMessageMapper.getRecentlyTransaction(walletList)) ;
            recentlyTransaction.addAll(leasePayRechargeMessageMapper.getRecentlyTransaction(walletList));
            // 按 updateTime 倒序排序，并取前五个元素
            recentlyTransaction = recentlyTransaction.stream()
                    .sorted((dto1, dto2) -> dto2.getUpdateTime().compareTo(dto1.getUpdateTime()))
                    .limit(5)
                    .collect(Collectors.toList());
            return Result.success(recentlyTransaction);
        }
        return Result.fail("交易记录为空");
    }


    @Override
    public Result<List<ChargeDto>> getCharge() {
        List<ChargeDto> allChargesAsDtoList = getAllChargesAsDtoList();
        return Result.success(allChargesAsDtoList);
    }

    public String getAuthCode(String userEmail){

        System.out.println("获取下载权限码"+userEmail);
        LeaseShop leaseShop = leaseShopMapper.selectOne(new LambdaQueryWrapper<LeaseShop>()
                .select(LeaseShop::getUserEmail)
                .eq(LeaseShop::getUserEmail, userEmail));

        if (leaseShop == null){
            throw new RuntimeException("下载失败,下载客户端权限,请重新登录并创建店铺");
        }
        // 直接把邮箱作为身份码
        //if (StringUtils.isEmpty(leaseShop.getIdentityCode())) {
        //    leaseShop.setIdentityCode(UuidGeneratorUtil.generateUuidWithoutHyphen());
        //    leaseShopMapper.updateById(leaseShop);
        //}
        return leaseShop.getUserEmail();
    }


    @Override
    public void downloadClient(String userEmail,String type,HttpServletRequest request, HttpServletResponse response) {
        String auth = getAuthCode(userEmail);
        //设置响应头信息
        response.reset();
        response.setCharacterEncoding("utf-8");
        response.setContentType("multipart/form-data");
        //设置压缩包的名字，date为时间戳
        String downloadName = "gpu.zip";
        String agent = request.getHeader("USER-AGENT");
        try {
            //针对IE或者以IE为内核的浏览器：
            if (agent.contains("MSIE") || agent.contains("Trident")) {
                downloadName = URLEncoder.encode(downloadName, "UTF-8");
            } else {
                //非IE浏览器的处理：
                downloadName = new String(downloadName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
            }

            // 创建临时目录
            Path tempDir = Files.createTempDirectory("client-download");


            // 创建auth.txt文件
            Path authFile = tempDir.resolve("auth");
            Files.write(authFile, auth.getBytes(StandardCharsets.UTF_8));

            //读取/home/ubuntu/web/client/linux 或 /home/ubuntu/web/client/windows 下所有文件和 auth文件一起压缩
            Path sourceDir = Paths.get(downloadClientLinux);
            try {
                Files.walk(sourceDir)
                        .filter(path -> !Files.isDirectory(path))
                        .forEach(path -> {
                            try {
                                Path dest = tempDir.resolve(sourceDir.relativize(path));
                                Files.createDirectories(dest.getParent());
                                Files.copy(path, dest);
                            } catch (IOException e) {
                                log.error("复制客户端文件失败", e);
                            }
                        });
            } catch (IOException e) {
                log.error("遍历客户端文件失败", e);
            }

            // 创建新的zip文件
            Path zipFile = Files.createTempFile("client", ".zip");
            try (ZipOutputStream zos = new ZipOutputStream(Files.newOutputStream(zipFile.toFile().toPath()))) {
                // 添加解压后的文件和auth.txt到新zip
                Files.walk(tempDir)
                        .filter(path -> !Files.isDirectory(path))
                        .forEach(path -> {
                            try {
                                // 修改这里，确保文件名编码正确
                                String entryName = tempDir.relativize(path).toString().replace('\\', '/');
                                ZipEntry zipEntry = new ZipEntry(entryName);
                                zos.putNextEntry(zipEntry);
                                Files.copy(path, zos);
                                zos.closeEntry();
                            } catch (IOException e) {
                                log.error("添加文件到zip失败", e);
                            }
                        });
            }

            // 设置响应头
            response.setHeader("Content-Disposition", "attachment;fileName=" + downloadName);
            response.setContentLength((int) Files.size(zipFile));

            // 发送文件
            Files.copy(zipFile, response.getOutputStream());
            response.flushBuffer();

            // 清理临时文件
            Files.walk(tempDir)
                    .sorted(Comparator.reverseOrder())
                    .forEach(path -> {
                        try {
                            Files.deleteIfExists(path);
                        } catch (IOException e) {
                            System.out.println("清理临时文件失败");
                        }
                    });
            Files.deleteIfExists(zipFile);

        } catch (Exception e) {
            log.error("系统异常", e);
            throw new RuntimeException("下载客户端失败", e);
        }

    }



    @Override
    public String getClientVersion() {
        try {
            return readTxtFromDir(downloadClientLinux, version);
        }catch (Exception e){
            return "获取配置信息失败"+e;
        }

    }


    /**
     * 读取ZIP压缩文件中指定txt文件的内容
     * @param filePath 文件目录
     * @param targetTxtName 目标txt文件名（含扩展名，如"config.txt"）
     * @return txt文件内容字符串
     * @throws IOException 文件操作异常
     */
    public String readTxtFromDir(String filePath, String targetTxtName) throws IOException {
       //遍历 zipFilePath 然后找到文件名未targetTxtName（带后缀） 的文件
        File dir = new File(filePath);
        if (!dir.isDirectory()) {
            throw new IllegalArgumentException("提供的路径不是一个目录");
        }

        File[] files = dir.listFiles((dir1, name) -> name.equals(targetTxtName));
        if (files == null || files.length == 0) {
            throw new FileNotFoundException("未找到目标文件: " + targetTxtName);
        }

        return new String(Files.readAllBytes(files[0].toPath()), StandardCharsets.UTF_8);
    }

}
