package com.yfd.platform.modules.experimentalData.controller;


import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yfd.platform.annotation.Log;
import com.yfd.platform.component.TaskStatusHolder;
import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.modules.experimentalData.domain.*;
import com.yfd.platform.modules.experimentalData.service.ITsFilesService;
import com.yfd.platform.modules.storage.model.result.FileItemResult;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;

/**
 * <p>
 * 试验任务文档表 前端控制器
 * </p>
 *
 * @author LiMengNan
 * @since 2025-01-21
 */
@RestController
@RequestMapping("/experimentalData/ts-files")
public class TsFilesController {

    //实验任务文档表
    @Resource
    private ITsFilesService tsFilesService;

    @Autowired
    private TaskStatusHolder taskStatusHolder;

    /**********************************
     * 用途说明: 分页查询试验数据管理-文档内容
     * 参数说明
     * id            id
     * fileName      文件名称
     * startDate     (开始日期)
     * endDate      （结束日期）
     * keywords      关键字
     *nodeId         节点ID
     *taskId          任务ID
     *isFile          文件夹、文件区分
     * pageNum 当前页
     * 返回值说明: com.yfd.platform.config.ResponseResult 返回分页查询结果
     ***********************************/
    @Log(module = "实验数据管理", value = "分页查询实验数据管理文档内容！")
    @GetMapping("/page")
    @ApiOperation("分页查询实验数据管理文档内容")
    @PreAuthorize("@el.check('select:tsfiles')")
    public ResponseResult getTsFilesPage(String id, String fileName, String startDate, String endDate, String keywords, String nodeId, String taskId, String childNode, Page<TsFiles> page) throws Exception {
        //分页查询
        int currentPage = (int) page.getCurrent();
        // 先尝试从缓存获取
        if(!StrUtil.isEmpty(id)){
            IPage<TsFiles> cachedPage = tsFilesService.getCachedTsFilesPage(taskId, nodeId, currentPage,id);
            if (cachedPage != null) {
                return ResponseResult.successData(cachedPage);
            }
        }
        Page<TsFiles> tsfilesPage = tsFilesService.getTsFilesPage(id, fileName, startDate, endDate, keywords, nodeId, taskId, fileName, childNode, page);
        return ResponseResult.successData(tsfilesPage);
    }

    /**********************************
     * 用途说明:   查询实验数据管理文件夹
     * 参数说明 id      父级ID
     * 参数说明 path    路径
     * 参数说明nodeId   节点ID
     * 参数说明taskId   任务ID
     * pageNum 当前页
     * 返回值说明: com.yfd.platform.config.ResponseResult 返回分页查询结果
     ***********************************/
    @Log(module = "实验数据管理", value = "查询实验数据管理文件夹！")
    @GetMapping("/listTsFiles")
    @ApiOperation("查询实验数据管理文件夹")
    @PreAuthorize("@el.check('select:tsfiles')")
    public ResponseResult getsListTsFiles(String id, String path, String nodeId, String taskId) throws Exception {
        //分页查询
        List<TsFiles> tsfiles = tsFilesService.getsListTsFiles(id, path, nodeId, taskId);
        return ResponseResult.successData(tsfiles);
    }

    /***********************************
     * 用途说明：新增试验数据管理-文档内容
     * 参数说明
     * TsFiles     文档内容
     * 返回值说明:  com.yfd.platform.config.ResponseResult 返回新增成功或者失败
     ***********************************/
    @Log(module = "实验数据管理", value = "新增试验数据管理文档内容！")
    @PostMapping("/addTsFiles")
    @ApiOperation("新增试验数据管理文档内容")
    @ResponseBody
    @PreAuthorize("@el.check('add:tsFiles')")
    public ResponseResult addTsFiles(@RequestBody TsFiles tsFiles) {
        //对象不能为空
        if (ObjUtil.isEmpty(tsFiles)) {
            return ResponseResult.error("参数为空");
        }

        return tsFilesService.addTsFiles(tsFiles);

    }

