package com.bonus.material.archives.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.bonus.common.biz.config.DateTimeHelper;
import com.bonus.common.biz.config.FileCompressor;
import com.bonus.common.biz.domain.FileInfo;
import com.bonus.common.biz.domain.HttpMsg;
import com.bonus.common.biz.domain.TreeBuild;
import com.bonus.common.biz.domain.TreeNode;
import com.bonus.common.biz.enums.HttpCodeEnum;
import com.bonus.common.core.exception.ServiceException;
import com.bonus.common.core.utils.DateUtils;
import com.bonus.common.core.utils.StringUtils;
import com.bonus.common.core.web.domain.AjaxResult;
import com.bonus.common.security.utils.SecurityUtils;
import com.bonus.material.archives.domain.ArchivesDetails;
import com.bonus.material.archives.domain.ArchivesInfo;
import com.bonus.material.archives.domain.ArchivesVo;
import com.bonus.material.archives.domain.ElcSignatureInfo;
import com.bonus.material.archives.mapper.ArchivesMapper;
import com.bonus.material.archives.service.ArchivesService;
import com.bonus.material.basic.domain.BmProject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * 电子档案管理接口实现类
 * @Author ma_sh
 * @create 2024/12/26 9:26
 */
@Service
@Slf4j
public class ArchivesServiceImpl implements ArchivesService {

    // 工程档案等级及档案类型名称
    public static final Integer PROJECT_TYPE_ARCHIVES_LEVEL = 1;
    public static final Long PROJECT_YEAR_ARCHIVES_LEVEL = 2L;
    public static final String PROJECT_TYPE_ARCHIVES_NAME = "工程项目材料";

    @Resource
    private ArchivesMapper archivesMapper;

    /**
     * 上传档案工程信息类型的附件
     *
     * @param fromProjectFileType 上传文件所属工程文件类型(领料单、退料单、业务联系单)
     * @param fileName  文件名称
     * @param filePath  文件地址
     * @param projectId 工程id（表内唯一键值key）
     * @return 结果
     */
    @Override
    public AjaxResult uploadArchivesProjectPdf(String fromProjectFileType, String fileName, String filePath, Integer projectId) {
        Integer leaseFolderNodeId = archivesMapper.selectDetailsNodeIdByDocNameAndInfoValue(fromProjectFileType, PROJECT_YEAR_ARCHIVES_LEVEL.intValue(), projectId);
        if (null == leaseFolderNodeId || 0 == leaseFolderNodeId) {
            return AjaxResult.error("未查询到工程所属档案文件夹信息");
        }
        ArchivesDetails archivesDetails = new ArchivesDetails();
        archivesDetails.setInfoId(Long.valueOf(projectId));
        archivesDetails.setParentId(Long.valueOf(leaseFolderNodeId));
        archivesDetails.setLevel(Long.toString(PROJECT_YEAR_ARCHIVES_LEVEL));
        archivesDetails.setDocName(fileName);
        archivesDetails.setDocType("pdf");
        archivesDetails.setDocUrl(filePath.contains("http") ? filePath : "https://xiyunwangcn.oss-cn-hangzhou.aliyuncs.com/" + filePath);
        archivesDetails.setDelFlag("0");
        archivesDetails.setCreateTime(DateUtils.getNowDate());
        archivesDetails.setCreateBy(SecurityUtils.getLoginUser().getSysUser().getNickName());
        int insertArchivesDetailsResult = archivesMapper.insertDetails(archivesDetails);
        return 0 < insertArchivesDetailsResult ? AjaxResult.success(HttpCodeEnum.SUCCESS.getMsg()) : AjaxResult.error(HttpCodeEnum.FAIL.getMsg());
    }


