package com.backendsys.modules.upload.service.impl;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.json.JSONArray;
import com.backendsys.exception.CustException;
import com.backendsys.modules.common.config.security.enums.SecurityEnum;
import com.backendsys.modules.common.config.security.utils.HttpRequestUtil;
import com.backendsys.modules.common.config.security.utils.SecurityUtil;
import com.backendsys.modules.sdk.douyincloud.tos.service.DouyinTosService;
import com.backendsys.modules.sdk.tencentcloud.cos.service.TencentCosService;
import com.backendsys.modules.system.entity.SysCommon;
import com.backendsys.modules.system.service.SysCommonService;
import com.backendsys.modules.upload.dao.SysFileCategoryDao;
import com.backendsys.modules.upload.dao.SysFileDao;
import com.backendsys.modules.upload.entity.SysFile;
import com.backendsys.modules.upload.entity.SysFileCategory;
import com.backendsys.modules.upload.entity.SysFileMergeByMd5;
import com.backendsys.modules.upload.entity.SysFileResult;
import com.backendsys.modules.upload.enums.StyleEnums;
import com.backendsys.modules.upload.enums.TargetEnums;
import com.backendsys.modules.upload.service.SysFileService;
import com.backendsys.modules.upload.utils.ObjectKey.ObjectKeyEntity;
import com.backendsys.modules.upload.utils.UploadUtil;
import com.backendsys.utils.response.PageEntity;
import com.backendsys.utils.response.PageInfoResult;
import com.backendsys.utils.response.ResultEnum;
import com.backendsys.utils.v2.PageUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.net.URL;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

@Service
public class SysFileServiceImpl extends ServiceImpl<SysFileDao, SysFile> implements SysFileService {

    @Autowired
    private HttpRequestUtil httpRequestUtil;
    @Autowired
    private SecurityUtil securityUtil;
    @Autowired
    private TencentCosService tencentCosService;
    @Autowired
    private DouyinTosService douyinTosService;

    @Autowired
    private UploadUtil uploadUtil;
    @Autowired
    private SysFileDao sysFileDao;
    @Autowired
    private SysFileCategoryDao sysFileCategoryDao;
    @Autowired
    private SysCommonService sysCommonService;

    // [方法] 设置缩略图 (参数)
    // 不同的云环境 (target)，缩略图配置也不一样
    //   -1:本地:
    //   1:腾讯云: https://cloud.tencent.com/document/product/436/113295
    //   2:阿里云:
    //   3:抖音云: https://www.volcengine.com/docs/6349/153626
    private SysFile setThumbUrl(SysFile sysFile, Integer width, Integer height, String backgroundColor) {
        if (sysFile.getContent_type() != null) {
            if (sysFile.getContent_type().toLowerCase().contains("image")) {
                if (StrUtil.isEmpty(sysFile.getUpload_id())) {
                    // 本地上传
                    if (sysFile.getTarget() == -1) {
                        sysFile.setUrl_thumb(sysFile.getUrl() + "?w=" + width + "&h=" + height);
                    }
                    // 腾讯云 (color值通过base64加密, #f8f8f8)
                    if (sysFile.getTarget() == 1) {
                        backgroundColor = "#" + backgroundColor;
                        sysFile.setUrl_thumb(sysFile.getUrl() + "?imageMogr2/thumbnail/" + width + "x" + height + "/pad/1/color/" + Base64.encode(backgroundColor));
                    }
                    // 抖音云
                    if (sysFile.getTarget() == 3) {
                        sysFile.setUrl_thumb(sysFile.getUrl() + "?x-tos-process=image/resize,w_" + width + ",h_" + height + ",m_pad,color_" + backgroundColor);
                    }
                }
            }
        }
        return sysFile;
    }

    /**
     * 获取文件列表
     */
    @Override
    public PageEntity selectUploadFileList(SysFile sysFile) {
        PageUtils.startPage();  // 分页
        List<SysFile> sysFileList = sysFileDao.selectUploadFileList(sysFile);

        // 1) 完成分页实体渲染
        PageEntity pageEntity = new PageInfoResult(sysFileList).toEntity();

        // 2) 分页列表格式化
        // [Common] 根据 Tag 获得 Options
        // JSONArray COMMON_OPTIONS = sysCommonService.getCommonOptionByTag("UPLOAD_TARGET");
        // 遍历列表，赋值公共值翻译
        sysFileList = sysFileList.stream().map(item -> {
            // 查询出 上传存储介质(target) 的翻译
            // String target_label = Convert.toStr(sysCommonService.getLabelByValue(COMMON_OPTIONS, item.getTarget()));
            String target_label = TargetEnums.targetToLabel(item.getTarget());
            item.setTarget_label(target_label);
            return item;
        }).collect(Collectors.toList());

        // 3) 分页实体重新赋值
        List<Object> objectList = sysFileList.stream().map(item -> (Object) item).collect(Collectors.toList());
        pageEntity.setList(objectList);

        return pageEntity;
    }