    /***********************************
     * 用途说明：新增试验数据管理-文件夹
     * 参数说明
     * TsFiles     文档内容
     * 返回值说明:  com.yfd.platform.config.ResponseResult 返回新增成功或者失败
     ***********************************/
    @Log(module = "实验数据管理", value = "新增试验数据管理文件夹")
    @PostMapping("/addTsFile")
    @ApiOperation("新增试验数据管理文件夹")
    @ResponseBody
    @PreAuthorize("@el.check('add:tsFiles')")
    public ResponseResult addTsFile(@RequestBody TsFiles tsFiles) throws IOException {
        //对象不能为空
        if (ObjUtil.isEmpty(tsFiles)) {
            return ResponseResult.error("参数为空");
        }
        return tsFilesService.addTsFile(tsFiles);

    }

    /**********************************
     * 用途说明: 修改试验数据管理-文档内容
     * 参数说明
     * TsFiles     文档内容
     * 返回值说明: com.yfd.platform.config.ResponseResult 返回修改成功或者失败
     ***********************************/
    @Log(module = "试验数据管理", value = "修改试验数据管理文档内容")
    @PostMapping("/updateTsFiles")
    @ApiOperation("修改试验数据管理文档内容")
    @PreAuthorize("@el.check('update:tsFiles')")
    public ResponseResult updateTsFiles(@RequestBody TsFiles tsFiles) {
        //对象不能为空
        if (ObjUtil.isEmpty(tsFiles) && StrUtil.isBlank(tsFiles.getId())) {
            return ResponseResult.error("参数为空");
        }
        return tsFilesService.updateTsFiles(tsFiles);

    }

    /**********************************
     * 用途说明: 根据ID删除试验数据管理-文档内容
     * 参数说明  id 文档内容ID
     * 参数说明  type local还是minio
     * 返回值说明: com.yfd.platform.config.ResponseResult 返回删除成功或者失败
     ***********************************/
    @Log(module = "试验数据管理", value = "根据ID删除试验数据管理文档内容")
    @PostMapping("/deleteTsFilesById")
    @ApiOperation("根据ID删除试验数据管理文档内容")
    @PreAuthorize("@el.check('del:tsFiles')")
    public ResponseResult deleteTsFilesById(@RequestParam String id, @RequestParam String type) {
        if (StrUtil.isBlank(id)) {
            return ResponseResult.error("参数为空");
        }
        List<String> dataset = Arrays.asList(id);
        return ResponseResult.success(tsFilesService.deleteTsFilesByIds(dataset, type));
    }

    /**********************************
     * 用途说明: 批量删除试验数据管理-文档内容
     * 参数说明  ids 文档内容id数组
     * 参数说明  type local还是minio
     * 返回值说明: com.yfd.platform.config.ResponseResult 返回批量删除成功或失败
     ***********************************/
    @Log(module = "专项文档管理", value = "批量删除试验数据管理文档内容")
    @PostMapping("/deleteTsFilesByIds")
    @ApiOperation("批量删除试验数据管理文档内容")
    @PreAuthorize("@el.check('del:tsFiles')")
    public ResponseResult deleteTsFilesByIds(@RequestParam String ids, @RequestParam String type) {
        if (StrUtil.isBlank(ids)) {
            return ResponseResult.error("参数为空");
        }
        String[] splitIds = ids.split(",");
        // 数组转集合
        List<String> dataset = Arrays.asList(splitIds);
        return ResponseResult.success(tsFilesService.deleteTsFilesByIds(dataset, type));
    }

    /**************************压缩 解压缩********************************/

    /**********************************
     * 用途说明: 压缩文件夹接口
     * 参数说明  ids 文件id数组
     * 参数说明  compressedFormat 压缩文件格式
     * 参数说明  compressedName 压缩文件名称
     * 参数说明  compressedPath 压缩文件路径
     * 参数说明  covered 是否覆盖 0 覆盖更新updateTime时间 1提示文件存在
     * 参数说明  parentId 父ID
     * 参数说明  path   根目录 /项目名/节点名称/
     * 返回值说明: com.yfd.platform.config.ResponseResult
     ***********************************/
    @Log(module = "实验数据管理", value = "压缩文件夹接口！")
    @PostMapping("/compress")
    @ApiOperation("压缩文件夹接口")
    public ResponseResult compressFolder(String ids, String compressedFormat, String compressedName, String compressedPath, String covered, String parentId, String path) {
        try {
            if (StrUtil.isBlank(ids) && StrUtil.isBlank(compressedFormat) && StrUtil.isBlank(compressedName) && StrUtil.isBlank(compressedPath) && StrUtil.isBlank(path)) {
                return ResponseResult.error("参数为空");
            }

            return ResponseResult.success(tsFilesService.compressFolder(ids, compressedFormat, compressedName, compressedPath, covered, parentId, path));
        } catch (Exception e) {
            System.out.print("压缩异常原因" + e);
            return ResponseResult.error("压缩失败");
        }
    }