    /**
     * 工程新增事件--处理档案库对应数据
     *
     * @param projectInfo 新建的工程信息
     */
    @Override
    public AjaxResult projectAddEventCope(BmProject projectInfo) {
        if (Objects.isNull(projectInfo) || Objects.isNull(projectInfo.getProId()) || Objects.isNull(projectInfo.getProName())) {
            log.error("工程新增事件--处理档案库对应数据-工程信息不能为空");
            return AjaxResult.error(HttpCodeEnum.TO_PARAM_NULL.getCode(), HttpCodeEnum.TO_PARAM_NULL.getMsg());
        }
        // 查询工程类型的档案信息
        ArchivesInfo projectTypeNodeInfo = archivesMapper.selectInfoListByNameAndLevel(PROJECT_TYPE_ARCHIVES_NAME,PROJECT_TYPE_ARCHIVES_LEVEL);
        if (Objects.isNull(projectTypeNodeInfo) || Objects.isNull(projectTypeNodeInfo.getInfoId())) {
            log.error("工程新增事件--处理档案库对应数据-工程档案类型信息不存在");
            return AjaxResult.error(HttpCodeEnum.QUERY_DATA_NULL.getCode(), "工程档案类型信息不存在");
        }
        // 获取当前年份
        String currentYear = DateUtils.getCurrentYear();
        ArchivesInfo currentYearArchivesNodeInfo = archivesMapper.selectByName(new ArchivesInfo().setArchivesName(currentYear).setParentId(projectTypeNodeInfo.getInfoId()));
        // 判断当前年份的工程档案节点是否存在
        if (Objects.isNull(currentYearArchivesNodeInfo) || Objects.isNull(currentYearArchivesNodeInfo.getInfoId())) {
            log.error("工程新增事件--处理档案库对应数据-工程档案当前年份节点不存在");
            return AjaxResult.error(HttpCodeEnum.QUERY_DATA_NULL.getCode(), "工程档案当前年份节点不存在");
        }

        ArchivesInfo currentProjectNodeInfo = new ArchivesInfo().setArchivesName(projectInfo.getProName()).setParentId(currentYearArchivesNodeInfo.getInfoId()).setLevel(Long.toString(PROJECT_YEAR_ARCHIVES_LEVEL));
        currentProjectNodeInfo.setArchivesValue(String.valueOf(projectInfo.getProId()));
        currentProjectNodeInfo.setCreateTime(DateUtils.getNowDate());
        currentProjectNodeInfo.setCreateBy(SecurityUtils.getLoginUser().getSysUser().getNickName());
        int insertCurrentProjectNodeResult = archivesMapper.insertInfo(currentProjectNodeInfo);
        //AjaxResult insertNodeInfoResult = this.add(currentProjectNodeInfo);
        if (insertCurrentProjectNodeResult > 0) {
            // 判断新增的工程节点信息是否完善
            if (ObjectUtil.isEmpty(currentProjectNodeInfo) || ObjectUtil.isEmpty(currentProjectNodeInfo.getInfoId())) {
                return AjaxResult.error(HttpCodeEnum.FAIL.getCode(), HttpCodeEnum.FAIL.getMsg());
            }
            // 增加详情节点
            ArchivesDetails details1 = new ArchivesDetails().setInfoId(currentProjectNodeInfo.getInfoId()).setParentId(0L).setLevel("1").setDocName("领料单").setDocType("文件夹");
            ArchivesDetails details2 = new ArchivesDetails().setInfoId(currentProjectNodeInfo.getInfoId()).setParentId(0L).setLevel("1").setDocName("退料单").setDocType("文件夹");
            ArchivesDetails details3 = new ArchivesDetails().setInfoId(currentProjectNodeInfo.getInfoId()).setParentId(0L).setLevel("1").setDocName("业务联系单").setDocType("文件夹");
            List<ArchivesDetails> archivesNodeDetailsList = new ArrayList<>(Arrays.asList(details1, details2, details3));
            ArchivesVo archivesVo = new ArchivesVo();
            archivesVo.setArchivesDetailsList(archivesNodeDetailsList);
            archivesVo.setEnableCheckNameExist(false);
            return this.addDetails(archivesVo);
        } else {
            return AjaxResult.error(HttpCodeEnum.FAIL.getCode(), HttpCodeEnum.FAIL.getMsg());
        }
    }