    @Override
    public Map<String, Object> selectUploadTarget() {
        Integer UPLOAD_TARGET = Convert.toInt(sysCommonService.getCommonByTag("UPLOAD_TARGET"));
        String target_label = TargetEnums.targetToLabel(UPLOAD_TARGET);
        Map<String, Object> resp = new LinkedHashMap<>();
        resp.put("target", UPLOAD_TARGET);
        resp.put("target_label", target_label);
        return resp;
    }

    // [方法] 上传事件
    private SysFile uploadEvent(MultipartFile multipartFile, Long category_id, Integer is_watermark, Integer target) {
        try {

            String filename = multipartFile.getOriginalFilename();
            if (filename.length() > 50) throw new CustException("文件名长度不能超过 50 字符");

            SysFileResult uploadResult = new SysFileResult();

            // target: 上传目标 (-1:本地, 1:腾讯云, 2:阿里云, 3.抖音云)
            if (target == -1) {
                uploadResult = uploadUtil.put(multipartFile);
            }
            if (target == 1) {
                // [腾讯云-上传对象]
                uploadResult = tencentCosService.putObject(multipartFile, null, is_watermark);
            }
            if (target == 3) {
                // [抖音云-上传对象]
                uploadResult = douyinTosService.putObject(multipartFile, null);
            }

            // [新增] 上传文件记录
            SysFile sysFileEntity = new SysFile();
            sysFileEntity.setCategory_id(category_id);
            sysFileEntity.setRequest_id(uploadResult.getRequest_id());
            sysFileEntity.setUser_id(httpRequestUtil.getUserId());
            sysFileEntity.setObject_key(uploadResult.getKey());

            // 文件名
//            sysFileEntity.setName(FileNameUtil.getName(uploadResult.getKey()));


            String filename_prefix = StrUtil.subBefore(filename, '.', true);
            String filename_suffix = StringUtils.getFilenameExtension(filename);
            /*
                filename = 200x134.png
                filename_prefix = 200x134
                filename_suffix = png
             */

            // 查询如果有同名文件，则在文件中加入数量命名
            LambdaQueryWrapper<SysFile> wrapper = new LambdaQueryWrapper<>();
            // 构造正则表达式 (匹配同名、同名(数量))
            String regex = "^" + filename_prefix + "(\\(\\d+\\))?\\." + filename_suffix + "$";
            wrapper.apply("name REGEXP {0}", regex);
            Long count = sysFileDao.selectCount(wrapper);
            if (count > 0) {
                sysFileEntity.setName(filename_prefix + "(" + count + ")." + filename_suffix);
            } else {
                sysFileEntity.setName(filename_prefix + "." + filename_suffix);
            }


            sysFileEntity.setContent_type(multipartFile.getContentType());
            if (target != -1) {
                // 非本地的 (Cos, Tos, ..)
                sysFileEntity.setUrl(uploadResult.getDomain() + "/" + uploadResult.getKey());
            } else {
                // 本地的
                sysFileEntity.setUrl(uploadResult.getDomain());
            }
            sysFileEntity.setSize(multipartFile.getSize());
            if (StrUtil.isNotEmpty(uploadResult.getE_tag())) {
                sysFileEntity.setMd5(uploadResult.getE_tag().replace("\"", ""));
            }
            sysFileEntity.setTarget(target);
            sysFileEntity.setTarget_label(TargetEnums.targetToLabel(target));

            // 获得公共配置
            List<SysCommon> sysCommonList = sysCommonService.getCommonByCategory("UPLOAD");
            AtomicReference<Integer> UPLOAD_TARGET = new AtomicReference<>();
            AtomicReference<Integer> UPLOAD_THUMB_SIZE = new AtomicReference<>();
            sysCommonList.stream().forEach(sysCommon -> {
                if (sysCommon.getTag().equals("UPLOAD_TARGET")) UPLOAD_TARGET.set(Convert.toInt(sysCommon.getValue()));
                if (sysCommon.getTag().equals("UPLOAD_THUMB_SIZE")) UPLOAD_THUMB_SIZE.set(Convert.toInt(sysCommon.getValue()));
            });
            System.out.println("[系统配置] 上传目标(-1:本地, 1:腾讯云, 2:阿里云, 3.抖音云): " + UPLOAD_TARGET);
            System.out.println("[系统配置] 图片的缩略图宽高尺寸 (px): " + UPLOAD_THUMB_SIZE);

            // 设置缩略图
            sysFileEntity = setThumbUrl(sysFileEntity, UPLOAD_THUMB_SIZE.get(), UPLOAD_THUMB_SIZE.get(), StyleEnums.THUMB_BACKGROUND.getValue());

            LocalDateTime nowLocalDateTime = (new DateTime()).toInstant().atZone(ZoneId.of("UTC")).toLocalDateTime();
            sysFileEntity.setCreate_time(nowLocalDateTime);
            sysFileEntity.setUpdate_time(nowLocalDateTime);

            sysFileDao.insert(sysFileEntity);

            return sysFileEntity;

        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 上传文件 (单文件大小不超过 n)
     * - target: 上传目标 (-1:本地, 1:腾讯云, 2:阿里云, 3.抖音云)
     */
    @Override
    public SysFile uploadSmall(MultipartFile multipartFile, Long category_id, Integer is_watermark) {

        List<SysCommon> sysCommonList = sysCommonService.getCommonByCategory("UPLOAD");

        AtomicReference<Integer> UPLOAD_TARGET = new AtomicReference<>();
        AtomicReference<Long> UPLOAD_MAX_SIZE_MB = new AtomicReference<>();
        AtomicReference<Integer> UPLOAD_THUMB_SIZE = new AtomicReference<>();
        AtomicReference<Boolean> UPLOAD_MD5_DUPLICATE = new AtomicReference<>();

        sysCommonList.stream().forEach(sysCommon -> {
            if (sysCommon.getTag().equals("UPLOAD_TARGET")) UPLOAD_TARGET.set(Convert.toInt(sysCommon.getValue()));
            if (sysCommon.getTag().equals("UPLOAD_MAX_SIZE_MB")) UPLOAD_MAX_SIZE_MB.set(Convert.toLong(sysCommon.getValue()));
            if (sysCommon.getTag().equals("UPLOAD_THUMB_SIZE")) UPLOAD_THUMB_SIZE.set(Convert.toInt(sysCommon.getValue()));
            if (sysCommon.getTag().equals("UPLOAD_MD5_DUPLICATE")) UPLOAD_MD5_DUPLICATE.set(Convert.toBool(sysCommon.getValue()));
        });

        System.out.println("[系统配置] 上传目标(-1:本地, 1:腾讯云, 2:阿里云, 3.抖音云): " + UPLOAD_TARGET);
        System.out.println("[系统配置] 单文件上传大小限制(MB): " + UPLOAD_MAX_SIZE_MB);
        System.out.println("[系统配置] 图片的缩略图宽高尺寸 (px): " + UPLOAD_THUMB_SIZE);
        System.out.println("[系统配置] 是否启用文件MD5查重: " + UPLOAD_MD5_DUPLICATE);

        // 判断文件是否超过大小
        Long MAX_SIZE = UPLOAD_MAX_SIZE_MB.get() * 1024 * 1024;
        if (multipartFile.getSize() > MAX_SIZE) {
            throw new CustException("上传文件不能大于 " + MAX_SIZE / 1024 / 1024 + " MB，请使用大文件上传功能");
        }

        try {

            // [系统配置] 是否启用文件MD5查重 (仅判断用户自己上传过的文件)
            // - 存在，则根据文件MD5 判断是否上传过文件 (仅更新时间，不上传已存在的文件，允许更新文件分类)
            // - 存在，如果存在两个相同 md5 以上的文件，则需要排重后再上传 (如果是不同用户
            // - 不存在，则走上传流程
            SysFile sysFileEntity = null;
            if (UPLOAD_MD5_DUPLICATE.get()) {

                String md5 = DigestUtil.md5Hex(multipartFile.getInputStream());

                // 排除文件异常的情况（出现两个以上相同MD5的文件）
                LambdaQueryWrapper<SysFile> wrapperFile = new LambdaQueryWrapper<>();
                wrapperFile.eq(SysFile::getMd5, md5);
                wrapperFile.eq(SysFile::getUser_id, SecurityUtil.getUserId());
                wrapperFile.isNull(SysFile::getUpload_id);
                List<SysFile> sysFileEntityList = sysFileDao.selectList(wrapperFile);
                if (sysFileEntityList != null && sysFileEntityList.size() > 1) {
                    throw new CustException("存在 " + sysFileEntityList.size() + " 个相同MD5 (" + md5 + ") 的文件", ResultEnum.STATUS_CONFLICT.getCode());
                }

                if (sysFileEntityList != null && sysFileEntityList.size() > 0) {
                    // 将已存在的文件，赋值
                    sysFileEntity = sysFileEntityList.get(0);
                    // [DB] 更新文件 (支持更换文件分类)
                    sysFileEntity.setIs_exist(true);
                    sysFileEntity.setCategory_id(category_id);

                    LocalDateTime nowLocalDateTime = (new DateTime()).toInstant().atZone(ZoneId.of("UTC")).toLocalDateTime();
                    sysFileEntity.setUpload_time(nowLocalDateTime);

                    sysFileDao.updateById(sysFileEntity);
                } else {
                    // [DB] 创建新的文件
                    sysFileEntity = uploadEvent(multipartFile, category_id, is_watermark, UPLOAD_TARGET.get());
                    // [格式化] 封面 (图片类型)
                    sysFileEntity = setThumbUrl(sysFileEntity, UPLOAD_THUMB_SIZE.get(), UPLOAD_THUMB_SIZE.get(), StyleEnums.THUMB_BACKGROUND.getValue());
                }
                return sysFileEntity;

            } else {
                // 不开启 MD5秒 传，则直接初始化分块
                // [方法] 上传事件
                sysFileEntity = uploadEvent(multipartFile, category_id, is_watermark, UPLOAD_TARGET.get());
                // [格式化] 封面 (图片类型)
                sysFileEntity = setThumbUrl(sysFileEntity, UPLOAD_THUMB_SIZE.get(), UPLOAD_THUMB_SIZE.get(), StyleEnums.THUMB_BACKGROUND.getValue());
                return sysFileEntity;
            }

        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }


    /**
     * 删除存储桶对象 (单个)
     * target: 上传目标 (-1:本地, 1:腾讯云, 2:阿里云, 3.抖音云)
     */
    @Override
    public void deleteObject(String object_key, Integer target) {
        if (target == -1) {
            // [本地] 删除文件
            uploadUtil.delete(object_key);
        }
        if (target == 1) {
            // [腾讯云] 删除对象
            tencentCosService.deleteObject(object_key);
            System.out.println("Delete tencent cos object: " + object_key);
        }
        if (target == 3) {
            // [抖音云] 删除对象
            douyinTosService.deleteObject(object_key);
            System.out.println("Delete douyin tos object: " + object_key);
        }
    }
    /**
     * 删除存储桶对象 (批量)
     */
    @Override
    public void deleteObjects(List<ObjectKeyEntity> list) {
        list.stream().forEach(item -> {
            if (item.getTarget() == 1) {
                // [腾讯云] 删除对象
                List<String> object_keys = list.stream().map(it -> it.getObject_key()).collect(Collectors.toList());
                tencentCosService.deleteObjects(object_keys);
                System.out.println("Delete tencent cos object (batch): " + object_keys);
            }
            if (item.getTarget() == 3) {
                // [抖音云] 删除对象
                List<String> object_keys = list.stream().map(it -> it.getObject_key()).collect(Collectors.toList());
                douyinTosService.deleteObjects(object_keys);
                System.out.println("Delete douyin tos object (batch): " + object_keys);
            }
        });
    }

    /**
     * 删除文件 (包括缩略图，如果有的话)
     */
    @Override
    public Map<String, Object> removeUploadFile(SysFile sysFile, SysFile querySysFile) {

        String object_key = querySysFile.getObject_key();

        // [Delete] 删除文件记录
        sysFileDao.delete(new LambdaQueryWrapper<SysFile>().eq(SysFile::getObject_key, object_key));

        // [异步任务] 创建一个 CompletableFuture 来执行异步任务
        CompletableFuture.runAsync(() -> {
            deleteObject(querySysFile.getObject_key(), querySysFile.getTarget());
        });

        return Map.of("object_key", object_key);
    }

    /**
     * 删除文件 (批量)
     */
    @Override
    public Map<String, Object> removeUploadFileBatch(SysFile sysFile, List<SysFile> querySysFileList) {

        // 判断是否存在
        List<String> object_keys = sysFile.getObject_keys();

        // [Delete] 批量删除
        sysFileDao.delete(new LambdaQueryWrapper<SysFile>().in(SysFile::getObject_key, object_keys));

        // [异步任务] 创建一个 CompletableFuture 来执行异步任务
        CompletableFuture.runAsync(() -> {
            querySysFileList.stream().forEach(entity -> {
                deleteObject(entity.getObject_key(), entity.getTarget());
            });
        });

        return Map.of("object_keys", object_keys);
    }


    /**
     * 编辑文件 (名称、文件分类)
     * - 判断文件、文件分类是否存在
     * - 判断文件、文件分类是否当前用户所有
     */
    @Override
    public Map<String, Object> updateUploadFile(SysFile sysFile) {

        // 查询文件是否存在
        LambdaQueryWrapper<SysFile> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysFile::getUser_id, sysFile.getUser_id());
        wrapper.eq(SysFile::getId, sysFile.getId());
        Boolean isFileExist = sysFileDao.exists(wrapper);
        if (!isFileExist) throw new CustException("文件不存在");

        // 查询文件分类是否存在
        if (sysFile.getCategory_id() != null) {
            LambdaQueryWrapper<SysFileCategory> wrapperCategory = new LambdaQueryWrapper<>();
            wrapperCategory.eq(SysFileCategory::getUser_id, sysFile.getUser_id());
            wrapperCategory.eq(SysFileCategory::getId, sysFile.getCategory_id());
            Boolean isFileCategoryExist = sysFileCategoryDao.exists(wrapperCategory);
            if (!isFileCategoryExist) throw new CustException("文件分类不存在");
        }

        // [DB] 更新文件
        sysFileDao.updateFile(sysFile);

        return Map.of("id", sysFile.getId());
    }


    /**
     * 编辑文件 (批量)
     * - 文件、文件分类必须存在，且是该用户所有
     */
    @Override
    public Map<String, Object> updateUploadFileBatch(SysFile sysFile) {

        List<Long> ids = sysFile.getIds();
        Long category_id = sysFile.getCategory_id();

        // 判断 文件分类ID 是否存在
        if (category_id != null) {
            Boolean isExist = sysFileCategoryDao.exists(new LambdaQueryWrapper<SysFileCategory>().eq(SysFileCategory::getId, category_id));
            if (!isExist) throw new CustException("文件分类不存在");
        }

        // [DB] 批量更新 分类ID
        LambdaUpdateWrapper<SysFile> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(SysFile::getUser_id, sysFile.getUser_id()).in(SysFile::getId, ids);
        wrapper.set(SysFile::getCategory_id, category_id);
        sysFileDao.update(null, wrapper);

        return Map.of("ids", ids);
    }

    // URL转存 (因为会用到 高级上传 -> 进度监听，需要从外部传入 user_id
    @Override
    public SysFileResult urlToUploadFile(String origin_url, Long input_user_id) {

        Integer UPLOAD_TARGET = Convert.toInt(sysCommonService.getCommonByTag("UPLOAD_TARGET"));

        SysFileResult sysFileResult = null;

        Long user_id = input_user_id == null ? SecurityUtil.getUserId() : input_user_id;

        // target: 上传目标 (-1:本地, 1:腾讯云, 2:阿里云, 3.抖音云)
        if (UPLOAD_TARGET == 1) {
            sysFileResult = tencentCosService.urlToCOS(origin_url, null, user_id);
        }
        // 3: 抖音云
        if (UPLOAD_TARGET == 3) {
            sysFileResult = douyinTosService.urlToTOS(origin_url, null, user_id);
        }
        if (sysFileResult == null) throw new CustException("上传失败");

        // [DB] 创建文件
        SysFile sysFileEntity = new SysFile();
        sysFileEntity.setRequest_id(sysFileEntity.getRequest_id());
        sysFileEntity.setUser_id(user_id);

        try {
            URL parsed_url = new URL(origin_url);
            sysFileEntity.setName(StrUtil.subAfter(parsed_url.getPath(), '/', true));
        } catch (Exception e) {
            throw new CustException(e.getMessage());
        }

        sysFileEntity.setUrl(sysFileResult.getDomain() + "/" + sysFileResult.getKey());
        sysFileEntity.setObject_key(sysFileResult.getKey());
        sysFileEntity.setSize(sysFileResult.getSize());
        sysFileEntity.setTarget(UPLOAD_TARGET);
        sysFileEntity.setTarget_label(TargetEnums.targetToLabel(UPLOAD_TARGET));

        LocalDateTime nowLocalDateTime = (new DateTime()).toInstant().atZone(ZoneId.of("UTC")).toLocalDateTime();
        sysFileEntity.setUpload_time(nowLocalDateTime);

        sysFileDao.insert(sysFileEntity);

        return sysFileResult;
    }


    /**
     * 根据 MD5 获取文件列表 (我的) (不显示未完成的分块文件)
     */
    @Override
    public List<Map<String, Object>> getUploadFileListByMd5(SysFile sysFile) {
        SysFile entity = new SysFile();
        entity.setUser_id(sysFile.getUser_id());
        entity.setMd5(sysFile.getMd5());
        return sysFileDao.selectUploadFileSimple(entity);
    }

    /**
     * 合并重复 MD5 文件 { md5, ids }
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> mergeFileByMd5(SysFileMergeByMd5 sysFileMergeByMd5) {

        Long user_id = sysFileMergeByMd5.getUser_id();
        List<String> object_keys = sysFileMergeByMd5.getObject_keys();
        String target_object_key = sysFileMergeByMd5.getTarget_object_key();
        String target_file_name = sysFileMergeByMd5.getTarget_file_name();

        // 判断 target_object 是否存在于 object_keys 中
        boolean exists = CollectionUtil.contains(object_keys, target_object_key);
        if (!exists) throw new CustException("合并目标文件ID不存在于列表中");
        // 判断权限 (需要子权限或超级管理员)
        if (!SecurityUtil.isSuper() && !securityUtil.hasPermission("1.1.5")) {
            throw new CustException(SecurityEnum.NOAUTH);
        }

        // [DB] 查询文件列表 (不包含 target_object_key、当前用户ID、upload_id 为空)
        LambdaQueryWrapper<SysFile> selectWrapper = new LambdaQueryWrapper<>();
        selectWrapper.in(SysFile::getUser_id, user_id);
        // 过滤一个没有 target_object_key 的 object_keys 集合
        List<String> file_object_keys_without_target = object_keys.stream().filter(object_key -> !object_key.equals(target_object_key)).collect(Collectors.toList());
        selectWrapper.in(SysFile::getObject_key, file_object_keys_without_target);
        selectWrapper.isNull(SysFile::getUpload_id);
        List<SysFile> querySysFileList = sysFileDao.selectList(selectWrapper);
        if (querySysFileList.size() == 0) {
            throw new CustException("选中的文件不存在", ResultEnum.PARAMETER_EXCEPTION.getCode(), "Field: object_keys");
        }

        // [DB] 更新文件命名 (及上传时间)
        LambdaQueryWrapper<SysFile> updateWrapper = new LambdaQueryWrapper<>();
        updateWrapper.eq(SysFile::getObject_key, target_object_key);
        SysFile updateEntity = new SysFile();
        updateEntity.setName(target_file_name);

        LocalDateTime nowLocalDateTime = (new DateTime()).toInstant().atZone(ZoneId.of("UTC")).toLocalDateTime();
        updateEntity.setUpload_time(nowLocalDateTime);

        sysFileDao.update(updateEntity, updateWrapper);

        // [DB] 批量删除 (除了 target_object_key 外的文件)
        List<String> delete_object_keys = querySysFileList.stream().map(entity -> entity.getObject_key()).collect(Collectors.toList());
        System.out.println(delete_object_keys);
        sysFileDao.delete(new LambdaQueryWrapper<SysFile>().in(SysFile::getObject_key, delete_object_keys));

        // [异步任务] 创建一个 CompletableFuture 来执行异步任务
        CompletableFuture.runAsync(() -> {
            querySysFileList.stream().forEach(entity -> {
                deleteObject(entity.getObject_key(), entity.getTarget());
            });
        });

        Map<String, Object> resp = new LinkedHashMap<>();
        resp.put("delete_object_keys", delete_object_keys);
        resp.put("target_object_key", target_object_key);
        return resp;
    }

}