    /**********************************
     * 用途说明: 解压缩接口
     * 参数说明  id  要解压的文件id
     * 参数说明  decompressionPath 解压缩路径
     * 参数说明  parentId 父ID
     * 参数说明  path   根目录 /项目名/节点名称/
     * 返回值说明: com.yfd.platform.config.ResponseResult
     ***********************************/
    @Log(module = "实验数据管理", value = "解压缩接口！")
    @PostMapping("/decompression")
    @ApiOperation("解压缩接口")
    public ResponseResult decompressionFolder(String id, String decompressionPath, String parentId, String path) {
        try {
            if (StrUtil.isBlank(id)) {
                return ResponseResult.error("参数为空");
            }


            return ResponseResult.success(tsFilesService.decompressionFolder(id, decompressionPath, parentId, path));
        } catch (Exception e) {
            System.out.print("解压缩异常原因" + e);
            return ResponseResult.error("解压缩失败");
        }
    }

    /**
     * 移动文件或文件夹
     * 参数说明 newPath 新路径
     * 参数说明 oldpaths 原路径
     * 参数说明 ParentId 父ID
     * 参数说明 newFileName 勾选的所有文件名称
     * 参数说明 Rename 重命名的文件名称
     * 参数说明 type 覆盖还是重命名  0 1
     */
    @Log(module = "实验数据管理", value = "移动文件文件夹！")
    @PostMapping("/moveFileFolder")
    @ApiOperation("移动")
    public ResponseResult moveFileFolder(@RequestBody MoveCopyFileFolderRequest request) throws IOException {

        try {
            if (request == null) {
                throw new IllegalArgumentException("请求参数不能为空");
            }
            if (request.getNewFileName() == null || request.getNewFileName().isEmpty()) {
                throw new IllegalArgumentException("newFileName 不能为空");
            }
            if (request.getNewPath() == null || request.getOldpaths() == null) {
                throw new IllegalArgumentException("路径参数不能为空");
            }

            return ResponseResult.success(tsFilesService.moveFileFolder(request));
        } catch (Exception e) {
            System.out.print("移动异常原因" + e);
            return ResponseResult.error("移动失败");
        }
    }

    /**
     * 复制文件或文件夹
     * 参数说明 newPath 新路径
     * 参数说明 oldpaths 原路径
     * 参数说明 ParentId 父ID
     * 参数说明 newFileName 勾选的所有文件名称
     * 参数说明 Rename 重命名的文件名称
     * 参数说明 type 覆盖还是重命名  0 1
     */
    @Log(module = "实验数据管理", value = "复制文件文件夹！")
    @PostMapping("/copyFileFolder")
    @ApiOperation("复制")
    public ResponseResult copyFileFolder(@RequestBody MoveCopyFileFolderRequest request) throws IOException {

        try {
            if (request == null) {
                throw new IllegalArgumentException("请求参数不能为空");
            }
            if (request.getNewFileName() == null || request.getNewFileName().isEmpty()) {
                throw new IllegalArgumentException("newFileName 不能为空");
            }
            if (request.getNewPath() == null || request.getOldpaths() == null) {
                throw new IllegalArgumentException("路径参数不能为空");
            }
            return ResponseResult.success(tsFilesService.copyFileFolder(request));
        } catch (Exception e) {
            System.out.print("复制异常原因" + e);
            return ResponseResult.error("复制失败");
        }
    }

    /**********************************
     * 用途说明: 对比本地和minio的文件差异
     * 参数说明  taskId 节点ID
     * 参数说明  nodeId 任务ID
     * 参数说明  id     文件id
     * 返回值说明: com.yfd.platform.config.ResponseResult 返回成功或者失败
     ***********************************/
    @Log(module = "实验数据管理", value = "对比本地和minio的文件差异！")
    @PostMapping("/compareMd5")
    @ApiOperation("对比本地和minio的文件差异")
    public ResponseResult compareMd5(String id, String nodeId, String taskId, Page<TsFiles> page) {
        try {
            List<String> dataset = new ArrayList<>();
            if (StrUtil.isNotEmpty(id)) {
                String[] splitIds = id.split(",");
                // 数组转集合
                dataset = Arrays.asList(splitIds);
            }
            Page<TsFiles> tsfilesPage = tsFilesService.compareMd5(dataset, nodeId, taskId, page);

            //List<TsFilesDTO> dtos = tsFilesService.compareMd5(dataset, nodeId, taskId);
            return ResponseResult.successData(tsfilesPage);
        } catch (Exception e) {
            return ResponseResult.error("对比失败");
        }
    }