    /**
     * 获取电子档案分类树
     * @param archiveInfo
     * @return
     */
    @Override
    public AjaxResult getTypeList(ArchivesInfo archiveInfo) {
        List<TreeNode> groupList = new ArrayList<>();
        List<TreeNode> list;
        try {
            list = archivesMapper.getTypeList(archiveInfo);
            if (CollectionUtils.isNotEmpty(list)) {
                // 创建树形结构（数据集合作为参数）
                TreeBuild treeBuild = new TreeBuild(list);
                // 原查询结果转换树形结构
                groupList = treeBuild.buildTree();
            }
        } catch (Exception e) {
            log.error("电子档案分类树-查询失败", e);
        }
        return AjaxResult.success(groupList);
    }

    /**
     * 新增电子档案分类
     * @param archiveInfo
     * @return
     */
    @Override
    public AjaxResult add(ArchivesInfo archiveInfo) {
        // 根据类型名称和上级id查询，同级下名称不能重复
        archiveInfo.setParentId(archiveInfo.getInfoId() != null ? archiveInfo.getInfoId() : 0L);
        ArchivesInfo info =  archivesMapper.selectByName(archiveInfo);
        if (info != null) {
            return AjaxResult.error(HttpCodeEnum.NAME_DUPLICATE.getCode(), HttpCodeEnum.NAME_DUPLICATE.getMsg());
        }
        archiveInfo.setCreateTime(DateUtils.getNowDate());
        archiveInfo.setCreateBy(SecurityUtils.getLoginUser().getSysUser().getNickName());
        archiveInfo.setParentId(archiveInfo.getInfoId() != null ? archiveInfo.getInfoId() : 0L);
        archiveInfo.setLevel((StringUtils.isNotBlank(archiveInfo.getLevel())) ? String.valueOf(Integer.parseInt(archiveInfo.getLevel()) + 1) : "1");
        int result = archivesMapper.insertInfo(archiveInfo);
        if (0 < result) {
            return AjaxResult.success(HttpCodeEnum.SUCCESS.getMsg(), result);
        }
        return AjaxResult.error(HttpCodeEnum.FAIL.getCode(), HttpCodeEnum.FAIL.getMsg());
    }

    /**
     * 修改电子档案分类树
     * @param archiveInfo
     * @return
     */
    @Override
    public AjaxResult edit(ArchivesInfo archiveInfo) {
        // 根据类型名称和上级id查询，同级下名称不能重复
        archiveInfo.setParentId(archiveInfo.getParentId() != null ? archiveInfo.getParentId() : 0L);
        ArchivesInfo info = archivesMapper.selectByName(archiveInfo);
        if (info != null && !archiveInfo.getInfoId().equals(info.getInfoId())) {
            return AjaxResult.error(HttpCodeEnum.NAME_DUPLICATE.getCode(), HttpCodeEnum.NAME_DUPLICATE.getMsg());
        }
        archiveInfo.setUpdateTime(DateUtils.getNowDate());
        archiveInfo.setUpdateBy(SecurityUtils.getLoginUser().getSysUser().getNickName());
        int result = archivesMapper.updateInfo(archiveInfo);
        if (result > 0) {
            return AjaxResult.success(HttpCodeEnum.SUCCESS.getMsg(), result);
        }
        return AjaxResult.error(HttpCodeEnum.FAIL.getCode(), HttpCodeEnum.FAIL.getMsg());
    }

    /**
     * 删除电子档案分类树
     * @param archiveInfo
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult deleteById(ArchivesInfo archiveInfo) {
        // 根据id查询，判断是否有子节点，有则不能删除
        List<ArchivesDetails> detailsList = new ArrayList<>();
        List<ArchivesInfo> list = archivesMapper.getListById(archiveInfo);
        if (CollectionUtil.isEmpty(list)) {
            ArchivesDetails archivesDetails = new ArchivesDetails();
            archivesDetails.setInfoId(archiveInfo.getInfoId());
            detailsList = archivesMapper.selectDetailsList(archivesDetails);
        }
        if (CollectionUtils.isNotEmpty(list) || CollectionUtils.isNotEmpty(detailsList)) {
            return AjaxResult.error(HttpCodeEnum.FAIL.getCode(), "该分类下有子分类，无法删除");
        }
        int result = archivesMapper.deleteInfo(archiveInfo);
        if (result > 0) {
            return AjaxResult.success(HttpCodeEnum.SUCCESS.getMsg(), result);
        }
        return AjaxResult.error(HttpCodeEnum.FAIL.getCode(), HttpCodeEnum.FAIL.getMsg());
    }

    /**
     * 获取电子档案详情信息
     * @param archivesDetails
     * @return
     */
    @Override
    public List<ArchivesDetails> getDetailsList(ArchivesDetails archivesDetails) {
        return archivesMapper.selectDetailsList(archivesDetails);
    }

    /**
     * 获取文件大小
     * @param multipartFile 文件
     * @return MB格式(例如: 18.23)
     */
    @Override
    public String getFileSizeInMb(MultipartFile multipartFile) {
        if (null == multipartFile || multipartFile.isEmpty()) {
            return "0";
        }
        try {
            long fileSizeInBytes = multipartFile.getSize();
            double fileSizeInMb = (double) fileSizeInBytes / (1024 * 1024);
            DecimalFormat df = new DecimalFormat("#.00");
            return df.format(fileSizeInMb);
        } catch (Exception e) {
            return "0";
        }
    }


    /**
     * 新增电子档案右侧类型
     * @param archivesVo
     * @return
     */
    @Override
    public AjaxResult addDetails(ArchivesVo archivesVo) {
        // 根据类型名称和上级id查询，同级下名称不能重复
        int result = 0;
        // 如果只有单条数据
        if (archivesVo.getArchivesDetails() != null) {
            ArchivesDetails archivesDetails = archivesVo.getArchivesDetails();
            if (isNameDuplicate(archivesDetails)) {
                return AjaxResult.error(HttpCodeEnum.NAME_DUPLICATE.getCode(), HttpCodeEnum.NAME_DUPLICATE.getMsg());
            }
            prepareArchivesDetails(archivesDetails);
            archivesDetails.setDocType("文件夹");
            result = archivesMapper.insertDetails(archivesDetails);
            // 如果插入成功，返回成功响应
            if (result > 0) {
                return AjaxResult.success(HttpCodeEnum.SUCCESS.getMsg(), result);
            }
            return AjaxResult.error(HttpCodeEnum.FAIL.getCode(), HttpCodeEnum.FAIL.getMsg());
        }
        // 如果有多条数据
        if (CollectionUtils.isNotEmpty(archivesVo.getArchivesDetailsList())) {
            if (archivesVo.isEnableCheckNameExist()) {
                // 检查是否有重复名称
                for (ArchivesDetails archivesDetails : archivesVo.getArchivesDetailsList()) {
                    if (isNameDuplicate(archivesDetails)) {
                        return AjaxResult.error(HttpCodeEnum.NAME_DUPLICATE.getCode(), HttpCodeEnum.NAME_DUPLICATE.getMsg());
                    }
                }
            }
            // 插入所有不重复的档案详情
            for (ArchivesDetails archivesDetails : archivesVo.getArchivesDetailsList()) {
                prepareArchivesDetails(archivesDetails);
                result += archivesMapper.insertDetails(archivesDetails);
            }
        }
        // 根据插入结果返回响应
        return result > 0
                ? AjaxResult.success(HttpCodeEnum.SUCCESS.getMsg(), result)
                : AjaxResult.error(HttpCodeEnum.FAIL.getCode(), HttpCodeEnum.FAIL.getMsg());
    }