    /**********************************
     * 用途说明: 对比本地和minio的文件差异
     * 参数说明  taskId 节点ID
     * 参数说明  nodeId 任务ID
     * 参数说明  id     文件id
     * 返回值说明: com.yfd.platform.config.ResponseResult 返回成功或者失败
     ***********************************/
    @Log(module = "实验数据管理", value = "对比本地和minio的文件差异返回集合！")
    @PostMapping("/compareMd5List")
    @ApiOperation("对比本地和minio的文件差异返回集合")
    public ResponseResult compareMd5List(String id, String nodeId, String taskId) {
        try {
            List<String> dataset = new ArrayList<>();
            if (StrUtil.isNotEmpty(id)) {
                String[] splitIds = id.split(",");
                // 数组转集合
                dataset = Arrays.asList(splitIds);
            }
            return ResponseResult.successData(tsFilesService.compareMd5List(dataset, nodeId, taskId));
        } catch (Exception e) {
            return ResponseResult.error("对比失败");
        }
    }

    /**********************************
     * 用途说明: 对比本地有minio没有的文件差异
     * 参数说明  taskId 节点ID
     * 参数说明  nodeId 任务ID
     * 参数说明  id     文件id
     * 返回值说明: com.yfd.platform.config.ResponseResult 返回成功或者失败
     ***********************************/
    @Log(module = "实验数据管理", value = "对比本地有minio没有的文件差异！")
    @PostMapping("/compareLocal")
    @ApiOperation("对比本地有minio没有的文件差异")
    public ResponseResult compareLocal(String id, String nodeId, String taskId, Page<TsFiles> page) {
        try {
            List<String> dataset = new ArrayList<>();
            if (StrUtil.isNotEmpty(id)) {
                String[] splitIds = id.split(",");
                // 数组转集合
                dataset = Arrays.asList(splitIds);
            }

            Page<TsFiles> tsfilesPage = tsFilesService.compareLocal(dataset, nodeId, taskId, page);

            return ResponseResult.successData(tsfilesPage);
        } catch (Exception e) {
            return ResponseResult.error("对比失败");
        }
    }


    /**********************************
     * 用途说明: 对比本地有minio没有的文件差异
     * 参数说明  taskId 节点ID
     * 参数说明  nodeId 任务ID
     * 参数说明  id     文件id
     * 返回值说明: com.yfd.platform.config.ResponseResult 返回成功或者失败
     ***********************************/
    @Log(module = "实验数据管理", value = "对比本地有minio没有的文件差异返回集合！")
    @PostMapping("/compareLocalList")
    @ApiOperation("对比本地有minio没有的文件差异返回集合")
    public ResponseResult compareLocalList(String id, String nodeId, String taskId) {
        try {
            List<String> dataset = new ArrayList<>();
            if (StrUtil.isNotEmpty(id)) {
                String[] splitIds = id.split(",");
                // 数组转集合
                dataset = Arrays.asList(splitIds);
            }
            return ResponseResult.successData(tsFilesService.compareLocalList(dataset, nodeId, taskId));
        } catch (Exception e) {
            return ResponseResult.error("对比失败");
        }
    }

    /**********************************
     * 用途说明: 对比本地没有minio有的文件差异
     * 参数说明  taskId 节点ID
     * 参数说明  nodeId 任务ID
     * 参数说明  id     文件id
     * 返回值说明: com.yfd.platform.config.ResponseResult 返回成功或者失败
     ***********************************/
    @Log(module = "实验数据管理", value = "对比本地没有minio有的文件差异！")
    @PostMapping("/compareMinio")
    @ApiOperation("对比本地没有minio有的文件差异")
    public ResponseResult compareMinio(String id, String nodeId, String taskId, Page<TsFiles> page) {
        try {
            List<String> dataset = new ArrayList<>();
            if (StrUtil.isNotEmpty(id)) {
                String[] splitIds = id.split(",");
                // 数组转集合
                dataset = Arrays.asList(splitIds);
            }
            Page<TsFiles> tsfilesPage = tsFilesService.compareMinio(dataset, nodeId, taskId, page);
            return ResponseResult.successData(tsfilesPage);
        } catch (Exception e) {
            return ResponseResult.error("对比失败");
        }
    }


    /**********************************
     * 用途说明: 对比本地没有minio有的文件差异
     * 参数说明  taskId 节点ID
     * 参数说明  nodeId 任务ID
     * 参数说明  id     文件id
     * 返回值说明: com.yfd.platform.config.ResponseResult 返回成功或者失败
     ***********************************/
    @Log(module = "实验数据管理", value = "对比本地没有minio有的文件差异返回集合！")
    @PostMapping("/compareMinioList")
    @ApiOperation("对比本地没有minio有的文件差异返回集合")
    public ResponseResult compareMinioList(String id, String nodeId, String taskId) {
        try {
            List<String> dataset = new ArrayList<>();
            if (StrUtil.isNotEmpty(id)) {
                String[] splitIds = id.split(",");
                // 数组转集合
                dataset = Arrays.asList(splitIds);
            }
            return ResponseResult.successData(tsFilesService.compareMinioList(dataset, nodeId, taskId));

        } catch (Exception e) {
            return ResponseResult.error("对比失败");
        }
    }

    /**********************************
     * 用途说明: 将文件上传到备份空间
     * 参数说明  parameter 数据集合
     * 返回值说明: com.yfd.platform.config.ResponseResult 返回成功或者失败
     ***********************************/
    @Log(module = "实验数据管理", value = "将文件上传到备份空间！")
    @PostMapping("/uploadToBackup")
    @ApiOperation("将文件上传到备份空间")
    public ResponseResult uploadToBackup(@RequestBody Parameter parameter) {

        if (parameter == null) {
            return ResponseResult.error("参数为空");
        }
        Boolean isOk = tsFilesService.uploadToBackup(parameter);
        if (isOk) {
            return ResponseResult.success();
        } else {
            return ResponseResult.error();
        }

    }

    /**********************************
     * 用途说明: 从备份空间下载到工作空间
     * 参数说明  parameter 数据集合
     * 返回值说明: com.yfd.platform.config.ResponseResult 返回成功或者失败
     ***********************************/
    @Log(module = "实验数据管理", value = "从备份空间下载到工作空间！")
    @PostMapping("/downloadToLocal")
    @ApiOperation("从备份空间下载到工作空间")
    public ResponseResult downloadToLocal(@RequestBody Parameter parameter) {

        if (parameter == null) {
            return ResponseResult.error("参数为空");
        }
        Boolean isOk = tsFilesService.downloadToLocal(parameter);
        if (isOk) {
            return ResponseResult.success();
        } else {
            return ResponseResult.error();
        }

    }

    /**********************************
     * 用途说明: 查询本地结构树
     * 参数说明  taskId 节点ID
     * 参数说明  nodeId 任务ID
     * 返回值说明: com.yfd.platform.config.ResponseResult 返回双树数据
     ***********************************/
    @Log(module = "实验数据管理", value = "查询本地结构树！")
    @PostMapping("/listLocalTree")
    @ApiOperation("查询本地结构树")
    public ResponseResult listLocalTree(String taskId, String nodeId) {

        //查询本地树和minio树
        DualTreeResponse response = tsFilesService.listLocalTree(taskId, nodeId);
        return ResponseResult.successData(response);
    }

    /**********************************
     * 用途说明: 查询备份空间结构树
     * 参数说明  taskId 节点ID
     * 参数说明  nodeId 任务ID
     * 返回值说明: com.yfd.platform.config.ResponseResult 返回双树数据
     ***********************************/
    @Log(module = "实验数据管理", value = "查询备份空间结构树！")
    @PostMapping("/listBackupTree")
    @ApiOperation("查询备份空间结构树")
    public ResponseResult listBackupTree(String taskId, String nodeId) {

        //查询本地树和minio树
        DualTreeResponse response = tsFilesService.listBackupTree(taskId, nodeId);
        return ResponseResult.successData(response);
    }