    /**
     * 处理通用逻辑
     * @param archivesDetails
     */
    private void prepareArchivesDetails(ArchivesDetails archivesDetails) {
        archivesDetails.setCreateBy(SecurityUtils.getLoginUser().getSysUser().getNickName());
        archivesDetails.setCreateTime(DateUtils.getNowDate());
        archivesDetails.setParentId(archivesDetails.getDetailsId() != null ? archivesDetails.getDetailsId() : 0L);
    }

    /**
     * 检查档案名称是否重复
     * @param archivesDetails
     * @return
     */
    private boolean isNameDuplicate(ArchivesDetails archivesDetails) {
        archivesDetails.setLevel(StringUtils.isNotBlank(archivesDetails.getLevel())
                ? String.valueOf(Integer.parseInt(archivesDetails.getLevel()) + 1)
                : "1");
        ArchivesDetails info = archivesMapper.selectDetailsByName(archivesDetails);
        return info != null;
    }

    /**
     * 修改电子档案右侧类型
     * @param archivesDetails
     * @return
     */
    @Override
    public AjaxResult updateDetails(ArchivesDetails archivesDetails) {
        // 根据类型名称和上级id查询，同级下名称不能重复
        ArchivesDetails info = archivesMapper.selectDetailsUpdateName(archivesDetails);
        if (info != null && !info.getDetailsId().equals(archivesDetails.getDetailsId())) {
            return AjaxResult.error(HttpCodeEnum.NAME_DUPLICATE.getCode(), HttpCodeEnum.NAME_DUPLICATE.getMsg());
        }
        archivesDetails.setUpdateBy(SecurityUtils.getLoginUser().getSysUser().getNickName());
        archivesDetails.setUpdateTime(DateUtils.getNowDate());
        int result = archivesMapper.updateDetails(archivesDetails);
        if (result > 0) {
            return AjaxResult.success(HttpCodeEnum.SUCCESS.getMsg(), result);
        }
        return AjaxResult.error(HttpCodeEnum.FAIL.getCode(), HttpCodeEnum.FAIL.getMsg());
    }