    /**********************************
     * 用途说明: 文件自动备份
     * 参数说明  taskId 节点ID
     * 参数说明  nodeId 任务ID
     * 返回值说明: com.yfd.platform.config.ResponseResult 返回成功或者失败
     ***********************************/
    @Log(module = "实验数据管理", value = "文件自动备份！")
    @PostMapping("/automaticFileBackup")
    @ApiOperation("自动备份本地文件到备份空间通过节点和任务")
    public ResponseResult automaticFileBackup(String taskId, String nodeId) throws IOException {


        if (StrUtil.isEmpty(taskId) || StrUtil.isEmpty(nodeId)) {
            return ResponseResult.error("参数为空");
        }

        // 生成唯一Key
        String asyncKey = taskStatusHolder.generateKey(taskId, nodeId);

        // 检查任务是否已存在
        String existingStatus = taskStatusHolder.getStatus(asyncKey);
        if ("IN_PROGRESS".equals(existingStatus)) {
            return ResponseResult.success("任务正在处理中!");
        } else if ("COMPLETED".equals(existingStatus)) {
            return ResponseResult.success("任务已完成!");
        }
        // 原子性启动新任务
        if (taskStatusHolder.startTaskIfAbsent(asyncKey)) {
            // 直接异步执行并推送结果
            tsFilesService.automaticFileBackupAsync(taskId, nodeId);
            return ResponseResult.success("任务开始处理!");
        } else {
            return ResponseResult.success("任务已由其他请求启动");
        }
    }

    /**********************************
     * 用途说明: 获取异步信息
     * 参数说明  taskId 所属项目ID
     * 参数说明  nodeId 所属节点ID
     * 返回值说明: com.yfd.platform.config.ResponseResult 返回成功或者失败
     ***********************************/
    @Log(module = "根据项目和节点获取异步信息", value = "根据项目和节点获取异步信息！")
    @PostMapping("/automaticFileBackupData")
    @ApiOperation("获取异步信息")
    public ResponseResult automaticFileBackupData(String taskId, String nodeId) throws Exception {
        if (StrUtil.isEmpty(taskId) || StrUtil.isEmpty(nodeId)) {
            return ResponseResult.error("参数为空");
        }
        // 生成唯一Key
        String asyncKey = taskStatusHolder.generateKey(taskId, nodeId);
        JSONObject jsonObject1 = new JSONObject();
        // 检查任务是否已存在
        String existingStatus = taskStatusHolder.getStatus(asyncKey);
        if ("TASK_NOT_FOUND".equals(existingStatus)) {
            jsonObject1.putOpt("status", "1");
            return ResponseResult.successData(jsonObject1);
        }
        if ("IN_PROGRESS".equals(existingStatus)) {
            jsonObject1.putOpt("status", "0");
            return ResponseResult.successData(jsonObject1);
        } else if ("COMPLETED".equals(existingStatus)) {
            jsonObject1.putOpt("status", "1");
            return ResponseResult.successData(jsonObject1);
        }

        return null;
    }


    /**********************************
     * 用途说明: 文件自动备份通过ID
     * 参数说明  taskId 节点ID
     * 参数说明  nodeId 任务ID
     * 返回值说明: com.yfd.platform.config.ResponseResult 返回成功或者失败
     ***********************************/
    @Log(module = "实验数据管理", value = "文件自动备份！")
    @PostMapping("/automaticFileBackupByIds")
    @ApiOperation("自动备份本地文件到备份空间通过ID")
    public ResponseResult automaticFileBackupByIds(String id,String taskId, String nodeId) throws IOException {
        if (StrUtil.isEmpty(id)) {
            return ResponseResult.error("参数为空");
        }
        List<String> dataset = StrUtil.split(id, ",");

        // 生成唯一Key
        String asyncKey = taskStatusHolder.generateKey(taskId, nodeId);

        // 检查任务是否已存在
        String existingStatus = taskStatusHolder.getStatus(asyncKey);
        if ("IN_PROGRESS".equals(existingStatus)) {
            return ResponseResult.success("任务正在处理中!");
        } else if ("COMPLETED".equals(existingStatus)) {
            return ResponseResult.success("任务已完成!");
        }
        // 原子性启动新任务
        if (taskStatusHolder.startTaskIfAbsent(asyncKey)) {
            // 直接异步执行并推送结果
            tsFilesService.automaticFileBackupAsyncByIds(dataset,taskId,nodeId);
            return ResponseResult.success("任务开始处理!");
        } else {
            return ResponseResult.success("任务已由其他请求启动");
        }
    }


    /**********************************
     * 用途说明: 实时获取轨迹数据
     * 参数说明  id 文件的ID
     * 参数说明  samTimes 时间
     * 参数说明  token SSE连接的token
     * 返回值说明: com.yfd.platform.config.ResponseResult
     ***********************************/
    @Log(module = "实验数据管理", value = "实时获取轨迹数据！")
    @PostMapping("/startSimpleNavi")
    @ApiOperation("实时获取轨迹数据")
    public ResponseResult startSimpleNavi(String id, int samTimes, String token) {
        try {
            // 使用线程池异步执行任务
            CompletableFuture.runAsync(() -> {
                try {
                    tsFilesService.batchSendNaviOutDataJob(id, samTimes, token);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }, Executors.newCachedThreadPool());

            return ResponseResult.success("任务已启动");
        } catch (Exception e) {
            return ResponseResult.error("任务启动失败: " + e.getMessage());
        }

    }

    /**********************************
     * 用途说明: 停止获取轨迹数据
     * 参数说明  token SSE连接的token
     * 返回值说明: com.yfd.platform.config.ResponseResult
     ***********************************/
    @Log(module = "实验数据管理", value = "停止获取轨迹数据！")
    @PostMapping("/stopSimpleNavi")
    @ApiOperation("停止获取轨迹数据")
    public ResponseResult stopSimpleNavi(String token) {
        tsFilesService.stopSimpleNavi(token);
        return ResponseResult.success();
    }

    /**********************************
     * 用途说明: 查询文件内容接口
     * 参数说明  id 文件的ID
     * 参数说明  type 查看本地还是minio   local  minio
     * 返回值说明: com.yfd.platform.config.ResponseResult文件内容的纯文本（UTF-8 编码）
     ***********************************/
    @Log(module = "实验数据管理", value = "查询文件内容！")
    @GetMapping("/api/files/content")
    @ApiOperation("查询文件内容")
    public ResponseResult getFileContent(@RequestParam String id) {
        try {
            if (StrUtil.isBlank(id)) {
                return ResponseResult.error("参数为空");
            }
            String content = tsFilesService.readFileContent(id);
            return ResponseResult.successData(content);
        } catch (SecurityException | IOException e) {
            return ResponseResult.error("非法操作: " + e.getMessage());
        }
    }

    /**********************************
     * 用途说明: 保存文件内容接口
     * 参数说明  id 文件的ID
     * 参数说明  content 新的文件内容（HTML/文本）
     * 返回值说明: com.yfd.platform.config.ResponseResult操作结果
     ***********************************/
    @Log(module = "实验数据管理", value = "保存文件内容！")
    @PostMapping("/save/files/content")
    @ApiOperation("保存文件内容")
    public ResponseResult saveFileContent(String id, String content) {
        try {
            if (StrUtil.isBlank(id) && StrUtil.isBlank(content)) {
                return ResponseResult.error("参数为空");
            }
            tsFilesService.saveFileContent(id, content);
            return ResponseResult.success("文件保存成功");
        } catch (SecurityException | IOException e) {
            return ResponseResult.error("非法操作: " + e.getMessage());
        }
    }


    /**********************************
     * 用途说明: 批量修改文件中多行多列的内容
     * 参数说明  request 要修改的文件信息
     * 返回值说明: com.yfd.platform.config.ResponseResult操作结果
     ***********************************/
    @Log(module = "实验数据管理", value = "批量修改文件中多行多列的内容！")
    @PostMapping("/batchModify")
    @ApiOperation("批量修改文件中多行多列的内容")
    public ResponseResult batchModifyFile(@RequestBody BatchModifyRequest request) throws IOException {
        tsFilesService.batchUpdateFile(request.getId(), request.getModifications());
        return ResponseResult.success("文件保存成功");
    }

    /**********************************
     * 用途说明: 获取文件url
     * 参数说明  id     文件夹ID
     * 返回值说明: com.yfd.platform.config.ResponseResult 返回文件信息
     ***********************************/
    @Log(module = "实验数据管理", value = "获取文件url！")
    @PostMapping("/obtainUrl")
    @ApiOperation("获取文件url")
    public ResponseResult obtainUrl(String id, String type) {
        if (StrUtil.isBlank(id) && StrUtil.isBlank(type)) {
            return ResponseResult.error("参数为空");
        }
        //查询本地树和minio树
        FileItemResult fileItemResult = tsFilesService.obtainUrl(id, type);
        return ResponseResult.successData(fileItemResult);
    }
}