    /**
     * 删除电子档案右侧类型
     * @param archivesVo
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult deleteByDetails(ArchivesVo archivesVo) {
        // 判断是否有子节点,有则不能删除
        if (CollectionUtils.isNotEmpty(archivesVo.getArchivesDetailsList())) {
            for (ArchivesDetails archivesDetails : archivesVo.getArchivesDetailsList()) {
                List<ArchivesDetails> list = archivesMapper.selectDetailsList(archivesDetails);
                if (CollectionUtils.isNotEmpty(list)) {
                    return AjaxResult.error(HttpCodeEnum.FAIL.getCode(), "该文件下有子文件，无法删除");
                }
                int result = archivesMapper.deleteDetails(archivesDetails);
                if (result > 0) {
                    return AjaxResult.success(HttpCodeEnum.SUCCESS.getMsg(), result);
                }
                return AjaxResult.error(HttpCodeEnum.FAIL.getCode(), HttpCodeEnum.FAIL.getMsg());
            }
        }
        return AjaxResult.error(HttpCodeEnum.TO_PARAM_NULL.getCode(), HttpCodeEnum.TO_PARAM_NULL.getMsg());
    }


    /**
     * 下载电子档案右侧详情
     * @param archivesVo
     *
     * @return
     */
    @Override
    public AjaxResult download(ArchivesVo archivesVo, HttpServletRequest request, HttpServletResponse response) {
        // 使用系统临时目录
        //String zipSavePath = "D:/" + DateTimeHelper.getNowDate() + ".zip";
        String zipSavePath = System.getProperty("java.io.tmpdir") + File.separator + DateTimeHelper.getNowDate() + ".zip";
        List<Long> idList = new ArrayList<>();
        String[] arr = archivesVo.getIds().split(",");
        for (String s : arr) {
            idList.add(Long.valueOf(s));
        }
        archivesVo.setDetailsIdList(idList);
        // 根据id查询详情
        List<ArchivesDetails> list = archivesMapper.selectDetails(archivesVo.getDetailsIdList());
        if (CollectionUtils.isNotEmpty(list)) {
            for (ArchivesDetails archivesDetails : list) {
                if ("文件夹".equals(archivesDetails.getDocType())) {
                    HttpMsg httpMsg = new HttpMsg();
                    httpMsg.setCode(500);
                    httpMsg.setMsg("所选文件中包含文件夹，文件夹不能下载！");
                    return AjaxResult.error("所选文件中包含文件夹，文件夹不能下载！", httpMsg);
                }
            }
        }
        try {
            File file=new File(zipSavePath);
            if(!file.isDirectory() && !file.exists()) {
                file.createNewFile();
            }
            // 提取文件信息
            List<FileInfo> fileInfos = extractFileInfos(list);
            if (fileInfos.isEmpty()) {
                response.sendError(HttpServletResponse.SC_NOT_FOUND, "No files found to download.");
                return AjaxResult.error("未查询到文件信息，请检查后重新提交！");
            }
            ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipSavePath));
            for (FileInfo fileInfo : fileInfos) {
                String fileUrl = fileInfo.getFilePath();
                String originalPath = fileInfo.getFileName();
                if (!isValidFileExtension(originalPath)) {
                    // 可以根据业务需求添加默认文件类型或进行其他处理
                    if (originalPath.lastIndexOf('.') == -1) {
                        originalPath = originalPath + "." + fileInfo.getDocType();
                    } else {
                        originalPath = originalPath + fileInfo.getDocType();
                    }
                }
                // 使用系统临时目录
                //String zipSavePath = "D:/" + DateTimeHelper.getNowDate() + ".zip";
                String savePath = System.getProperty("java.io.tmpdir") + File.separator + originalPath;
                // 获取 Path 对象
                Path path = Paths.get(savePath);
                try {
                    // 确保父目录存在，如果不存在则创建
                    if (!Files.exists(path.getParent())) {
                        Files.createDirectories(path.getParent());
                    }
                    // 检查文件保存路径是否可写
                    if (Files.isWritable(path.getParent())) {
                        // 下载文件并保存到本地
                        downloadFile(fileUrl, savePath);
                        // 将文件添加到压缩包
                        fileToZip(savePath, zipOut);
                        // 将临时文件删除
                        new File(savePath).delete();
                    } else {
                        System.err.println("保存文件的路径不可写: " + savePath);
                    }
                } catch (IOException e) {
                    System.err.println("文件操作过程中出现异常: " + e.getMessage());
                }
            }
            // 压缩完成后,关闭压缩流
            zipOut.close();
            //拼接下载默认名称并转为ISO-8859-1格式
            String fileName = new String((DateTimeHelper.getNowDate() + "下载文件.zip").getBytes("UTF-8"),"ISO-8859-1");
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
            //该流不可以手动关闭,手动关闭下载会出问题,下载完成后会自动关闭
            ServletOutputStream outputStream = response.getOutputStream();
            FileInputStream inputStream = new FileInputStream(zipSavePath);
            // copy方法为文件复制,在这里直接实现了下载效果
            IOUtils.copy(inputStream, outputStream);
            // 关闭输入流
            inputStream.close();
            //下载完成之后，删掉这个zip包
            File fileTempZip = new File(zipSavePath);
            fileTempZip.delete();
            return AjaxResult.success("下载成功");
        } catch (IOException e) {
            e.printStackTrace();
            return AjaxResult.error("发生内部错误，请联系管理员！");
        }
    }

    /**
     * 判断文件扩展名是否在允许的范围内
     * @param originalPath
     * @return
     */
    private boolean isValidFileExtension(String originalPath) {
        // 定义一个正则表达式，匹配常见的文件扩展名
        String regex = ".*\\.(bmp|gif|jpg|jpeg|png|svg|doc|docx|xls|xlsx|csv|ppt|pptx|html|htm|txt|rar|zip|gz|bz2|mp4|avi|rmvb|pdf)$";
        return Pattern.matches(regex, originalPath);
    }

    /**
     * 下载文件
     * @param fileUrl
     * @param savePath
     */
    private void downloadFile(String fileUrl, String savePath) throws IOException {
        //处理中文文件名的问题
        String fileName = fileUrl.substring(fileUrl.lastIndexOf('/') + 1);
        String encodedFileName = URLEncoder.encode(fileName, "UTF-8");
        String newPath = fileUrl.substring(0, fileUrl.lastIndexOf('/') + 1) + encodedFileName;
        URL url = new URL(newPath);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        // 设置请求方法为 GET
        connection.setRequestMethod("GET");
        // 以下是一些可能的请求头设置，根据服务器需求修改
        connection.setRequestProperty("User-Agent", "Mozilla/5.0");
        connection.setRequestProperty("Accept", "application/pdf,text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
        connection.setRequestProperty("Accept-Language", "en-US,en;q=0.5");
        // 禁用缓存
        connection.setRequestProperty("Cache-Control", "no-cache");
        connection.setRequestProperty("Pragma", "no-cache");
        // 假设需要添加认证信息，添加 Authorization 头，根据实际情况修改
        connection.setRequestProperty("Authorization", "Bearer your_access_token");
        // 延长连接超时和读取超时时间
        connection.setConnectTimeout(10000);
        connection.setReadTimeout(10000);
        try {
            int responseCode = connection.getResponseCode();
            if (responseCode == 200) {
                try (InputStream inputStream = connection.getInputStream();
                     BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
                     FileOutputStream fileOutputStream = new FileOutputStream(savePath)) {
                    byte[] buffer = new byte[1024];
                    int bytesRead;
                    while ((bytesRead = bufferedInputStream.read(buffer))!= -1) {
                        fileOutputStream.write(buffer, 0, bytesRead);
                    }
                }
            } else {
                throw new IOException("Server returned HTTP response code: " + responseCode);
            }
        } catch (IOException e) {
            // 更详细的异常信息打印
            System.err.println("Failed to download file from " + fileUrl);
        } finally {
            connection.disconnect();
        }
    }

    /**
     * 将文件添加到压缩包
     * @param filePath
     * @param zipOut
     * @throws IOException
     */
    public static void fileToZip(String filePath, ZipOutputStream zipOut) throws IOException {
        // 需要压缩的文件
        File file = new File(filePath);
        // 获取文件名称,如果有特殊命名需求,可以将参数列表拓展,传fileName
        String fileName = file.getName();
        FileInputStream fileInput = new FileInputStream(filePath);
        // 缓冲
        byte[] bufferArea = new byte[1024 * 10];
        BufferedInputStream bufferStream = new BufferedInputStream(fileInput, 1024 * 10);
        // 将当前文件作为一个zip实体写入压缩流,fileName代表压缩文件中的文件名称
        zipOut.putNextEntry(new ZipEntry(fileName));
        int length = 0;
        while ((length = bufferStream.read(bufferArea, 0, 1024 * 10)) != -1) {
            zipOut.write(bufferArea, 0, length);
        }
        //关闭流
        fileInput.close();
        // 需要注意的是缓冲流必须要关闭流,否则输出无效
        bufferStream.close();
    }

    /**
     * 电子签名 修改用户表信息
     * @param info
     * @return
     */
    @Override
    public AjaxResult updateSign(ElcSignatureInfo info) {
        if (info == null || info.getSignUrl() == null) {
            return AjaxResult.error(HttpCodeEnum.TO_PARAM_NULL.getCode(), HttpCodeEnum.TO_PARAM_NULL.getMsg());
        }
        Long userId = SecurityUtils.getLoginUser().getUserid();
        if (userId == null) {
            return AjaxResult.error("无法获取到当前用户信息，请联系管理员！");
        }
        info.setUserId(userId);
        int result = archivesMapper.updateSign(info);
        if (result > 0) {
            return AjaxResult.success(HttpCodeEnum.SUCCESS.getMsg(), result);
        }
        return AjaxResult.error(HttpCodeEnum.FAIL.getCode(), HttpCodeEnum.FAIL.getMsg());
    }

    /**
     * 获取电子签名 修改用户表信息
     * @param info
     * @return
     */
    @Override
    public AjaxResult getSign(ElcSignatureInfo info) {
        Long userId = SecurityUtils.getLoginUser().getUserid();
        if (userId == null) {
            return AjaxResult.error("无法获取到当前用户信息，请联系管理员！");
        }
        info.setUserId(userId);
        ElcSignatureInfo elcSignatureInfo = archivesMapper.getSign(info);
        if (elcSignatureInfo != null) {
            if (StringUtils.isNotBlank(elcSignatureInfo.getSignUrl())) {
                if (!elcSignatureInfo.getSignUrl().startsWith("http")) {
                    elcSignatureInfo.setSignUrl("data:image/png;base64," + elcSignatureInfo.getSignUrl());
                }
            }
        }
        return AjaxResult.success(elcSignatureInfo);
    }

    /**
     * 从档案详情中提取文件信息
     * @param detailsList
     * @return
     */
    private List<FileInfo> extractFileInfos(List<ArchivesDetails> detailsList) {
        List<FileInfo> fileInfos = new ArrayList<>();
        if (detailsList != null && !detailsList.isEmpty()) {
            for (ArchivesDetails archivesDetails : detailsList) {
                if (archivesDetails.getDocUrl() != null && !archivesDetails.getDocUrl().isEmpty()) {
                    FileInfo fileInfo = new FileInfo();
                    fileInfo.setFileName(archivesDetails.getDocName());
                    fileInfo.setFilePath(archivesDetails.getDocUrl());
                    fileInfo.setUpdateBy(archivesDetails.getUpdateBy());
                    fileInfo.setUpdateTime(archivesDetails.getUpdateTime());
                    fileInfo.setDocType(archivesDetails.getDocType());
                    fileInfos.add(fileInfo);
                }
            }
        }
        return fileInfos;
    }

    /**
     * 创建临时ZIP文件
     * @param fileInfos
     * @return
     * @throws IOException
     */
    private String createTempZipFile(List<FileInfo> fileInfos) throws IOException {
        String tempZipFilePath = "temp_files.zip";
        try {
            FileCompressor.zipFiles(fileInfos, tempZipFilePath);
        } catch (IOException e) {
            throw new IOException("Error creating ZIP file", e);
            }
        return tempZipFilePath;
    }

    /**
     * 设置HTTP响应头
     * @param response
     */
    private void setResponseHeaders(HttpServletResponse response) {
        response.setContentType("application/zip");
        response.setHeader("Content-Disposition", "attachment; filename=files.zip");
    }

    /**
     * 将生成的ZIP文件流返回给客户端
     * @param zipFilePath
     * @param response
     * @throws IOException
     */
    private void sendZipFileToClient(String zipFilePath, HttpServletResponse response) throws IOException {
        Path zipPath = Paths.get(zipFilePath);
        try (BufferedInputStream bis = new BufferedInputStream(Files.newInputStream(zipPath));
             OutputStream os = response.getOutputStream()) {

            byte[] buffer = new byte[8192]; // 使用更大的缓冲区
            int bytesRead;
            while ((bytesRead = bis.read(buffer)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
        } catch (IOException e) {
            throw new IOException("Error sending ZIP file to client", e);
        }
    }

    /**
     * 删除临时ZIP文件
     * @param zipFilePath
     */
    private void deleteTempZipFile(String zipFilePath) {
        try {
            Path path = Paths.get(zipFilePath);
            if (Files.exists(path)) {
                Files.delete(path);
            }
        } catch (IOException e) {
            System.err.println("Failed to delete temporary ZIP file: " + e.getMessage());
        }
    }

}
