package com.ai.da.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.ai.da.common.config.exception.BusinessException;
import com.ai.da.common.constant.CommonConstant;
import com.ai.da.common.constant.ModelConstants;
import com.ai.da.common.context.UserContext;
import com.ai.da.common.enums.CollectionLevel1TypeEnum;
import com.ai.da.common.enums.CreditsEventsEnum;
import com.ai.da.common.enums.DesignTypeEnum;
import com.ai.da.common.enums.LibraryLevel1TypeEnum;
import com.ai.da.common.response.PageBaseResponse;
import com.ai.da.common.response.ResultEnum;
import com.ai.da.common.utils.*;
import com.ai.da.mapper.primary.*;
import com.ai.da.mapper.primary.entity.*;
import com.ai.da.mapper.primary.entity.Collection;
import com.ai.da.mapper.secondary.AttributeRetrievalMapper;
import com.ai.da.mapper.secondary.entity.AttributeRecognitionJSON;
import com.ai.da.model.dto.*;
import com.ai.da.model.enums.CollectionType;
import com.ai.da.model.enums.Module;
import com.ai.da.model.vo.*;
import com.ai.da.python.PythonService;
import com.ai.da.service.*;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;

import java.util.Comparator;

import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.base.Function;
import com.google.gson.Gson;
import io.minio.errors.MinioException;
import io.netty.util.internal.StringUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 服务实现类
 *
 * @author yanglei
 * @since 2022-09-30
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class UserLikeGroupServiceImpl extends ServiceImpl<UserLikeGroupMapper, UserLikeGroup> implements UserLikeGroupService {
    private final UserLikeGroupMapper userLikeGroupMapper;
    private final AccountService accountService;
    private final CollectionService collectionService;
    private final UserLikeService userLikeService;
    private final WorkspaceService workspaceService;
    private final UserLikeMapper userLikeMapper;
    private final MinioUtil minioUtil;
    private final TDesignPythonOutfitMapper designPythonOutfitMapper;
    private final DesignMapper designMapper;
    private final MoodboardPositionService moodboardPositionService;
    private final SysFileMapper sysFileMapper;
    private final LibraryMapper libraryMapper;
    private final GenerateDetailMapper generateDetailMapper;
    private final PortfolioMapper portfolioMapper;
    private final TagsMapper tagsMapper;
    private final DesignItemDetailService designItemDetailService;
    private final CollectionElementMapper collectionElementMapper;
    private final AttributeRetrievalMapper attributeRetrievalMapper;
    private final ProductImageAttributeMapper productImageAttributeMapper;
    private final CollectionSortMapper collectionSortMapper;
    private final ClassificationService classificationService;
    //    private ProjectMapper projectMapper;
    private final ProjectService projectService;
    private final LibraryModelPointMapper libraryModelPointMapper;
    private final LibraryService libraryService;
    private final BrandDNAMapper brandDNAMapper;
    private final BrandRelLibraryMapper brandRelLibraryMapper;
    private final ThreeDLayoutMapper threeDLayoutMapper;
    private final ThreeDPatternLayoutMapper threeDPatternLayoutMapper;
    private final ThreeDDetailMapper threeDDetailMapper;
    private final ThreeDSimpleMapper threeDSimpleMapper;
    private final ThreeDModuleMapper threeDModuleMapper;
    private final ProductImageService productImageService;
    private final CollectionElementRelModelMapper collectionElementRelModelMapper;
    private final CollectionSortService collectionSortService;
    private final GenerateService generateService;
    private final ToProductElementMapper toProductElementMapper;
    private final ToProductImageRecordMapper toProductImageRecordMapper;
    private final ToProductImageResultMapper toProductImageResultMapper;
    private final ToProductImageResultService toProductImageResultService;
    private final CloudTaskMapper cloudTaskMapper;
    private final PythonService pythonService;
    private final CreditsService creditsService;
    private final PoseTransformationMapper poseTransformationMapper;
    private final ExportFileMapper exportFileMapper;
    private final DesignItemDetailCanvasMapper designItemDetailCanvasMapper;
    @Value("${redis.key.generateResult}")
    private String generateResultKey;

    @Override
    public void deleteUserGroup(Long userGroupId) {
        UserLikeGroup group = getById(userGroupId);
        if (Objects.isNull(group)) {
            throw new BusinessException("history.not.found");
        }
        userLikeGroupMapper.deleteById(userGroupId);
    }

    @Override
    public HistoryUpdateVO updateUserGroupName(Long userGroupId, String userGroupName, String timeZone) {
        UserLikeGroup group = getById(userGroupId);
        if (Objects.isNull(group)) {
            throw new BusinessException("history.not.found");
        }
        QueryWrapper<UserLikeGroup> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id", userGroupId);
        UserLikeGroup userLikeGroup = new UserLikeGroup();
        userLikeGroup.setName(userGroupName);
        userLikeGroup.setUpdateDate(DateUtil.getByTimeZone(timeZone));
        log.info("跟新group名字###{}###时间是###{}", userLikeGroup.getUpdateDate(), TimeZone.getDefault());
        userLikeGroupMapper.update(userLikeGroup, queryWrapper);
        return new HistoryUpdateVO(userLikeGroup.getName(), userLikeGroup.getUpdateDate().getTime());
    }

//    public static void main(String[] args) {
//        System.out.println(TimeZone.getDefault());
//        Date kolkata =DateUtil.getByTimeZone("Asia/Kolkata");
//        Date shanghai =DateUtil.getByTimeZone("Asia/Shanghai");
//        System.out.println(kolkata);
//        System.out.println(shanghai);
//        System.out.println(kolkata.getTime());
//        System.out.println(shanghai.getTime());
//        System.out.println(kolkata.getTime() == shanghai.getTime());
//    }

    private List<UserLikeGroup> selectByUserId(Long userId) {
        QueryWrapper<UserLikeGroup> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("accountId", userId);
        return userLikeGroupMapper.selectList(queryWrapper);
    }

    @Override
    public Long insertUserGroup(Long userId, Long collectionId, String timeZone, Long projectId) {
        UserLikeGroup userLikeGroup = new UserLikeGroup();
        //默认当前时间
        userLikeGroup.setName(DateUtil.dateToStr(new Date(), DateUtil.YYYY_MM_DD_HH_MM_SS));
        userLikeGroup.setCreateDate(DateUtil.getByTimeZone(timeZone));
        userLikeGroup.setUpdateDate(DateUtil.getByTimeZone(timeZone));
        userLikeGroup.setAccountId(userId);
        userLikeGroup.setCollectionId(collectionId);
        userLikeGroup.setOriginal(1);
        userLikeGroup.setProjectId(projectId);
        userLikeGroupMapper.insertUserLikeGroup(userLikeGroup);
        return userLikeGroup.getId();
    }

    @Override
    public UserLikeChooseVO choose(Long userGroupId) {
        UserLikeGroup group = getById(userGroupId);
        if (Objects.isNull(group)) {
            throw new BusinessException("history.not.found");
        }
        List<UserLikeVO> userLikeVOS = userLikeService.getGroupDetail(userGroupId);
        String sex = null;

        QueryWrapper<CollectionSort> userLikeSortQw = new QueryWrapper<>();
        userLikeSortQw.lambda().eq(CollectionSort::getUserLikeGroupId, userGroupId);
        List<CollectionSort> userLikeSortList = collectionSortMapper.selectList(userLikeSortQw);
        if (CollectionUtil.isEmpty(userLikeSortList)) {
            Integer sort = 1;
            for (UserLikeVO userLikeVO : userLikeVOS) {
                CollectionSort userLikeSort = new CollectionSort();
                userLikeSort.setUserLikeId(userLikeVO.getId());
                userLikeSort.setUserLikeGroupId(userGroupId);
                userLikeSort.setSort(sort);
                collectionSortMapper.insert(userLikeSort);
                sort++;
            }
        }

        userLikeVOS.forEach(o -> {
            TDesignPythonOutfit tDesignPythonOutfit1 = designPythonOutfitMapper.selectById(o.getDesignOutfitId());
            o.setUrl(tDesignPythonOutfit1.getDesignUrl());
            if (o.getUrl().contains("/")) {
                int index = o.getUrl().lastIndexOf("/");
                o.setPictureName(o.getUrl().substring(index + 1));
            }
            o.setDesignOutfitUrl(minioUtil.getPreSignedUrl(o.getUrl(), 24 * 60));
            QueryWrapper<TDesignPythonOutfit> qw = new QueryWrapper<>();
            qw.lambda().eq(TDesignPythonOutfit::getDesignItemId, o.getDesignItemId());
            List<TDesignPythonOutfit> tDesignPythonOutfits = designPythonOutfitMapper.selectList(qw);
            if (CollectionUtil.isNotEmpty(tDesignPythonOutfits)) {
                TDesignPythonOutfit tDesignPythonOutfit = tDesignPythonOutfits.get(0);
                o.setDesignOutfitId(tDesignPythonOutfit.getId());
            }

            QueryWrapper<CollectionSort> userLikeSortQueryWrapper = new QueryWrapper<>();
            userLikeSortQueryWrapper.lambda().eq(CollectionSort::getUserLikeId, o.getId());
            List<CollectionSort> userLikeSorts = collectionSortMapper.selectList(userLikeSortQueryWrapper);
            if (CollectionUtil.isNotEmpty(userLikeSorts)) {
                CollectionSort userLikeSort = userLikeSorts.get(0);
                o.setSort(userLikeSort.getSort());
                o.setUserLikeSortId(userLikeSort.getId());
            }
        });
        UserLikeCollectionVO userLikeCollection = collectionService.chooseCollection(group.getCollectionId());
        Integer beenPublished = 0;
        QueryWrapper<Portfolio> qw = new QueryWrapper<>();
        qw.lambda().eq(Portfolio::getUserLikeGroupSourceId, userGroupId);
        List<Portfolio> portfolios = portfolioMapper.selectList(qw);
//        Portfolio portfolio = new Portfolio();
        PortfolioDTO portfolioDTO = new PortfolioDTO();
        if (CollectionUtil.isNotEmpty(portfolios)) {
//            portfolio = portfolios.get(0);
            portfolioDTO = CopyUtil.copyObject(portfolios.get(0), PortfolioDTO.class);
            beenPublished = 1;
            portfolioDTO.setTagsDTO(tagsMapper.getTagByPortfolioId(portfolioDTO.getId()));
        }
        return new UserLikeChooseVO(userGroupId, userLikeVOS, userLikeCollection, sex, beenPublished, portfolioDTO);
    }

    @Override
    public ProjectChooseVO choose(ProjectDTO projectDTO) {

        Project project = projectService.getById(projectDTO.getId());

        Long workspaceId = workspaceService.getByProjectId(project.getId());
        WorkspaceVO workspaceVO = new WorkspaceVO();
        if (null != workspaceId) {
            workspaceVO = workspaceService.getByIdForProject(workspaceId);
        }

        String process = project.getProcess();
        String name = project.getName();

        UserLikeGroup userLikeGroup = userLikeService.getUserLikeGroupByProjectId(project.getId());
        Long collectionId = null;
        if (Objects.nonNull(userLikeGroup)) {
            Collection collection = collectionService.getById(userLikeGroup.getCollectionId());
            if (Objects.nonNull(collection)) {
                collectionId = collection.getId();
            }
        }

        Integer beenPublished = 0;
        QueryWrapper<Portfolio> qw = new QueryWrapper<>();
        qw.lambda().eq(Portfolio::getProjectId, projectDTO.getId());
        List<Portfolio> portfolios = portfolioMapper.selectList(qw);
//        Portfolio portfolio = new Portfolio();
        PortfolioDTO portfolioDTO = new PortfolioDTO();
        if (CollectionUtil.isNotEmpty(portfolios)) {
//            portfolio = portfolios.get(0);
            portfolioDTO = CopyUtil.copyObject(portfolios.get(0), PortfolioDTO.class);
            beenPublished = 1;
            portfolioDTO.setTagsDTO(tagsMapper.getTagByPortfolioId(portfolioDTO.getId()));
        }

        return new ProjectChooseVO(projectDTO.getId(), name, workspaceVO, process, collectionId, beenPublished, portfolioDTO);
    }

    @Override
    public UserLikeGroup getByProjectId(Long projectId) {
        QueryWrapper<UserLikeGroup> qw = new QueryWrapper<>();
        qw.lambda().eq(UserLikeGroup::getProjectId, projectId);
        List<UserLikeGroup> userLikeGroupList = userLikeGroupMapper.selectList(qw);
        if (CollectionUtil.isEmpty(userLikeGroupList)) {
            return null;
        }
        return userLikeGroupList.get(0);
    }

    @Override
    public void deleteTrialData(Long userId) {
        QueryWrapper<UserLikeGroup> qw = new QueryWrapper<>();
        qw.lambda().eq(UserLikeGroup::getAccountId, userId);
        List<Long> userLikeGroupIdList = userLikeGroupMapper.selectList(qw).stream()
                .map(UserLikeGroup::getId)
                .collect(Collectors.toList());
        userLikeGroupMapper.delete(qw);
        if (CollectionUtil.isNotEmpty(userLikeGroupIdList)) {
            QueryWrapper<UserLike> userLikeQueryWrapper = new QueryWrapper<>();
            userLikeQueryWrapper.lambda().in(UserLike::getUserLikeGroupId, userLikeGroupIdList);
            userLikeMapper.delete(userLikeQueryWrapper);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateDate(Long id, String timeZone) {
        UpdateWrapper<UserLikeGroup> uw = new UpdateWrapper<>();
        uw.eq("id", id);
        uw.set("update_date", DateUtil.getByTimeZone(timeZone));

        baseMapper.update(null, uw);
    }

    @Override
    public Long exportSave(MultipartFile file, Long projectId, String module, Long designItemDetailId) {
        AuthPrincipalVo userHolder = UserContext.getUserHolder();
        if (Objects.isNull(projectId) && !module.equals("designItemDetail")) {
            log.warn("用户 {} 保存 {} 模块的画布时, projectId为空", userHolder.getId(), module);
            throw new BusinessException("project.id.cannot.be.empty", ResultEnum.PROMPT.getCode());
        }

        QueryWrapper<ExportFile> qw = new QueryWrapper<>();
        List<ExportFile> exportFiles = null;
        if (Objects.nonNull(projectId)) {
            qw.lambda().eq(ExportFile::getProjectId, projectId);
            qw.lambda().eq(ExportFile::getModule, module);
            exportFiles = exportFileMapper.selectList(qw);
        } else if (Objects.nonNull(designItemDetailId)) {
            DesignItemDetailCanvas designItemDetailCanvas = designItemDetailService.getDIDCByDesignItemDetailId(designItemDetailId);
            if (Objects.nonNull(designItemDetailCanvas) && Objects.nonNull(designItemDetailCanvas.getExportFileId())) {
                qw.lambda().eq(ExportFile::getId, designItemDetailCanvas.getExportFileId());
                qw.lambda().eq(ExportFile::getModule, module);
                exportFiles = exportFileMapper.selectList(qw);
            }
        }
//        String upload = minioUtil.upload("aida-users", userHolder.getId() + "/exportFile", file);

        ExportFile exportFile = null;
        if (CollectionUtil.isNotEmpty(exportFiles)) {
            exportFile = exportFiles.get(0);
            // 更新画布信息时，只重新上传图片，不用修改数据库url
            String url = exportFile.getUrl();
            String path = url.substring(url.indexOf("/") + 1);
            minioUtil.upload("aida-users", path, file, null);
//            exportFile.setUrl(upload);
//            exportFileMapper.updateById(exportFile);
        } else {
            String upload = minioUtil.upload("aida-users", userHolder.getId() + "/exportFile", file);
            exportFile = new ExportFile();
            exportFile.setProjectId(projectId);
            exportFile.setModule(module);
            exportFile.setUrl(upload);
            exportFileMapper.insert(exportFile);
            if (Objects.nonNull(designItemDetailId)) {
                designItemDetailService.saveDesignItemDetailCanvas(designItemDetailId, exportFile.getId());
            }
        }
        return exportFile.getId();
    }

    /**
     * 产品图像生成方法
     * 根据输入的设计元素和参数，生成对应的产品图像
     *
     * @param toProductImageDTO 产品图像生成请求参数
     * @return 生成的产品图像结果列表
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<ToProductImageResultVO> toProduct(ToProductImageDTO toProductImageDTO) {
        // 判断是否使用（高级模型）
        boolean advanced = !StringUtil.isNullOrEmpty(toProductImageDTO.getModelName())
                && toProductImageDTO.getModelName().equals(ModelConstants.ADVANCED);

        // 根据模型类型选择对应的积分消耗事件
        CreditsEventsEnum creditsEventsEnum = advanced ? CreditsEventsEnum.TO_PRODUCT_IMAGE_ADVANCED : CreditsEventsEnum.TO_PRODUCT_IMAGE;

        // 预扣除积分，检查用户积分是否足够本次生成消耗
        Boolean preDeduction = creditsService.creditsPreDeduction(creditsEventsEnum, toProductImageDTO.getToProductImageVOList().size());
        if (!preDeduction) {
            throw new BusinessException("remaining.credits.insufficient", ResultEnum.WARNING.getCode());
        }

        // 获取当前登录用户信息
        AuthPrincipalVo userHolder = UserContext.getUserHolder();

        // 获取项目ID并查找对应的用户喜欢组
        Long projectId = toProductImageDTO.getProjectId();
        UserLikeGroup userLikeGroup = getByProjectId(projectId);
        Long userLikeGroupId = null;

        // 创建产品图像记录对象，用于记录本次生成任务的基本信息
        ToProductImageRecord toProductImageRecord = new ToProductImageRecord();
        toProductImageRecord.setProjectId(projectId);
        if (Objects.nonNull(userLikeGroup)) {
            userLikeGroupId = userLikeGroup.getId();
            toProductImageRecord.setUserLikeGroupId(userLikeGroupId);
        }

        String prompt = toProductImageDTO.getPrompt();
        String advancedPrompt = buildAdvancedPrompt(projectId, prompt);
        // 初始化基础提示词，确保生成高质量的真实图像
        StringBuilder sb = new StringBuilder("The best quality, masterpiece, real image.");
        if (!StringUtil.isNullOrEmpty(prompt) && !advanced) {
            // 调用Python服务进行提示词翻译（中文转英文等）
            prompt = pythonService.promptTranslate(prompt);

            // 检查翻译后的提示词长度，限制在180个单词以内
            String[] words = prompt.split("\\s+");
            if (words.length > 180) {
                throw new BusinessException("Please keep your input text under 200 words. Thanks!");
            }
        }

        // 设置记录创建时间并保存原始提示词
        toProductImageRecord.setCreateTime(LocalDateTime.now());
        if (!StringUtils.isEmpty(toProductImageDTO.getPrompt())) {
            toProductImageRecord.setPrompt(toProductImageDTO.getPrompt());
        }
        // 将产品图像记录插入数据库
        toProductImageRecordMapper.insert(toProductImageRecord);

        // 初始化结果列表
        List<ToProductImageResultVO> result = new ArrayList<>();
        // 判断是否为儿童年龄组，用于后续生成不同的提示词
        boolean childFlag = !StringUtil.isNullOrEmpty(toProductImageDTO.getAgeGroup())
                && toProductImageDTO.getAgeGroup().equals("Child");
        // 循环计数器，用于生成唯一的任务ID
        int i = 0;

//        else {
//            s = "best quality, masterpiece. detailed, high-res, simple background, studio photography, extremely detailed, updo, detailed face, face, close-up, HDR, UHD, 8K realistic, Highly detailed, simple background, Studio lighting";
//        }
        // 遍历所有需要生成的产品图像元素
        for (ToProductImageVO toProductImageVO : toProductImageDTO.getToProductImageVOList()) {
            String taskId;
            // 处理设计服装类型的元素
            if (toProductImageVO.getElementType().equals("DesignOutfit")) {
                // 生成唯一的任务ID，包含UUID、序号和用户ID
                taskId = UUID.randomUUID() + "-" + i + "-" + userHolder.getId();
                // 根据元素ID查询设计Python服装信息
                TDesignPythonOutfit tDesignPythonOutfit = designPythonOutfitMapper.selectById(toProductImageVO.getElementId());

                // 获取设计项目ID并查询相关的设计项目详情
                Long designItemId = tDesignPythonOutfit.getDesignItemId();
                QueryWrapper<DesignItemDetail> designItemDetailQueryWrapper = new QueryWrapper<>();
                designItemDetailQueryWrapper.lambda().eq(DesignItemDetail::getDesignItemId, designItemId);
                designItemDetailQueryWrapper.lambda().ne(DesignItemDetail::getType, "Body"); // 排除身体部分
                List<DesignItemDetail> designItemDetails = designItemDetailService.list(designItemDetailQueryWrapper);
                // 将设计项目的类型拼接成字符串（如：Tops,Bottoms）
                String collect = designItemDetails.stream().map(DesignItemDetail::getType).collect(Collectors.joining(","));

                // 获取设计ID并查询设计信息
                Long designId = tDesignPythonOutfit.getDesignId();
                Design design = designMapper.selectById(designId);
                // 默认产品类型为整体
                String productType = "overall";
                // 根据设计的单品/整体属性决定产品类型和提示词构建方式
                if (design.getSingleOverall().equals("single")) {
                    // 单品设计：直接使用服装类型
                    productType = "single";
                    sb.append(collect);
                } else {
                    // 整体设计：根据服装类型和年龄组添加人物描述
                    if (collect.contains("Tops") && childFlag) {
                        sb.append("a handsome boy,"); // 儿童上装 - 男孩
                    } else if (collect.contains("Tops") && !childFlag) {
                        sb.append("a handsome man,"); // 成人上装 - 男性
                    } else if (childFlag) {
                        sb.append("a beautiful girl,"); // 儿童其他 - 女孩
                    } else {
                        sb.append("a beautiful woman,"); // 成人其他 - 女性
                    }
//                    sb.append("wearing ").append(collect);
                }
                // 根据是否有自定义提示词来完善最终的提示词
                if (StringUtils.isEmpty(prompt)) {
                    // 无自定义提示词：使用默认的高质量服装细节描述
                    sb.append(",high quality clothing details,8K realistic,HDR");
                } else {
                    // 有自定义提示词：结合用户提示词和高质量描述
                    sb.append(",high quality clothing details,").append(prompt).append(",8K realistic,HDR");
                }
                // 创建产品图像结果对象
                ToProductImageResultVO toProductImageResult = new ToProductImageResultVO();
                // 根据是否使用flux模型选择不同的生成方式
                if (advanced) {
                    // 使用flux高级模型
                    if (childFlag) {
                        sb.append(", Children's face"); // 儿童面部特征
                    }
                    taskId = generateService.toProductAsyncTask(tDesignPythonOutfit.getDesignUrl(), ModelConstants.NANO_BANANA, advancedPrompt);
                    toProductImageResult.setModelName(toProductImageDTO.getModelName());
                    toProductImageResult.setResultType(CollectionType.TO_PRODUCT_IMAGE.getValue());
                } else {
                    // 使用本地Python模型
                    if (childFlag) {
                        sb.append(", (Children's face:1.3)"); // 儿童面部特征（权重1.3）
                    }
                    // 调用Python服务生成产品图像
                    pythonService.toProductImage(tDesignPythonOutfit.getDesignUrl(), taskId, sb.toString(), toProductImageDTO.getImageStrength(), productType);
//                    toProductImageResult.setModelName("local"); // 注释掉的本地模型标记
                }

                // 设置产品图像结果的基本信息
                toProductImageResult.setElementId(tDesignPythonOutfit.getId()); // 关联的设计服装ID
                toProductImageResult.setElementType("DesignOutfit"); // 元素类型：设计服装
                toProductImageResult.setCreateTime(LocalDateTime.now()); // 创建时间
                toProductImageResult.setToProductImageRecordId(toProductImageRecord.getId()); // 关联的记录ID
//                toProductImageResult.setUrl(productImageUrl); // 生成的图像URL（暂时注释）
                toProductImageResult.setIsLike(0); // 默认未点赞
                toProductImageResult.setTaskId(taskId); // 任务ID
                toProductImageResult.setProjectId(projectId); // 项目ID
                if (userLikeGroupId != null) {
                    toProductImageResult.setUserLikeGroupId(userLikeGroupId); // 用户喜欢组ID
                }
                toProductImageResult.setImageStrength(toProductImageDTO.getImageStrength()); // 图像强度
                toProductImageResult.setResultType(CollectionType.TO_PRODUCT_IMAGE.getValue()); // 结果类型
                toProductImageResult.setStatus("Pending"); // 状态：待处理
                // 将结果插入数据库
                toProductImageResultMapper.insert(toProductImageResult);
//                toProductImageResult.setUrl(minioUtil.getPresignedUrl(toProductImageResult.getUrl(), 24 * 60));
                // 处理默认点赞逻辑
                if (Objects.nonNull(toProductImageDTO.getIsDefaultLike()) && toProductImageDTO.getIsDefaultLike()) {
                    // 如果设置了默认点赞，则自动添加到用户喜欢列表
                    CollectionSort collectionSort = addToProductLike(toProductImageVO.getParentId(), toProductImageResult.getId(), toProductImageDTO.getProjectId());
                    // 重新排序：根据用户指定的排序位置调整
                    Integer reSort = collectionSortService.rearrangeChildSort(toProductImageResult.getId(), CollectionType.TO_PRODUCT_IMAGE.getValue(),
                            toProductImageVO.getParentId(), toProductImageVO.getUserLikeSortId());
                    // 设置排序信息到结果对象中
                    toProductImageResult.setSort(Objects.isNull(reSort) ? Objects.isNull(collectionSort) ? null : collectionSort.getSort() : reSort);
                    toProductImageResult.setParentId(toProductImageVO.getParentId()); // 父级ID
                    toProductImageResult.setUserLikeSortId(Objects.isNull(collectionSort) ? null : collectionSort.getId()); // 排序记录ID
                } else if (Objects.nonNull(toProductImageDTO.getIsDefaultLike()) && Objects.nonNull(toProductImageVO.getParentId())) {
                    // 不默认点赞但有父级ID的情况
                    toProductImageResult.setParentId(toProductImageVO.getParentId());
                    // 注释：原本计划添加到collectionSort表中，但当前未实现
//                    designService.addCollectionSort(toProductImageResult.getId(), CollectionType.TO_PRODUCT_IMAGE.getValue(), toProductImageDTO.getProjectId(), toProductImageVO.getParentId());
                }
                // 将处理完的结果添加到返回列表中
                result.add(toProductImageResult);
            } else {
                // 处理ProductElement类型的元素
                // 根据是否有自定义提示词来构建最终提示词
                if (StringUtils.isEmpty(prompt)) {
                    sb.append(",high quality clothing details,8K realistic,HDR");
                } else {
                    sb.append(",high quality clothing details,").append(prompt).append(",8K realistic,HDR");
                }

                // 生成唯一的任务ID
                taskId = UUID.randomUUID() + "-" + i + "-" + userHolder.getId();
                // 查询产品元素信息
                ToProductElement toProductElement = toProductElementMapper.selectById(toProductImageVO.getElementId());
                // 创建产品图像结果对象
                ToProductImageResultVO toProductImageResult = new ToProductImageResultVO();

                // 根据是否使用高级模型选择不同的图像生成方式
                if (advanced) {
                    // 使用模型生成图像
                    taskId = generateService.toProductAsyncTask(toProductElement.getUrl(), ModelConstants.NANO_BANANA, advancedPrompt);
                    toProductImageResult.setModelName(toProductImageDTO.getModelName()); // 设置模型名称
                    toProductImageResult.setResultType(CollectionType.TO_PRODUCT_IMAGE.getValue()); // 设置结果类型
                } else {
                    // 使用本地Python模型生成图像
                    if (childFlag) {
                        // 如果是儿童年龄组，添加儿童面部特征提示
                        sb.append(", (Children's face:1.3)");
                    }
                    // 调用Python服务生成产品图像
                    pythonService.toProductImage(toProductElement.getUrl(), taskId, sb.toString(), toProductImageDTO.getImageStrength(), "overall");
//                    toProductImageResult.setModelName("local"); // 本地模型名称（已注释）
                }
                // 设置产品图像结果的基本信息
                toProductImageResult.setElementId(toProductElement.getId()); // 关联的产品元素ID
                toProductImageResult.setElementType("ProductElement"); // 元素类型：产品元素
                toProductImageResult.setCreateTime(LocalDateTime.now()); // 创建时间
                toProductImageResult.setToProductImageRecordId(toProductImageRecord.getId()); // 关联的记录ID
//                toProductImageResult.setUrl(productImageUrl); // 生成的图像URL（暂时注释）
                toProductImageResult.setIsLike(0); // 默认未点赞
                toProductImageResult.setTaskId(taskId); // 任务ID
                toProductImageResult.setProjectId(projectId); // 项目ID
                if (userLikeGroupId != null) {
                    toProductImageResult.setUserLikeGroupId(userLikeGroupId); // 用户喜欢组ID
                }
                toProductImageResult.setImageStrength(toProductImageDTO.getImageStrength()); // 图像强度
                toProductImageResult.setResultType(CollectionType.TO_PRODUCT_IMAGE.getValue()); // 结果类型
                toProductImageResult.setStatus("Pending"); // 状态：待处理
                // 将结果插入数据库
                toProductImageResultMapper.insert(toProductImageResult);
//                toProductImageResult.setUrl(minioUtil.getPresignedUrl(toProductImageResult.getUrl(), 24 * 60));
                // 处理默认点赞逻辑
                if (Objects.nonNull(toProductImageDTO.getIsDefaultLike()) && toProductImageDTO.getIsDefaultLike()) {
                    // 如果设置了默认点赞，则自动添加到用户喜欢列表
                    CollectionSort collectionSort = addToProductLike(toProductImageVO.getParentId(), toProductImageResult.getId(), toProductImageDTO.getProjectId());
                    // 重新排序：根据用户指定的排序位置调整
                    Integer reSort = collectionSortService.rearrangeChildSort(toProductImageResult.getId(), CollectionType.TO_PRODUCT_IMAGE.getValue(),
                            toProductImageVO.getParentId(), toProductImageVO.getUserLikeSortId());
                    // 设置排序信息到结果对象中
                    toProductImageResult.setSort(Objects.isNull(reSort) ? Objects.isNull(collectionSort) ? null : collectionSort.getSort() : reSort);
                    toProductImageResult.setParentId(toProductImageVO.getParentId()); // 父级ID
                    toProductImageResult.setUserLikeSortId(Objects.isNull(collectionSort) ? null : collectionSort.getId()); // 排序记录ID
                } else if (Objects.nonNull(toProductImageDTO.getIsDefaultLike()) && Objects.nonNull(toProductImageVO.getParentId())) {
                    // 不默认点赞但有父级ID的情况
                    toProductImageResult.setParentId(toProductImageVO.getParentId());
                    // 注释：原本计划添加到collectionSort表中，但当前未实现
//                    designService.addCollectionSort(toProductImageResult.getId(), CollectionType.TO_PRODUCT_IMAGE.getValue(), toProductImageDTO.getProjectId(), toProductImageVO.getParentId());
                }
                // 将处理完的结果添加到返回列表中
                result.add(toProductImageResult);
            }
            i++; // 循环计数器递增
            sb = new StringBuilder("The best quality, masterpiece, real image."); // 重置提示词构建器
            // 添加需要扣除的积分到预扣除区
            creditsService.addRecordToCreditsDeduction(userHolder.getId(), taskId, creditsEventsEnum);
            // 添加积分扣除记录到数据库
            creditsService.preInsert(userHolder.getId(), creditsEventsEnum.getName(), taskId, Boolean.TRUE, null);
        }
        // 更新项目更新时间，记录最后一次操作时间
        projectService.modifyProjectUpdateTime(toProductImageDTO.getProjectId());
        // 返回生成的产品图像结果列表
        return result;
    }

    private CollectionSort addToProductLike(Long parentId, Long toProductImageResultId, Long projectId) {
        if (Objects.nonNull(parentId) && !parentId.equals(0L)) {
            return productImageLike(new ProductImageLikeDTO(Collections.singletonList(toProductImageResultId),
                    projectId, parentId));
        }
        return null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void toProduct(String taskId) {
        QueryWrapper<ToProductImageResult> qw = new QueryWrapper<>();
        qw.lambda().eq(ToProductImageResult::getTaskId, taskId);
        List<ToProductImageResult> toProductImageResults = toProductImageResultMapper.selectList(qw);
        if (CollectionUtil.isNotEmpty(toProductImageResults)) {
            ToProductImageResult toProductImageResultOne = toProductImageResults.get(0);
            ToProductImageRecord toProductImageRecord = toProductImageRecordMapper.selectById(toProductImageResultOne.getToProductImageRecordId());
            String prompt = toProductImageRecord.getPrompt();
            StringBuilder sb = new StringBuilder("The best quality, masterpiece, real image.");
            if (!StringUtil.isNullOrEmpty(prompt)) {
                prompt = pythonService.promptTranslate(prompt);
            }
            String elementType = toProductImageResultOne.getElementType();
            if (elementType.equals("DesignOutfit")) {
                TDesignPythonOutfit tDesignPythonOutfit = designPythonOutfitMapper.selectById(toProductImageResultOne.getElementId());
                Long designItemId = tDesignPythonOutfit.getDesignItemId();
                QueryWrapper<DesignItemDetail> designItemDetailQueryWrapper = new QueryWrapper<>();
                designItemDetailQueryWrapper.lambda().eq(DesignItemDetail::getDesignItemId, designItemId);
                designItemDetailQueryWrapper.lambda().ne(DesignItemDetail::getType, "Body");
                List<DesignItemDetail> designItemDetails = designItemDetailService.list(designItemDetailQueryWrapper);
                String collect = designItemDetails.stream().map(DesignItemDetail::getType).collect(Collectors.joining(","));

                Long designId = tDesignPythonOutfit.getDesignId();
                Design design = designMapper.selectById(designId);
                String productType = "overall";
                if (design.getSingleOverall().equals("single")) {
                    productType = "single";
                    sb.append(collect);
                } else {
                    if (collect.contains("Tops")) {
                        sb.append("a handsome man,");
                    } else {
                        sb.append("a beautiful women,");
                    }
                    sb.append("wearing ").append(collect);
                }
                if (StringUtils.isEmpty(prompt)) {
                    sb.append(",high quality clothing details,8K realistic,HDR");
                } else {
                    sb.append(",high quality clothing details,").append(prompt).append(",8K realistic,HDR");
                }
                // 走模型
                pythonService.toProductImage(tDesignPythonOutfit.getDesignUrl(), taskId, sb.toString(), toProductImageResultOne.getImageStrength(), "single");
            } else {
                if (StringUtils.isEmpty(prompt)) {
                    sb.append(",high quality clothing details,8K realistic,HDR");
                } else {
                    sb.append(",high quality clothing details,").append(prompt).append(",8K realistic,HDR");
                }

                ToProductElement toProductElement = toProductElementMapper.selectById(toProductImageResultOne.getElementId());
                // 走模型
                pythonService.toProductImage(toProductElement.getUrl(), taskId, sb.toString(), toProductImageResultOne.getImageStrength(), "single");
            }

        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ToProductElementVO toProductImageElementUpload(MultipartFile file, Long projectId, String type) {
        if (null == file || StringUtils.isEmpty(file.getOriginalFilename())) {
            throw new BusinessException("file.cannot.be.empty");
        }
//        if (projectId == null) {
//            throw new BusinessException("projectId.cannot.be.empty");
//        }
        AuthPrincipalVo userHolder = UserContext.getUserHolder();
        String bucketName = "aida-users";
        String minioUrl = minioUtil.upload(bucketName, userHolder.getId() + "/toProductImageElement", file);
        ToProductElement toProductElement = new ToProductElement();
        toProductElement.setUrl(minioUrl);
//        toProductElement.setUserLikeGroupId(userLikeGroupId);
        toProductElement.setProjectId(projectId);
        toProductElement.setCreateTime(LocalDateTime.now());
        toProductElement.setFrameType(type);
        toProductElementMapper.insert(toProductElement);
        ToProductElementVO toProductElementVO = CopyUtil.copyObject(toProductElement, ToProductElementVO.class);
        toProductElementVO.setMinioUrl(toProductElementVO.getUrl());
        toProductElementVO.setUrl(minioUtil.getPreSignedUrl(toProductElementVO.getUrl(), 24 * 60));
        return toProductElementVO;
    }

    @Override
    public CollectionSort productImageLike(ProductImageLikeDTO dto) {
        List<Long> resultIds = dto.getToProductImageResultId();
        ToProductImageResult result = toProductImageResultMapper.selectById(resultIds.get(0));
        CollectionSort collectionSort = null;
        boolean updatedFlag = false;

        Long parentId = dto.getCollectionSortParentId();
        if (parentId == null) {
            return null;
        }

        // 统一处理两种类型
        CollectionType collectionType = "Relight".equals(result.getResultType())
                ? CollectionType.RELIGHT
                : CollectionType.TO_PRODUCT_IMAGE;

        collectionSort = collectionSortService.getUserLikeSortByUserLikeId(
                result.getId(), collectionType.getValue(), dto.getProjectId(), parentId);

        if (Objects.isNull(collectionSort)) {
            collectionSort = collectionSortService.addCollectionSort(
                    result.getId(), collectionType.getValue(), dto.getProjectId(), parentId);
            updatedFlag = true;
        }

        if (updatedFlag) {
            updateLikeStatus(resultIds);
            projectService.modifyProjectUpdateTime(dto.getProjectId());
        }

        return collectionSort;
    }

    private void updateLikeStatus(List<Long> resultIds) {
        QueryWrapper<ToProductImageResult> qw = new QueryWrapper<>();
        qw.lambda().in(ToProductImageResult::getId, resultIds);

        ToProductImageResult updateEntity = new ToProductImageResult();
        updateEntity.setIsLike(1);
        toProductImageResultMapper.update(updateEntity, qw);
    }

    @Resource
    private RedisUtil redisUtil;
    @Value("${redis.key.toProductImageResultKey}")
    private String toProductImageResultKey;
    @Value("${redis.key.relightResultKey}")
    private String relightResultKey;

    /**
     * 获取产品图像生成结果列表
     * 根据任务ID列表查询对应的产品图像生成结果，支持flux模型和传统Python模型两种处理方式
     *
     * @param taskIdList 任务ID列表，用于查询对应的产品图像生成结果
     * @return 返回MagicToolResultVO列表，包含图像生成结果的详细信息（URL、状态、元素信息等）
     * @throws BusinessException 当源图像不存在或任务不存在时抛出业务异常
     */
    @Override
    public List<MagicToolResultVO> getToProductImageResultList(List<String> taskIdList) {
        // 初始化结果列表和状态收集集合
        List<MagicToolResultVO> results = new ArrayList<>();
        Set<String> collect = new HashSet<>();

        // 遍历每个任务ID，处理对应的产品图像生成结果
        taskIdList.forEach(taskId -> {
            // 根据任务ID查询产品图像生成结果记录
            QueryWrapper<ToProductImageResult> qw = new QueryWrapper<>();
            qw.lambda().eq(ToProductImageResult::getTaskId, taskId);
            ToProductImageResult toProductImageResult = toProductImageResultMapper.selectOne(qw);
            if (Objects.isNull(toProductImageResult)) {
                throw new BusinessException("source.image.does.not.exist");
            }

            // 查询产品图像记录，获取提示词等信息
            ToProductImageRecord toProductImageRecord = toProductImageRecordMapper.selectById(toProductImageResult.getToProductImageRecordId());
            if (Objects.isNull(toProductImageRecord)) {
                throw new BusinessException("This task does not exist.");
            }

            if (!StringUtil.isNullOrEmpty(toProductImageResult.getModelName()) && toProductImageResult.getModelName().equals(ModelConstants.ADVANCED)) {
                // 获取项目信息，用于构建文件路径和积分扣除
                Project project = projectService.getById(toProductImageResult.getProjectId());
                if (Objects.isNull(project)) {
                    throw new BusinessException("unknown project");
                }

                // 获取flux模型生成结果
                String redisResult;
                if (toProductImageResult.getStatus().equals("Success") && !StringUtil.isNullOrEmpty(toProductImageResult.getUrl())) {
                    // 如果已经有成功的结果URL，直接使用
                    redisResult = toProductImageResult.getUrl();
                } else {
                    String key = generateResultKey + ":" + taskId;
                    redisResult = redisUtil.getFromString(key);
                }

                GenerateResultVO cachedResult = new Gson().fromJson(redisResult, GenerateResultVO.class);


                // 根据flux结果状态进行不同处理
                if (StringUtil.isNullOrEmpty(redisResult)) {
                    // 如果结果为空，标记为失败状态
                    toProductImageResult.setStatus("Fail");
                    toProductImageResultMapper.updateById(toProductImageResult);
                    collectionSortMapper.delete(new QueryWrapper<CollectionSort>().lambda().eq(CollectionSort::getRelationId, toProductImageResult.getId()));
                    results.add(new MagicToolResultVO(taskId, "Fail"));
                } else if ("Pending".equals(cachedResult.getStatus()) || "Fail".equals(cachedResult.getStatus())) {
                    // 如果结果为失败或待处理状态，更新状态并返回对应结果
                    toProductImageResult.setStatus(cachedResult.getStatus());
                    toProductImageResultMapper.updateById(toProductImageResult);
                    if (cachedResult.getStatus().equals("Fail")) {
                        collectionSortMapper.delete(new QueryWrapper<CollectionSort>().lambda().eq(CollectionSort::getRelationId, toProductImageResult.getId()));
                    }
                    String errorMessage = cachedResult.getUrl();
                    if (errorMessage != null) {
                        results.add(new MagicToolResultVO(taskId, cachedResult.getStatus(), errorMessage));
                    } else {
                        results.add(new MagicToolResultVO(taskId, cachedResult.getStatus()));
                    }
                } else {
                    // 如果结果成功，处理flux结果并构建返回对象
                    results.add(processNanoBananaResult(cachedResult.getUrl(), toProductImageResult, taskId, toProductImageRecord.getPrompt()));
                    // 执行积分扣除操作
                    Boolean flag = creditsService.taskCreditsDeduction(project.getAccountId(), taskId);
                    if (flag) creditsService.updateChangedCredits(String.valueOf(project.getAccountId()), taskId);
                }

                // 如果任务失败，将积分预扣除记录移除
                if (toProductImageResult.getStatus().equals("Fail")) {
                    creditsService.deleteCreditsDeduction(project.getAccountId(), taskId);
                }

                // flux模型处理完成，跳过后续的Redis缓存处理逻辑
                return;
            }

            // 非flux模型的处理逻辑：从Redis缓存获取结果
            String key = toProductImageResultKey + ":" + taskId;
            MagicToolResultVO magicToolResultVO = new Gson().fromJson(redisUtil.getFromString(key), MagicToolResultVO.class);

            // 如果从Redis获取到结果且URL不为空，则构建返回对象
            if (!Objects.isNull(magicToolResultVO) && !StringUtil.isNullOrEmpty(magicToolResultVO.getUrl())) {
                String url = magicToolResultVO.getUrl();
                // 检查是否为无效图片（白色图片表示生成失败）
                if (url.substring(url.lastIndexOf("/") + 1).equals("white_image.jpg")) {
                    magicToolResultVO.setStatus("Invalid");
                } else {
                    // 设置预签名URL和相关属性
                    magicToolResultVO.setUrl(minioUtil.getPreSignedUrl(url, CommonConstant.MINIO_IMAGE_EXPIRE_TIME));
                    magicToolResultVO.setResultType(toProductImageResult.getResultType());
                    magicToolResultVO.setElementId(toProductImageResult.getElementId());
                    magicToolResultVO.setElementType(toProductImageResult.getElementType());
                    magicToolResultVO.setDirection(toProductImageResult.getDirection());
                    magicToolResultVO.setBrightenValue(toProductImageResult.getBrightenValue());
                    magicToolResultVO.setImageStrength(toProductImageResult.getImageStrength());
                    magicToolResultVO.setPrompt(toProductImageRecord.getPrompt());

                    // 根据元素类型设置源图片URL和父ID
                    if (toProductImageResult.getElementType().equals("ProductElement")) {
                        // 处理ProductElement类型：获取产品元素信息
                        ToProductElement toProductElement = toProductElementMapper.selectById(toProductImageResult.getElementId());
                        magicToolResultVO.setSourceUrl(minioUtil.getPreSignedUrl(toProductElement.getUrl(), 24 * 60));

                        // 获取ProductElement的父ID
                        Long parentId = collectionSortService.getParentIdByElementIdAndElementType(toProductImageResult.getElementId(), toProductImageResult.getElementType());
                        magicToolResultVO.setParentId(parentId);
                    } else {
                        // 处理DesignOutfit类型：获取设计服装信息
                        TDesignPythonOutfit tDesignPythonOutfit = designPythonOutfitMapper.selectById(toProductImageResult.getElementId());
                        magicToolResultVO.setSourceUrl(minioUtil.getPreSignedUrl(tDesignPythonOutfit.getDesignUrl(), 24 * 60));

                        // 通过DesignOutfit查找对应的UserLike记录，获取父ID
                        QueryWrapper<UserLike> userLikeQueryWrapper = new QueryWrapper<>();
                        userLikeQueryWrapper.lambda().eq(UserLike::getDesignOutfitId, tDesignPythonOutfit.getId());
                        List<UserLike> userLikeList = userLikeMapper.selectList(userLikeQueryWrapper);
                        if (!CollectionUtils.isEmpty(userLikeList)) {
                            UserLike userLike = userLikeList.get(0);
                            Long parentId = collectionSortService.getParentIdByElementIdAndElementType(userLike.getId(), toProductImageResult.getElementType());
                            magicToolResultVO.setParentId(parentId);
                        }
                    }
                }
                // 将构建好的结果对象添加到返回列表
                results.add(magicToolResultVO);
            } else if (Objects.isNull(magicToolResultVO)) {
                // 如果Redis中没有结果对象，创建执行中状态的结果对象
                magicToolResultVO = new MagicToolResultVO(taskId, "Executing");
                results.add(magicToolResultVO);
            } else {
                // 如果Redis中有结果对象但URL为空，直接添加到返回列表
                results.add(magicToolResultVO);
            }

            // 收集任务状态用于统计
            if (!StringUtil.isNullOrEmpty(magicToolResultVO.getStatus())) collect.add(magicToolResultVO.getStatus());
            results.add(magicToolResultVO);
        });

        // 返回所有任务的处理结果列表
        return results;
    }

    private MagicToolResultVO processNanoBananaResult(String resultImgMinioPath, ToProductImageResult toProductImageResult, String taskId, String prompt) {
        // 如果任务状态不是成功且URL为空，则更新任务状态和URL
        if (!toProductImageResult.getStatus().equals("Success")
                && StringUtil.isNullOrEmpty(toProductImageResult.getUrl())) {
            toProductImageResult.setStatus("Success");
            toProductImageResult.setUrl(resultImgMinioPath);
            toProductImageResultMapper.updateById(toProductImageResult);
        }

        // 创建返回结果对象并设置基本信息
        MagicToolResultVO magicToolResultVO = CopyUtil.copyObject(toProductImageResult, MagicToolResultVO.class);
        magicToolResultVO.setTaskId(taskId);
        magicToolResultVO.setId(toProductImageResult.getId());
        // 设置Flux生成图片的预签名URL（使用系统配置的过期时间）
        magicToolResultVO.setUrl(minioUtil.getPreSignedUrl(resultImgMinioPath, CommonConstant.MINIO_IMAGE_EXPIRE_TIME));
        magicToolResultVO.setStatus("Success");
        magicToolResultVO.setResultType(toProductImageResult.getResultType());
        magicToolResultVO.setElementId(toProductImageResult.getElementId());
        magicToolResultVO.setElementType(toProductImageResult.getElementType());
        magicToolResultVO.setPrompt(prompt);

        // 根据元素类型设置源图片URL和父ID
        if (toProductImageResult.getElementType().equals("ProductElement")) {
            // 处理产品元素类型：获取产品元素信息并设置源图片URL
            ToProductElement toProductElement = toProductElementMapper.selectById(toProductImageResult.getElementId());
            magicToolResultVO.setSourceUrl(minioUtil.getPreSignedUrl(toProductElement.getUrl(), 24 * 60));

            // 通过CollectionSort服务获取父ID
            Long parentId = collectionSortService.getParentIdByElementIdAndElementType(toProductImageResult.getElementId(), toProductImageResult.getElementType());
            magicToolResultVO.setParentId(parentId);
        } else if (toProductImageResult.getElementType().equals("DesignOutfit")) {
            // 处理设计服装类型：获取设计服装信息并设置源图片URL
            TDesignPythonOutfit tDesignPythonOutfit = designPythonOutfitMapper.selectById(toProductImageResult.getElementId());
            magicToolResultVO.setSourceUrl(minioUtil.getPreSignedUrl(tDesignPythonOutfit.getDesignUrl(), 24 * 60));

            // 通过设计服装ID查找对应的用户喜欢记录，获取父ID
            QueryWrapper<UserLike> userLikeQueryWrapper = new QueryWrapper<>();
            userLikeQueryWrapper.lambda().eq(UserLike::getDesignOutfitId, tDesignPythonOutfit.getId());
            List<UserLike> userLikeList = userLikeMapper.selectList(userLikeQueryWrapper);
            if (!CollectionUtils.isEmpty(userLikeList)) {
                UserLike userLike = userLikeList.get(0);
                Long parentId = collectionSortService.getParentIdByElementIdAndElementType(userLike.getId(), toProductImageResult.getElementType());
                magicToolResultVO.setParentId(parentId);
            }
        } else if (toProductImageResult.getElementType().equals("ToProductImage")) {
            // 处理转产品图像类型：获取转产品图像信息并设置源图片URL
            ToProductImageResult toProductImage = toProductImageResultMapper.selectById(toProductImageResult.getElementId());
            magicToolResultVO.setSourceUrl(minioUtil.getPreSignedUrl(toProductImage.getUrl(), 24 * 60));

            // 直接通过元素ID和类型获取父ID
            Long parentId = collectionSortService.getParentIdByElementIdAndElementType(toProductImageResult.getElementId(), toProductImageResult.getElementType());
            magicToolResultVO.setParentId(parentId);
        }

//        Long parentId = collectionSortService.getParentIdByElementIdAndElementType(toProductImageResult.getId(), toProductImageResult.getResultType());
//        magicToolResultVO.setParentId(parentId);
        return magicToolResultVO;
    }

    /**
     * 处理Flux模型生成的结果，构建返回给前端的结果对象
     *
     * @param fluxImgMinioPath     Flux生成的图片在Minio中的路径
     * @param toProductImageResult 产品图像生成结果记录
     * @param taskId               任务ID
     * @param prompt               生成提示词
     * @return MagicToolResultVO 构建好的魔法工具结果对象
     */
    private MagicToolResultVO processFluxResult(String fluxImgMinioPath, ToProductImageResult toProductImageResult, String taskId, String prompt) {
        // 如果任务状态不是成功且URL为空，则更新任务状态和URL
        if (!toProductImageResult.getStatus().equals("Success")
                && StringUtil.isNullOrEmpty(toProductImageResult.getUrl())) {
            toProductImageResult.setStatus("Success");
            toProductImageResult.setUrl(fluxImgMinioPath);
            toProductImageResultMapper.updateById(toProductImageResult);
        }

        // 创建返回结果对象并设置基本信息
        MagicToolResultVO magicToolResultVO = CopyUtil.copyObject(toProductImageResult, MagicToolResultVO.class);
        magicToolResultVO.setTaskId(taskId);
        magicToolResultVO.setId(toProductImageResult.getId());
        // 设置Flux生成图片的预签名URL（使用系统配置的过期时间）
        magicToolResultVO.setUrl(minioUtil.getPreSignedUrl(fluxImgMinioPath, CommonConstant.MINIO_IMAGE_EXPIRE_TIME));
        magicToolResultVO.setStatus("Success");
        magicToolResultVO.setResultType(toProductImageResult.getResultType());
        magicToolResultVO.setElementId(toProductImageResult.getElementId());
        magicToolResultVO.setElementType(toProductImageResult.getElementType());
        magicToolResultVO.setPrompt(prompt);

        // 根据元素类型设置源图片URL和父ID
        if (toProductImageResult.getElementType().equals("ProductElement")) {
            // 处理产品元素类型：获取产品元素信息并设置源图片URL
            ToProductElement toProductElement = toProductElementMapper.selectById(toProductImageResult.getElementId());
            magicToolResultVO.setSourceUrl(minioUtil.getPreSignedUrl(toProductElement.getUrl(), 24 * 60));

            // 通过CollectionSort服务获取父ID
            Long parentId = collectionSortService.getParentIdByElementIdAndElementType(toProductImageResult.getElementId(), toProductImageResult.getElementType());
            magicToolResultVO.setParentId(parentId);
        } else if (toProductImageResult.getElementType().equals("DesignOutfit")) {
            // 处理设计服装类型：获取设计服装信息并设置源图片URL
            TDesignPythonOutfit tDesignPythonOutfit = designPythonOutfitMapper.selectById(toProductImageResult.getElementId());
            magicToolResultVO.setSourceUrl(minioUtil.getPreSignedUrl(tDesignPythonOutfit.getDesignUrl(), 24 * 60));

            // 通过设计服装ID查找对应的用户喜欢记录，获取父ID
            QueryWrapper<UserLike> userLikeQueryWrapper = new QueryWrapper<>();
            userLikeQueryWrapper.lambda().eq(UserLike::getDesignOutfitId, tDesignPythonOutfit.getId());
            List<UserLike> userLikeList = userLikeMapper.selectList(userLikeQueryWrapper);
            if (!CollectionUtils.isEmpty(userLikeList)) {
                UserLike userLike = userLikeList.get(0);
                Long parentId = collectionSortService.getParentIdByElementIdAndElementType(userLike.getId(), toProductImageResult.getElementType());
                magicToolResultVO.setParentId(parentId);
            }
        } else if (toProductImageResult.getElementType().equals("ToProductImage")) {
            // 处理转产品图像类型：获取转产品图像信息并设置源图片URL
            ToProductImageResult toProductImage = toProductImageResultMapper.selectById(toProductImageResult.getElementId());
            magicToolResultVO.setSourceUrl(minioUtil.getPreSignedUrl(toProductImage.getUrl(), 24 * 60));

            // 直接通过元素ID和类型获取父ID
            Long parentId = collectionSortService.getParentIdByElementIdAndElementType(toProductImageResult.getElementId(), toProductImageResult.getElementType());
            magicToolResultVO.setParentId(parentId);
        }

//        Long parentId = collectionSortService.getParentIdByElementIdAndElementType(toProductImageResult.getId(), toProductImageResult.getResultType());
//        magicToolResultVO.setParentId(parentId);
        return magicToolResultVO;
    }

    @Override
    public JSONObject exportSearch(ExportSearchDTO exportSearchDTO) {
        QueryWrapper<ExportFile> qw = new QueryWrapper<>();
        if (Objects.nonNull(exportSearchDTO.getProjectId())) {
            qw.lambda().eq(ExportFile::getProjectId, exportSearchDTO.getProjectId());
        } else if (Objects.nonNull(exportSearchDTO.getId())) {
            qw.lambda().eq(ExportFile::getId, exportSearchDTO.getId());
        }
        qw.lambda().eq(ExportFile::getModule, exportSearchDTO.getModule());
        List<ExportFile> exportFiles = exportFileMapper.selectList(qw);
        if (CollectionUtil.isNotEmpty(exportFiles)) {
            try {
                InputStream download = minioUtil.download(exportFiles.get(0).getUrl());
                String convert = convert(download);
                JSONObject jsonObject = JSONObject.parseObject(convert);

                JSONObject canvas = jsonObject.getJSONObject("canvas");
                if (Objects.nonNull(canvas)) {
                    JSONArray objectJSONArrayLevel1 = canvas.getJSONArray("objects");
                    for (int i = 0; i < objectJSONArrayLevel1.size(); i++) {
                        JSONObject jsonObjectLevel1 = objectJSONArrayLevel1.getJSONObject(i);
                        String type = jsonObjectLevel1.getString("type");
                        if (type.equals("image")) {
                            String minioUrl = jsonObjectLevel1.getString("minioUrl");
                            if (!StringUtil.isNullOrEmpty(minioUrl))
                                jsonObjectLevel1.put("src", minioUtil.getPreSignedUrl(minioUrl, 24 * 60));
                        }
                        if (type.equals("group")) {
                            JSONArray objectJSONArrayLevel2 = jsonObjectLevel1.getJSONArray("objects");
                            for (int j = 0; j < objectJSONArrayLevel2.size(); j++) {
                                JSONObject jsonObjectLevel2 = objectJSONArrayLevel2.getJSONObject(j);
                                String typeGroup = jsonObjectLevel2.getString("type");
                                if (typeGroup.equals("image") && !StringUtil.isNullOrEmpty(jsonObjectLevel2.getString("minioUrl"))) {
                                    String minioUrl = jsonObjectLevel2.getString("minioUrl");
                                    jsonObjectLevel2.put("src", minioUtil.getPreSignedUrl(minioUrl, 24 * 60));
                                }
                                objectJSONArrayLevel2.set(j, jsonObjectLevel2);
                            }
                            jsonObjectLevel1.put("objects", objectJSONArrayLevel2);
                        }
                        /*if (type.equals("rect")) {
                            JSONObject custom = jsonObjectLevel1.getJSONObject("custom");
                            if (custom.getString("type").equals("init")) {
                                String minioUrl = jsonObjectLevel1.getString("minioUrl");
                                if (!StringUtils.isEmpty(minioUrl)) {
                                    JSONObject fill = jsonObjectLevel1.getJSONObject("fill");
                                    fill.put("source", minioUtil.getPreSignedUrl(minioUrl, 24 * 60));
                                    jsonObjectLevel1.put("fill", fill);
                                }
                            }
                        }*/
                        objectJSONArrayLevel1.set(i, jsonObjectLevel1);
                    }
                    canvas.put("objects", objectJSONArrayLevel1);
                    jsonObject.put("canvas", canvas);
                } else {
                    JSONArray objectJSONArrayLevel1 = jsonObject.getJSONArray("objects");
                    for (int i = 0; i < objectJSONArrayLevel1.size(); i++) {
                        JSONObject jsonObjectLevel1 = objectJSONArrayLevel1.getJSONObject(i);
                        String type = jsonObjectLevel1.getString("type");
                        if (type.equals("image")) {
                            String minioUrl = jsonObjectLevel1.getString("minioUrl");
                            if (!StringUtil.isNullOrEmpty(minioUrl))
                                jsonObjectLevel1.put("src", minioUtil.getPreSignedUrl(minioUrl, 24 * 60));
                        }
                        if (type.equals("group")) {
                            JSONArray objectJSONArrayLevel2 = jsonObjectLevel1.getJSONArray("objects");
                            for (int j = 0; j < objectJSONArrayLevel2.size(); j++) {
                                JSONObject jsonObjectLevel2 = objectJSONArrayLevel2.getJSONObject(j);
                                String typeGroup = jsonObjectLevel2.getString("type");
                                if (typeGroup.equals("image") && !StringUtil.isNullOrEmpty(jsonObjectLevel2.getString("minioUrl"))) {
                                    String minioUrl = jsonObjectLevel2.getString("minioUrl");
                                    jsonObjectLevel2.put("src", minioUtil.getPreSignedUrl(minioUrl, 24 * 60));
                                }
                                objectJSONArrayLevel2.set(j, jsonObjectLevel2);
                            }
                            jsonObjectLevel1.put("objects", objectJSONArrayLevel2);
                        }
                        /*if (type.equals("rect")) {
                            JSONObject custom = jsonObjectLevel1.getJSONObject("custom");
                            if (custom.getString("type").equals("init")) {
                                String minioUrl = jsonObjectLevel1.getString("minioUrl");
                                if (!StringUtils.isEmpty(minioUrl)) {
                                    JSONObject fill = jsonObjectLevel1.getJSONObject("fill");
                                    fill.put("source", minioUtil.getPreSignedUrl(minioUrl, 24 * 60));
                                    jsonObjectLevel1.put("fill", fill);
                                }
                            }
                        }*/
                        objectJSONArrayLevel1.set(i, jsonObjectLevel1);
                    }
                    jsonObject.put("objects", objectJSONArrayLevel1);
                }
                return jsonObject;
            } catch (Exception e) {
                log.error(e.getMessage());
                return null;
            }
        } else {
            return null;
        }
    }

    @Override
    public CanvasElementUpload canvasElementUpload(MultipartFile file) {
        AuthPrincipalVo userHolder = UserContext.getUserHolder();
        CanvasElementUpload canvasElementUpload = new CanvasElementUpload();
        String url = minioUtil.upload("aida-users", userHolder.getId() + "/canvasElementUpload", file);
        canvasElementUpload.setUrl(url);
        canvasElementUpload.setMinioUrl(minioUtil.getPreSignedUrl(url, 24 * 60));
        return canvasElementUpload;
    }

    @Override
    public List<ToProductImageResultVO> productImageLikeList(ToProductImageDTO toProductImageDTO) {
        QueryWrapper<ToProductImageResult> qw = new QueryWrapper<>();
        qw.lambda().eq(ToProductImageResult::getIsLike, 1);

        Long projectId = toProductImageDTO.getProjectId();
//        UserLikeGroup userLikeGroup = getByProjectId(projectId);
//        Long userLikeGroupId = null;

        qw.lambda().eq(ToProductImageResult::getProjectId, projectId);
        List<ToProductImageResult> toProductImageResults = toProductImageResultMapper.selectList(qw);
        for (ToProductImageResult toProductImageResult : toProductImageResults) {
            toProductImageResult.setUrl(minioUtil.getPreSignedUrl(toProductImageResult.getUrl(), 24 * 60));
        }
        List<ToProductImageResultVO> toProductImageResultVOS = CopyUtil.copyList(toProductImageResults, ToProductImageResultVO.class);
        for (ToProductImageResultVO toProductImageResultVO : toProductImageResultVOS) {
            if (toProductImageResultVO.getElementType().equals("ProductElement")) {
                ToProductElement toProductElement = toProductElementMapper.selectById(toProductImageResultVO.getElementId());
                toProductImageResultVO.setSourceUrl(minioUtil.getPreSignedUrl(toProductElement.getUrl(), 24 * 60));
            } else if ((toProductImageResultVO.getElementType().equals("DesignOutfit"))) {
                TDesignPythonOutfit tDesignPythonOutfit = designPythonOutfitMapper.selectById(toProductImageResultVO.getElementId());
                toProductImageResultVO.setSourceUrl(minioUtil.getPreSignedUrl(tDesignPythonOutfit.getDesignUrl(), 24 * 60));
            } else {
                ToProductImageResult toProductImageResult1 = toProductImageResultMapper.selectById(toProductImageResultVO.getElementId());
                toProductImageResultVO.setSourceUrl(minioUtil.getPreSignedUrl(toProductImageResult1.getUrl(), 24 * 60));
            }
        }
        // 更新项目更新时间
        projectService.modifyProjectUpdateTime(toProductImageDTO.getProjectId());
        return toProductImageResultVOS;
    }

    @Override
    public Boolean productImageUnLike(ProductImageLikeDTO productImageLikeDTO) {
        List<Long> toProductImageResultId = productImageLikeDTO.getToProductImageResultId();
        if (!CollectionUtils.isEmpty(toProductImageResultId)) {
            Long toProductImageId = toProductImageResultId.get(0);
            ToProductImageResult toProductImageResult = toProductImageResultMapper.selectById(toProductImageId);
            toProductImageResult.setIsLike(0);
            toProductImageResultMapper.updateById(toProductImageResult);
            if (toProductImageResult.getResultType().equals(CollectionType.RELIGHT.getValue())) {
                if (null != productImageLikeDTO.getCollectionSortParentId()) {
                    collectionSortService.deleteCollectionSort(toProductImageResult.getId(), CollectionType.RELIGHT.getValue(), productImageLikeDTO.getProjectId(), productImageLikeDTO.getCollectionSortParentId());
                }
            } else {
                if (null != productImageLikeDTO.getCollectionSortParentId()) {
                    collectionSortService.deleteCollectionSort(toProductImageResult.getId(), CollectionType.TO_PRODUCT_IMAGE.getValue(), productImageLikeDTO.getProjectId(), productImageLikeDTO.getCollectionSortParentId());
                }
            }
        }
        // 更新项目更新时间
        projectService.modifyProjectUpdateTime(productImageLikeDTO.getProjectId());
        return Boolean.TRUE;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void relight(String taskId) {
        QueryWrapper<ToProductImageResult> qw = new QueryWrapper<>();
        qw.lambda().eq(ToProductImageResult::getTaskId, taskId);
        List<ToProductImageResult> toProductImageResults = toProductImageResultMapper.selectList(qw);
        if (CollectionUtil.isNotEmpty(toProductImageResults)) {
            ToProductImageResult toProductImageResultOne = toProductImageResults.get(0);
            ToProductImageRecord toProductImageRecord = toProductImageRecordMapper.selectById(toProductImageResultOne.getToProductImageRecordId());
            String prompt = toProductImageRecord.getPrompt();

            // 翻译
            String s = "";
            if (!StringUtil.isNullOrEmpty(prompt)) {
                s = pythonService.promptTranslate(prompt);
            } else {
                s = "Snow moutain, snowy day, natural light";
            }
            String elementType = toProductImageResultOne.getElementType();
            if (elementType.equals("ToProductImage")) {
                ToProductImageResult toProductImageResult1 = toProductImageResultMapper.selectById(toProductImageResultOne.getElementId());
                String relightType = "overall";
                if (toProductImageResult1.getElementType().equals("DesignOutfit")) {
                    TDesignPythonOutfit tDesignPythonOutfit = designPythonOutfitMapper.selectById(toProductImageResult1.getElementId());
                    Long designId = tDesignPythonOutfit.getDesignId();
                    Design design = designMapper.selectById(designId);
                    if (design.getSingleOverall().equals("single")) {
                        relightType = "single";
                    }
                }

                // 走模型
                pythonService.relight(toProductImageResult1.getUrl(), taskId, s, toProductImageResultOne.getDirection(), "single");
            } else {
                ToProductElement toProductElement = toProductElementMapper.selectById(toProductImageResultOne.getElementId());
                // 走模型
                pythonService.relight(toProductElement.getUrl(), taskId, s, toProductImageResultOne.getDirection(), "single");
            }

        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<ToProductImageResultVO> relight(ToProductImageDTO toProductImageDTO) {
        // 判断用户当前积分是否够本次生成消耗
        boolean fluxTask = !StringUtil.isNullOrEmpty(toProductImageDTO.getModelName())
                && toProductImageDTO.getModelName().equals("flux");
        CreditsEventsEnum creditsEventsEnum = fluxTask ? CreditsEventsEnum.RELIGHT_FLUX : CreditsEventsEnum.RELIGHT;
        Boolean preDeduction = creditsService.creditsPreDeduction(creditsEventsEnum, toProductImageDTO.getToProductImageVOList().size());
        if (!preDeduction) {
            throw new BusinessException("remaining.credits.insufficient", ResultEnum.WARNING.getCode());
        }

        AuthPrincipalVo userHolder = UserContext.getUserHolder();
        Long projectId = toProductImageDTO.getProjectId();
        UserLikeGroup userLikeGroup = getByProjectId(projectId);
        Long userLikeGroupId = null;

        ToProductImageRecord toProductImageRecord = new ToProductImageRecord();
        toProductImageRecord.setProjectId(projectId);
        if (Objects.nonNull(userLikeGroup)) {
            userLikeGroupId = userLikeGroup.getId();
            toProductImageRecord.setUserLikeGroupId(userLikeGroupId);
        }

        // 翻译
        String prompt = toProductImageDTO.getPrompt();
        String s = "";
        if (!StringUtil.isNullOrEmpty(prompt)) {
            s = pythonService.promptTranslate(prompt);
        } else {
//            s = "Snow moutain, snowy day, natural light";
            s = "Street, natural light";
        }
        // 对输入文本进行长度限制
        String[] words = prompt.split("\\s+");
        if (words.length > 200) {
            throw new BusinessException("Please keep your input text under 200 words. Thanks!");
        }

        toProductImageRecord.setCreateTime(LocalDateTime.now());
        if (!StringUtils.isEmpty(toProductImageDTO.getPrompt())) {
            toProductImageRecord.setPrompt(toProductImageDTO.getPrompt());
        }
        toProductImageRecordMapper.insert(toProductImageRecord);

        List<ToProductImageResultVO> result = new ArrayList<>();

        int i = 0;

        for (ToProductImageVO toProductImageVO : toProductImageDTO.getToProductImageVOList()) {
            String taskId = UUID.randomUUID() + "-" + i + "-" + userHolder.getId();
            i++;
            if (toProductImageVO.getElementType().equals("ToProductImage")) {
                ToProductImageResult toProductImageResult1 = toProductImageResultMapper.selectById(toProductImageVO.getElementId());
                String relightType = "overall";
                if (toProductImageResult1.getElementType().equals("DesignOutfit")) {
                    TDesignPythonOutfit tDesignPythonOutfit = designPythonOutfitMapper.selectById(toProductImageResult1.getElementId());
                    Long designId = tDesignPythonOutfit.getDesignId();
                    Design design = designMapper.selectById(designId);
                    if (design.getSingleOverall().equals("single")) {
                        relightType = "single";
                    }
                }

                ToProductImageResultVO toProductImageResult = new ToProductImageResultVO();
                if (fluxTask) {
                    taskId = generateService.flux(creditsEventsEnum, s, toProductImageResult1.getUrl(), false);
                    toProductImageResult.setModelName("flux");
                    toProductImageResult.setResultType(CollectionType.RELIGHT.getValue());
                } else {
                    // 走模型
                    pythonService.relight(toProductImageResult1.getUrl(), taskId, s, toProductImageDTO.getDirection(), relightType);
                }
                toProductImageResult.setElementId(toProductImageResult1.getId());
                toProductImageResult.setElementType("ToProductImage");
                toProductImageResult.setCreateTime(LocalDateTime.now());
                toProductImageResult.setToProductImageRecordId(toProductImageRecord.getId());
//                toProductImageResult.setUrl(productImageUrl);
                toProductImageResult.setIsLike(0);
                toProductImageResult.setTaskId(taskId);
                toProductImageResult.setProjectId(projectId);
                if (null != userLikeGroupId) {
                    toProductImageResult.setUserLikeGroupId(userLikeGroupId);
                }
                if (toProductImageDTO.getBrightenValue() != null) {
                    toProductImageResult.setBrightenValue(toProductImageDTO.getBrightenValue());
                }
                toProductImageResult.setDirection(toProductImageDTO.getDirection());
                toProductImageResult.setResultType(CollectionType.RELIGHT.getValue());
                toProductImageResult.setStatus("Pending");
                toProductImageResultMapper.insert(toProductImageResult);
//                toProductImageResult.setUrl(minioUtil.getPresignedUrl(toProductImageResult.getUrl(), 24 * 60));
                // 先判断是否需要默认like
                if (Objects.nonNull(toProductImageDTO.getIsDefaultLike()) && toProductImageDTO.getIsDefaultLike()) {
                    // 满足条件情况下默认添加到like
                    CollectionSort collectionSort = addToProductLike(toProductImageVO.getParentId(), toProductImageResult.getId(), toProductImageDTO.getProjectId());
                    // 重新排序
                    Integer reSort = collectionSortService.rearrangeChildSort(toProductImageResult.getId(), CollectionType.RELIGHT.getValue(),
                            toProductImageVO.getParentId(), toProductImageVO.getUserLikeSortId());
                    // 将生成结果的排序返回
                    toProductImageResult.setSort(Objects.isNull(reSort) ? Objects.isNull(collectionSort) ? null : collectionSort.getSort() : reSort);
                    toProductImageResult.setParentId(toProductImageVO.getParentId());
                    toProductImageResult.setUserLikeSortId(Objects.isNull(collectionSort) ? null : collectionSort.getId());
                } else if (Objects.nonNull(toProductImageDTO.getIsDefaultLike()) && Objects.nonNull(toProductImageVO.getParentId())) {
                    toProductImageResult.setParentId(toProductImageVO.getParentId());
                    // 默认不添加到like,但是需要有parentId,所以这里添加到collectionSort表中
//                    designService.addCollectionSort(toProductImageResult.getId(), CollectionType.RELIGHT.getValue(), toProductImageDTO.getProjectId(), toProductImageVO.getParentId());
                }
                result.add(toProductImageResult);
            } else {
                ToProductElement toProductElement = toProductElementMapper.selectById(toProductImageVO.getElementId());
                ToProductImageResultVO toProductImageResult = new ToProductImageResultVO();
                if (fluxTask) {
                    taskId = generateService.flux(CreditsEventsEnum.RELIGHT_FLUX, s, toProductElement.getUrl(), false);
                    toProductImageResult.setModelName("flux");
                    toProductImageResult.setResultType(CollectionType.RELIGHT.getValue());
                } else {
                    // 走模型
                    pythonService.relight(toProductElement.getUrl(), taskId, s, toProductImageDTO.getDirection(), "overall");
                }
                toProductImageResult.setElementId(toProductElement.getId());
                toProductImageResult.setElementType("ProductElement");
                toProductImageResult.setCreateTime(LocalDateTime.now());
                toProductImageResult.setToProductImageRecordId(toProductImageRecord.getId());
//                toProductImageResult.setUrl(productImageUrl);
                toProductImageResult.setIsLike(0);
                toProductImageResult.setTaskId(taskId);
                toProductImageResult.setProjectId(projectId);
                if (null != userLikeGroupId) {
                    toProductImageResult.setUserLikeGroupId(userLikeGroupId);
                }
                if (toProductImageDTO.getBrightenValue() != null) {
                    toProductImageResult.setBrightenValue(toProductImageDTO.getBrightenValue());
                }
                toProductImageResult.setDirection(toProductImageDTO.getDirection());
                toProductImageResult.setResultType(CollectionType.RELIGHT.getValue());
                toProductImageResult.setStatus("Pending");
                toProductImageResultMapper.insert(toProductImageResult);
//                toProductImageResult.setUrl(minioUtil.getPresignedUrl(toProductImageResult.getUrl(), 24 * 60));
                // 先判断是否需要默认like
                if (Objects.nonNull(toProductImageDTO.getIsDefaultLike()) && toProductImageDTO.getIsDefaultLike()) {
                    // 满足条件情况下默认添加到like
                    CollectionSort collectionSort = addToProductLike(toProductImageVO.getParentId(), toProductImageResult.getId(), toProductImageDTO.getProjectId());
                    // 重新排序
                    Integer reSort = collectionSortService.rearrangeChildSort(toProductImageResult.getId(), CollectionType.RELIGHT.getValue(),
                            toProductImageVO.getParentId(), toProductImageVO.getUserLikeSortId());
                    // 将生成结果的排序返回
                    toProductImageResult.setSort(Objects.isNull(reSort) ? Objects.isNull(collectionSort) ? null : collectionSort.getSort() : reSort);
                    toProductImageResult.setParentId(toProductImageVO.getParentId());
                    toProductImageResult.setUserLikeSortId(Objects.isNull(collectionSort) ? null : collectionSort.getId());
                } else if (Objects.nonNull(toProductImageDTO.getIsDefaultLike()) && Objects.nonNull(toProductImageVO.getParentId())) {
                    toProductImageResult.setParentId(toProductImageVO.getParentId());
                    // 默认不添加到like,但是需要有parentId,所以这里添加到collectionSort表中
//                    designService.addCollectionSort(toProductImageResult.getId(), CollectionType.RELIGHT.getValue(), toProductImageDTO.getProjectId(), toProductImageVO.getParentId());
                }
                result.add(toProductImageResult);
            }
            // 添加需要扣除的积分到预扣除区
            creditsService.addRecordToCreditsDeduction(userHolder.getId(), taskId, creditsEventsEnum);
            // 添加积分扣除记录到db
            creditsService.preInsert(userHolder.getId(), creditsEventsEnum.getName(), taskId, Boolean.TRUE, null);
        }
        // 更新项目更新时间
        projectService.modifyProjectUpdateTime(toProductImageDTO.getProjectId());
        return result;
    }

    @Override
    public List<MagicToolResultVO> getRelightResult(List<String> taskIdList) {
        List<MagicToolResultVO> results = new ArrayList<>();
        Set<String> collect = new HashSet<>();
        taskIdList.forEach(taskId -> {
            QueryWrapper<ToProductImageResult> qw = new QueryWrapper<>();
            qw.lambda().eq(ToProductImageResult::getTaskId, taskId);
            ToProductImageResult toProductImageResult = toProductImageResultMapper.selectOne(qw);
            if (Objects.isNull(toProductImageResult)) {
                throw new BusinessException("source.image.does.not.exist");
            }
            ToProductImageRecord toProductImageRecord = toProductImageRecordMapper.selectById(toProductImageResult.getToProductImageRecordId());
            if (Objects.isNull(toProductImageRecord)) {
                throw new BusinessException("This task does not exist.");
            }
            // 判断当任务从哪个模型获取结果
            if (!StringUtil.isNullOrEmpty(toProductImageResult.getModelName())
                    && toProductImageResult.getModelName().equals("flux")) {
                Project project = projectService.getById(toProductImageResult.getProjectId());
                if (Objects.isNull(project)) {
                    throw new BusinessException("unknown project");
                }
                String fluxResult;
                if (toProductImageResult.getStatus().equals("Success") && !StringUtil.isNullOrEmpty(toProductImageResult.getUrl())) {
                    fluxResult = toProductImageResult.getUrl();
                } else {
                    String objectName = project.getAccountId() + "/relight_image/" + taskId + ".png";
                    fluxResult = generateService.getFluxResult(taskId, objectName);
                }

                if (StringUtil.isNullOrEmpty(fluxResult)) {
                    toProductImageResult.setStatus("Fail");
                    toProductImageResultMapper.updateById(toProductImageResult);
                    results.add(new MagicToolResultVO(taskId, "Fail"));
                } else if (fluxResult.equals("Fail") || fluxResult.equals("Pending")) {
                    toProductImageResult.setStatus(fluxResult);
                    toProductImageResultMapper.updateById(toProductImageResult);
                    results.add(new MagicToolResultVO(taskId, fluxResult));
                } else {
                    results.add(processFluxResult(fluxResult, toProductImageResult, taskId, toProductImageRecord.getPrompt()));
                    // 扣积分
                    Boolean flag = creditsService.taskCreditsDeduction(project.getAccountId(), taskId);
                    if (flag) creditsService.updateChangedCredits(String.valueOf(project.getAccountId()), taskId);
                }
                // 将积分暂扣区的积分移除
                if (toProductImageResult.getStatus().equals("Fail")) {
                    creditsService.deleteCreditsDeduction(project.getAccountId(), taskId);
                }

                return;
            }

            String key = relightResultKey + ":" + taskId;
            MagicToolResultVO magicToolResultVO = new Gson().fromJson(redisUtil.getFromString(key), MagicToolResultVO.class);
            if (!Objects.isNull(magicToolResultVO) && !StringUtil.isNullOrEmpty(magicToolResultVO.getUrl())) {
                String url = magicToolResultVO.getUrl();
                magicToolResultVO.setDirection(toProductImageResult.getDirection());
                magicToolResultVO.setBrightenValue(toProductImageResult.getBrightenValue());
                magicToolResultVO.setImageStrength(toProductImageResult.getImageStrength());
                magicToolResultVO.setPrompt(toProductImageRecord.getPrompt());
                if (url.substring(url.lastIndexOf("/") + 1).equals("white_image.jpg")) {
                    magicToolResultVO.setStatus("Invalid");
                } else {
                    magicToolResultVO.setUrl(minioUtil.getPreSignedUrl(url, CommonConstant.MINIO_IMAGE_EXPIRE_TIME));

                    magicToolResultVO.setResultType(toProductImageResult.getResultType());
                    magicToolResultVO.setElementId(toProductImageResult.getElementId());
                    magicToolResultVO.setElementType(toProductImageResult.getElementType());
                    if (toProductImageResult.getElementType().equals("ProductElement")) {
                        ToProductElement toProductElement = toProductElementMapper.selectById(toProductImageResult.getElementId());
                        magicToolResultVO.setSourceUrl(minioUtil.getPreSignedUrl(toProductElement.getUrl(), 24 * 60));
                    } else {
                        ToProductImageResult toProductImageResult1 = toProductImageResultMapper.selectById(toProductImageResult.getElementId());
                        magicToolResultVO.setSourceUrl(minioUtil.getPreSignedUrl(toProductImageResult1.getUrl(), 24 * 60));
                    }
                    Long parentId = collectionSortService.getParentIdByElementIdAndElementType(toProductImageResult.getElementId(), toProductImageResult.getElementType());
                    magicToolResultVO.setParentId(parentId);
                }
            } else if (Objects.isNull(magicToolResultVO)) {
                magicToolResultVO = new MagicToolResultVO();
            }
            if (!StringUtil.isNullOrEmpty(magicToolResultVO.getStatus())) collect.add(magicToolResultVO.getStatus());
            results.add(magicToolResultVO);
        });
        return results;
    }

    public static String convert(InputStream inputStream) {
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
            return reader.lines().collect(Collectors.joining("\n"));
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void deleteToProductRelightResult(Long id, Long projectId, String type) {
        // 1. 权限校验和删除主数据
        Long accountId = UserContext.getUserHolder().getId();
        Project project = projectService.getById(projectId);
        if (!project.getAccountId().equals(accountId)) {
            throw new IllegalArgumentException("项目不属于当前账号");
        }

        // 2. 删除主表数据
        UpdateWrapper<ToProductImageResult> wrapper = new UpdateWrapper<>();
        wrapper.lambda().eq(ToProductImageResult::getProjectId, projectId)
                .eq(ToProductImageResult::getId, id).or().eq(ToProductImageResult::getElementId, id)
                .set(ToProductImageResult::getIsDeleted, 1);

        int update = toProductImageResultMapper.update(null, wrapper);
        log.info("删除 {} 结果, id={}, 影响行数={}", type, id, update);

        if (update == 0) {
            return; // 未删除任何数据，直接返回
        }

        // 3. 查询所有被删除的排序项（按sort升序）
        List<CollectionSort> deletedItems = collectionSortMapper.selectList(
                new QueryWrapper<CollectionSort>()
                        .eq("project_id", projectId)
                        .eq("relation_id", id)
                        .eq("relation_type", type)
                        .orderByAsc("sort")
        );

        if (deletedItems.isEmpty()) return;

        // 4. 删除这些记录
        int deletedCount = collectionSortMapper.delete(
                new QueryWrapper<CollectionSort>()
                        .eq("project_id", projectId)
                        .eq("relation_id", id)
                        .eq("relation_type", type)
        );
        log.info("删除排序记录：id={}, type={}, 影响行数={}", id, type, deletedCount);

        // 5. 对每个被删除的sort值，单独调整后续记录
        for (CollectionSort deletedItem : deletedItems) {
            collectionSortMapper.update(
                    null,
                    new UpdateWrapper<CollectionSort>()
                            .eq("project_id", projectId)
                            .gt("sort", deletedItem.getSort())
                            .setSql("sort = sort - 1") // 每条SQL只减1
            );
        }
    }

    @Override
    public String likeHistoryRelSketch() {
        QueryWrapper<UserLikeGroup> qw = new QueryWrapper<>();
        List<UserLikeGroup> userLikeGroups = userLikeGroupMapper.selectList(qw);
        List<List<Map<String, Object>>> result = new ArrayList<>();

        for (UserLikeGroup userLikeGroup : userLikeGroups) {
            Long accountId = userLikeGroup.getAccountId();
            Long collectionId = userLikeGroup.getCollectionId();

            // 提前转换为Set以提高contains的效率
            List<CollectionElement> collectionElements = getCollectionElementsByCollectionId(collectionId);
            Set<String> urlSet = collectionElements.stream()
                    .map(CollectionElement::getUrl)
                    .collect(Collectors.toSet());

            List<UserLike> userLikes = getUserLikesByGroupId(userLikeGroup.getId());

            for (UserLike userLike : userLikes) {
                List<Map<String, Object>> userLikeSketchList = new ArrayList<>();
                List<DesignItemDetail> designItemDetails = getDesignItemDetails(userLike.getDesignItemId());

                for (DesignItemDetail designItemDetail : designItemDetails) {
                    Map<String, Object> sketch = new HashMap<>();
                    String path = designItemDetail.getPath();

                    // 下载路径到本地
//                    if (!StringUtils.isEmpty(path)) {
//                        String bucketName = minioUtil.getBucketNameFromPath(path);
//                        String objectName = minioUtil.getObjectNameFromPath(path);
//                        String localBasePath = "C:\\workspace\\fileData\\minio";
//                        String localFilePath = Paths.get(localBasePath, path).toString();
//
//                        // 检查文件是否已经存在，避免重复下载
//                        File localFile = new File(localFilePath);
//                        if (!localFile.exists()) {
//                            minioUtil.downloadMinioObjectToLocal(bucketName, objectName, localFilePath);
//                        } else {
//                            log.info("File already exists, skipping download: {}", localFilePath);
//                        }
//                    }

                    Long designId = designItemDetail.getDesignId();
                    Design design = designMapper.selectById(designId);
                    if (null == design) {
                        continue;
                    }
                    if (design.getSingleOverall().equals("single")) {
                        continue;
                    }
                    if (design.getModelType().equals("System")) {
                        SysFile sysFile = sysFileMapper.selectById(design.getTemplateId());
                        if (null == sysFile) {
                            continue;
                        }
                        sketch.put("sex", sysFile.getLevel2Type().equals("Male") ? "Male" : "Female");
                    } else {
                        Library library = libraryMapper.selectById(design.getTemplateId());
                        if (null == library) {
                            continue;
                        }
                        sketch.put("sex", library.getLevel2Type().equals("Female") ? "Female" : "Male");
                    }

                    sketch.put("type", designItemDetail.getType());
                    sketch.put("path", path);
                    sketch.put("beSelected", urlSet.contains(path));
                    sketch.put("accountId", accountId);

                    if (path.contains("aida-sys-image/images/")) {
                        String replace = path.replace("aida-sys-image/images/", "");
                        String style = getStyleByUrl(replace);
                        if (!StringUtils.isEmpty(style)) {
                            sketch.put("style", style);
                        }
                    }
                    userLikeSketchList.add(sketch);
                }
                if (CollectionUtil.isNotEmpty(userLikeSketchList)) {
                    result.add(userLikeSketchList);
                }
            }
        }

        // 将结果以美观的JSON形式保存到文件中
        saveResultAsPrettyJson(result, "C:\\Users\\10233\\Desktop\\result.json");

        return null;
    }

    @Override
    public String download() {
        // 下载 aida-collection-element bucket 下所有 Sketchboard 文件夹内容
//        String sketchboardLocalPath = "C:\\workspace\\fileData\\minio";
//        minioUtil.downloadSketchboardDirectories(sketchboardLocalPath);
//
//        // 下载整个 aida-users bucket
//        String aidaUsersLocalPath = "C:\\workspace\\fileData\\minio";
//        minioUtil.downloadEntireBucket("aida-users", aidaUsersLocalPath);
        return null;
    }

    // 提取公共方法
    private List<CollectionElement> getCollectionElementsByCollectionId(Long collectionId) {
        QueryWrapper<CollectionElement> qw = new QueryWrapper<>();
        qw.lambda().eq(CollectionElement::getCollectionId, collectionId)
                .eq(CollectionElement::getLevel1Type, "Sketchboard");
        return collectionElementMapper.selectList(qw);
    }

    private List<UserLike> getUserLikesByGroupId(Long groupId) {
        QueryWrapper<UserLike> qw = new QueryWrapper<>();
        qw.lambda().eq(UserLike::getUserLikeGroupId, groupId);
        return userLikeMapper.selectList(qw);
    }

    private List<DesignItemDetail> getDesignItemDetails(Long designItemId) {
        QueryWrapper<DesignItemDetail> qw = new QueryWrapper<>();
        qw.lambda().eq(DesignItemDetail::getDesignItemId, designItemId)
                .ne(DesignItemDetail::getType, "Body");
        return designItemDetailService.list(qw);
    }

    private void saveResultAsPrettyJson(List<List<Map<String, Object>>> result, String filePath) {
        // 使用一个 Map<String, Object> 将结果存储为字符串键
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("data", result);

        try (FileWriter file = new FileWriter(filePath)) {
            // 使用 JSONObject 将转换后的 Map 转为 JSON
            JSONObject jsonObject = new JSONObject(resultMap);
            // 格式化输出为美观的 JSON
            file.write(JSON.toJSONString(jsonObject, SerializerFeature.PrettyFormat));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    private String getStyleByUrl(String replace) {
        String[] split = replace.split("/");
        String tableName = getTableName(split);
        if (StringUtils.isEmpty(tableName)) {
            return null;
        } else {
            replace = split[1] + "/" + split[2];
            return attributeRetrievalMapper.getStyleByUrl(replace, tableName);
        }
    }

    private String getTableName(String[] split) {
        switch (split[0]) {
            case "female": {
                switch (split[1]) {
                    case "blouse": {
                        return "female_top";
                    }
                    case "trousers": {
                        return "female_pants";
                    }
                    case "skirt": {
                        return "female_skirt";
                    }
                    case "outwear": {
                        return "female_outwear";
                    }
                    case "dress": {
                        return "female_dress";
                    }
                    default: {
                        return null;
                    }
                }
            }
            case "male": {
                switch (split[1]) {
                    case "top": {
                        return "male_top";
                    }
                    case "bottom": {
                        return "male_bottom";
                    }
                    case "outwear": {
                        return "male_outwear";
                    }
                    default: {
                        return null;
                    }
                }
            }
            default: {
                return null;
            }
        }
    }

    @Override
    public Boolean productImageInitialize(ProductImageInitializeDTO productImageInitializeDTO) {
        AuthPrincipalVo userHolder = UserContext.getUserHolder();
        productImageService.asyncInitialize(productImageInitializeDTO.getBrandId(), userHolder);
        return true;
    }

    @Override
    public InitializeProgressVO getInitializeProgress(ProductImageInitializeDTO productImageInitializeDTO) {
        InitializeProgressVO vo = new InitializeProgressVO();

//        QueryWrapper<>

        ProgressDTO dto = redisUtil.getTaskProgressDTO(String.valueOf(productImageInitializeDTO.getBrandId()));

        if (Objects.isNull(dto)) {
            vo.setAnalyzed(false);
            return vo;
        }
        vo.setAnalyzed(true);
        vo.setComputeTime(dto.getComputeTime());
        if (dto.getTotal() == 0 || dto.isError()) {
            vo.setPercent(0.0);
            return vo;
        }
        vo.setPercent(dto.getCurrent() * 1.0 / dto.getTotal());
        return vo;
    }

    private ProductImageAttribute toAttrDict(AttributeRecognitionJSON attrDictJSON) {
        ProductImageAttribute attributeRetrieval = new ProductImageAttribute();

        // 处理 imgName
//        if (CollectionUtil.isNotEmpty(attrDictJSON.getImgName()) && attrDictJSON.getImgName().get(0) != null) {
//            attributeRetrieval.setImgName(attrDictJSON.getImgName().get(0));
//        }
        // 处理 length
        if (CollectionUtil.isNotEmpty(attrDictJSON.getLength()) && attrDictJSON.getLength().get(0) != null) {
            attributeRetrieval.setLength(attrDictJSON.getLength().get(0));
        }
        // 处理 sleeveLength
        if (CollectionUtil.isNotEmpty(attrDictJSON.getSleeveLength()) && attrDictJSON.getSleeveLength().get(0) != null) {
            attributeRetrieval.setSleeveLength(attrDictJSON.getSleeveLength().get(0));
        }
        // 处理 sleeveShape
        if (CollectionUtil.isNotEmpty(attrDictJSON.getSleeveShape()) && attrDictJSON.getSleeveShape().get(0) != null) {
            attributeRetrieval.setSleeveShape(attrDictJSON.getSleeveShape().get(0));
        }
        // 处理 sleeveShoulder
        if (CollectionUtil.isNotEmpty(attrDictJSON.getSleeveShoulder()) && attrDictJSON.getSleeveShoulder().get(0) != null) {
            attributeRetrieval.setSleeveShoulder(attrDictJSON.getSleeveShoulder().get(0));
        }
        // 处理 neckline
        if (CollectionUtil.isNotEmpty(attrDictJSON.getNeckline()) && attrDictJSON.getNeckline().get(0) != null) {
            attributeRetrieval.setNeckline(attrDictJSON.getNeckline().get(0));
        }
        // 处理 collar
        if (CollectionUtil.isNotEmpty(attrDictJSON.getCollar()) && attrDictJSON.getCollar().get(0) != null) {
            attributeRetrieval.setCollar(attrDictJSON.getCollar().get(0));
        }
        // 处理 design
        if (CollectionUtil.isNotEmpty(attrDictJSON.getDesign()) && attrDictJSON.getDesign().get(0) != null) {
            attributeRetrieval.setDesign(attrDictJSON.getDesign().get(0));
        }
        // 处理 silhouette
        if (CollectionUtil.isNotEmpty(attrDictJSON.getSilhouette()) && attrDictJSON.getSilhouette().get(0) != null) {
            attributeRetrieval.setSilhouette(attrDictJSON.getSilhouette().get(0));
        }
        // 处理 type
        if (CollectionUtil.isNotEmpty(attrDictJSON.getType()) && attrDictJSON.getType().get(0) != null) {
            attributeRetrieval.setType(attrDictJSON.getType().get(0));
        }
        // 处理 openingType
        if (CollectionUtil.isNotEmpty(attrDictJSON.getOpeningType()) && attrDictJSON.getOpeningType().get(0) != null) {
            attributeRetrieval.setOpeningType(attrDictJSON.getOpeningType().get(0));
        }
        // 处理 subtype
        if (CollectionUtil.isNotEmpty(attrDictJSON.getSubtype()) && attrDictJSON.getSubtype().get(0) != null) {
            attributeRetrieval.setSubtype(attrDictJSON.getSubtype().get(0));
        }

        return attributeRetrieval;
    }

//    private ProductImageAttribute toAttrDict(AttributeRecognitionJSON attrDictJSON) {
//        ProductImageAttribute attributeRetrieval = new ProductImageAttribute();

    /// /        attributeRetrieval.setImgName(attrDictJSON.getImgName().get(0));
    /// /        attributeRetrieval.setLength(attrDictJSON.getLength().get(0));
    /// /        attributeRetrieval.setSleeveLength(attrDictJSON.getSleeveLength().get(0));
    /// /        attributeRetrieval.setSleeveShape(attrDictJSON.getSleeveShape().get(0));
    /// /        attributeRetrieval.setSleeveShoulder(attrDictJSON.getSleeveShoulder().get(0));
    /// /        attributeRetrieval.setNeckline(attrDictJSON.getNeckline().get(0));
    /// /        attributeRetrieval.setCollar(attrDictJSON.getCollar().get(0));
//        if (CollectionUtil.isNotEmpty(attrDictJSON.getDesign()) && attrDictJSON.getDesign().get(0) != null) {
//            attributeRetrieval.setDesign(attrDictJSON.getDesign().get(0));
//        }
//        if (CollectionUtil.isNotEmpty(attrDictJSON.getSilhouette()) && attrDictJSON.getSilhouette().get(0) != null) {
//            attributeRetrieval.setSilhouette(attrDictJSON.getSilhouette().get(0));
//        }
//        if (CollectionUtil.isNotEmpty(attrDictJSON.getType()) && attrDictJSON.getType().get(0) != null) {
//            attributeRetrieval.setType(attrDictJSON.getType().get(0));
//        }
//        if (CollectionUtil.isNotEmpty(attrDictJSON.getSubtype()) && attrDictJSON.getSubtype().get(0) != null) {
//            attributeRetrieval.setSubtype(attrDictJSON.getSubtype().get(0));
//        }
//        if (CollectionUtil.isNotEmpty(attrDictJSON.getOpeningType()) && attrDictJSON.getOpeningType().get(0) != null) {
//            attributeRetrieval.setOpeningType(attrDictJSON.getOpeningType().get(0));
//        }
//        return attributeRetrieval;
//    }
    @Override
    public IPage<ProjectVO> getPage(ProjectQueryDTO query) {
        AuthPrincipalVo authPrincipalVo = UserContext.getUserHolder();
        // 分页数据
        QueryWrapper<Project> queryWrapper = new QueryWrapper<>();

        queryWrapper.eq("account_id", authPrincipalVo.getId());
        if (Objects.nonNull(query.getId())) {
            queryWrapper.eq("id", query.getId());
        }
//        queryWrapper.isNull("parent_id");
        if (!StringUtils.isEmpty(query.getProjectName())) {
            queryWrapper.like("name", query.getProjectName());
        }
        if (Objects.nonNull(query.getStartDate())) {
            queryWrapper.ge("update_time", new Date(query.getStartDate()));
        }
        if (Objects.nonNull(query.getEndDate())) {
            queryWrapper.le("update_time", new Date(query.getEndDate()));
        }
        if (Objects.nonNull(query.getProcess()) && !query.getProcess().isEmpty()) {
//        if (!StringUtils.isEmpty(query.getProcess())) {
            // todo 获取历史列表，允许传入多个类型
            queryWrapper.in("process", query.getProcess());
//            queryWrapper.eq("process", query.getProcess());
        }
        // 新增分类过滤
        if (CollectionUtil.isNotEmpty(query.getClassificationIdList())) {
            List<Long> projectIdList = new ArrayList<>();
            if (query.getIntersection() == 0) {
                for (Long classificationId : query.getClassificationIdList()) {
                    projectIdList.addAll(classificationService.getLibraryIdListByClassificationId(classificationId));
                }
                if (CollectionUtil.isNotEmpty(projectIdList)) {
                    queryWrapper.in("id", projectIdList);
                } else {
                    return new Page<>();
                }
            } else {
                for (int i = 0; i < query.getClassificationIdList().size(); i++) {
                    List<Long> historyIdListByClassificationId = classificationService.getLibraryIdListByClassificationId(query.getClassificationIdList().get(i));
                    if (i == 0) {
                        projectIdList.addAll(historyIdListByClassificationId);
                    } else {
                        projectIdList.retainAll(historyIdListByClassificationId);
                    }
                    if (CollectionUtil.isEmpty(projectIdList)) {
                        return new Page<>();
                    }
                }
                queryWrapper.in("id", projectIdList);
            }
        }
        if (query.getAsc() != null && query.getAsc() == 1) {
            queryWrapper.orderByAsc("update_time");
        } else {
            queryWrapper.orderByDesc("update_time");
        }
        IPage<Project> page = projectService.page(
                new Page<>(query.getPage(), query.getSize()), queryWrapper);
        if (CollectionUtils.isEmpty(page.getRecords())) {
            return new Page<>();
        }
        Set<Long> projectIdSet = page.getRecords().stream().map(Project::getId).collect(Collectors.toSet());
        QueryWrapper<UserLikeGroup> userLikeGroupQueryWrapper = new QueryWrapper<>();
        userLikeGroupQueryWrapper.lambda().in(UserLikeGroup::getProjectId, projectIdSet);
        List<UserLikeGroup> userLikeGroups = userLikeGroupMapper.selectList(userLikeGroupQueryWrapper);

        Map<Long, List<UserLikeVO>> groupDetailMap = new HashMap<>();

        if (CollectionUtil.isNotEmpty(userLikeGroups)) {
            List<Long> groupIds = userLikeGroups.stream().map(UserLikeGroup::getId).collect(Collectors.toList());
            List<UserLikeVO> groupDetails = userLikeService.getGroupDetails(groupIds);

            groupDetailMap = groupDetails.stream()
                    .collect(Collectors.groupingBy(UserLikeVO::getUserLikeGroupId));
        }

        Account account = accountService.getById(authPrincipalVo.getId());
        Map<Long, List<UserLikeVO>> finalGroupDetailMap = groupDetailMap;
        IPage<ProjectVO> convert = page.convert((Function<Project, ProjectVO>) project -> {
            if (project != null) {
                ProjectVO projectVO = CopyUtil.copyObject(project, ProjectVO.class);
                // 用于排序的时间
                LocalDateTime orderTime = Objects.isNull(project.getUpdateTime()) ? project.getCreateTime() : project.getUpdateTime();
                projectVO.setUpdateDate(orderTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());

                QueryWrapper<UserLikeGroup> userLikeGroupQueryWrapper1 = new QueryWrapper<>();
                userLikeGroupQueryWrapper1.lambda().eq(UserLikeGroup::getProjectId, projectVO.getId());
                UserLikeGroup userLikeGroup = userLikeGroupMapper.selectOne(userLikeGroupQueryWrapper1);
                if (Objects.nonNull(userLikeGroup)) {
                    UserLikeGroupVO userLikeGroupVO = CopyUtil.copyObject(userLikeGroup, UserLikeGroupVO.class);
                    userLikeGroupVO.setAuthor(account.getUserName());
                    //count 和detail
                    if (finalGroupDetailMap.keySet().contains(userLikeGroupVO.getId())) {
                        List<UserLikeVO> details = finalGroupDetailMap.get(userLikeGroupVO.getId());
                        for (UserLikeVO detail : details) {
                            TDesignPythonOutfit tDesignPythonOutfit = designPythonOutfitMapper.selectById(detail.getDesignOutfitId());
                            detail.setUrl(minioUtil.getPreSignedUrl(tDesignPythonOutfit.getDesignUrl(), 24 * 60));
                        }
                        userLikeGroupVO.setGroupDetails(details);
                        userLikeGroupVO.setSketchCount(CollectionUtils.isEmpty(details) ? 0 : details.size());
                    } else {
                        userLikeGroupVO.setSketchCount(0);
                    }
                    if (userLikeGroupVO.getOriginal() == 0) {
                        userLikeGroupVO.setOriginalAccountName(accountService.getById(userLikeGroupVO.getOriginalAccountId()).getUserName());
                        Portfolio byId = portfolioMapper.getByIdAll(userLikeGroupVO.getOriginalPortfolioId());
                        if (Objects.nonNull(byId)) {
                            String portfolioName = byId.getPortfolioName();
                            userLikeGroupVO.setOriginalPortfolioName(portfolioName);
                        }
                    }
                    projectVO.setUserLikeGroupVO(userLikeGroupVO);
                }
                return projectVO;
            }
            return null;
        });
        return convert;
    }


    @Override
    public ModuleChooseVO getModuleContent(ProjectDTO projectDTO) {
        ModuleChooseVO moduleChooseVO = new ModuleChooseVO();
        moduleChooseVO.setProjectId(projectDTO.getId());
//        UserLikeCollectionVO userLikeCollectionVO = new UserLikeCollectionVO();
        LambdaQueryWrapper<Project> projectLambdaQueryWrapper = new LambdaQueryWrapper<>();
        projectLambdaQueryWrapper.select(Project::getAccountId).eq(Project::getId, projectDTO.getId());
        Project project = projectService.getOne(projectLambdaQueryWrapper);

        LambdaQueryWrapper<CollectionElement> queryWrapper = new LambdaQueryWrapper<>();
        // 判空处理
        if (project != null && project.getAccountId() != null) {
            queryWrapper.eq(CollectionElement::getAccountId, project.getAccountId());
        }
        queryWrapper.eq(CollectionElement::getProjectId, projectDTO.getId());

        List<CollectionElement> allCollectionElements = collectionElementMapper.selectList(queryWrapper);

        for (String module : projectDTO.getModuleList()) {
            if (module.equals(Module.colorBoard.name())) {
                List<CollectionElement> collectionElements = allCollectionElements.stream()
                        .filter(element -> CollectionLevel1TypeEnum.COLOR_BOARD.getRealName().equals(element.getLevel1Type()))
                        .collect(Collectors.toList());
                moduleChooseVO.setColorBoard(collectionService.resolveColorBoard(collectionElements));
            } else if (module.equals(Module.moodBoard.name())) {
                MoodBoardModuleChooseVO moodBoardModuleChooseVO = new MoodBoardModuleChooseVO();

                List<CollectionElement> collectionElements = allCollectionElements.stream()
                        .filter(element -> CollectionLevel1TypeEnum.MOOD_BOARD.getRealName().equals(element.getLevel1Type()))
                        .collect(Collectors.toList());

                List<CollectionElementVO> list = new ArrayList<>();
                for (CollectionElement collectionElement : collectionElements) {
                    if (null != collectionElement.getIsCompositeImage() && collectionElement.getIsCompositeImage() == 1) {
                        moodBoardModuleChooseVO.setMoodTemplateId(String.valueOf(collectionElement.getId()));
                        moodBoardModuleChooseVO.setMoodTemplateName(collectionElement.getName());
                        moodBoardModuleChooseVO.setMoodTemplateUrl(getMinioUrl(collectionElement.getUrl()));

                        String moodboardPositionString = collectionService.getMoodboardPositionString(collectionElement.getId());
                        if (!StringUtils.isEmpty(moodboardPositionString)) {
                            moodBoardModuleChooseVO.setMoodboardPosition(moodboardPositionString);
                        }
                        continue;
                    }
                    CollectionElementVO collectionElementVO = CopyUtil.copyObject(collectionElement, CollectionElementVO.class);
                    collectionElementVO.setDesignType(DesignTypeEnum.COLLECTION.getRealName());
                    String url = collectionElement.getUrl();
                    collectionElementVO.setOriginalUrl(url);
                    if (minioUtil.doesObjectExist(url)) {
                        collectionElementVO.setUrl(getMinioUrl(url));
                    }
                    if (minioUtil.doesObjectExist(collectionElementVO.getOriginalUrl())) {
                        list.add(collectionElementVO);
                    }
                }
                moodBoardModuleChooseVO.setMoodBoards(list);
                moduleChooseVO.setMoodBoard(moodBoardModuleChooseVO);
            } else if (module.equals(Module.printBoard.name())) {

                List<CollectionElement> collectionElements = allCollectionElements.stream()
                        .filter(element -> CollectionLevel1TypeEnum.PRINT_BOARD.getRealName().equals(element.getLevel1Type()))
                        .collect(Collectors.toList());
                List<CollectionElementVO> list = new ArrayList<>();

                for (CollectionElement collectionElement : collectionElements) {
                    CollectionElementVO collectionElementVO = CopyUtil.copyObject(collectionElement, CollectionElementVO.class);
                    collectionElementVO.setIsPin(collectionElement.getHasPin());
                    collectionElementVO.setDesignType(DesignTypeEnum.COLLECTION.getRealName());
                    String url = collectionElement.getUrl();
                    collectionElementVO.setOriginalUrl(url);
                    if (minioUtil.doesObjectExist(url)) {
                        collectionElementVO.setUrl(getMinioUrl(url));
                    }
                    if (minioUtil.doesObjectExist(collectionElementVO.getOriginalUrl())) {
                        list.add(collectionElementVO);
                    }
                }
                moduleChooseVO.setPrintBoard(list);
            } else if (module.equals(Module.sketchBoard.name())) {

                List<CollectionElement> collectionElements = allCollectionElements.stream()
                        .filter(element -> CollectionLevel1TypeEnum.SKETCH_BOARD.getRealName().equals(element.getLevel1Type()))
                        .collect(Collectors.toList());
                List<CollectionElementVO> list = new ArrayList<>();

                for (CollectionElement collectionElement : collectionElements) {
                    CollectionElementVO collectionElementVO = CopyUtil.copyObject(collectionElement, CollectionElementVO.class);
                    collectionElementVO.setIsPin(collectionElement.getHasPin());
                    collectionElementVO.setDesignType(DesignTypeEnum.COLLECTION.getRealName());
                    String url = collectionElement.getUrl();
                    collectionElementVO.setOriginalUrl(url);
                    if (minioUtil.doesObjectExist(url)) {
                        collectionElementVO.setUrl(getMinioUrl(url));
                        if (url.contains(".")) {
                            String[] split = url.split("\\.");
                            collectionElementVO.setUrlWithWhiteSide(getMinioUrl(split[0] + "-show." + split[1]));
                        } else {
                            collectionElementVO.setUrlWithWhiteSide(getMinioUrl(url + "-show"));
                        }
                    }
                    if (minioUtil.doesObjectExist(collectionElementVO.getOriginalUrl())) {
                        list.add(collectionElementVO);
                    }
                }
                List<CollectionSketchVO> voList = new ArrayList<>();
                for (CollectionElement collectionElement : collectionElements) {
                    CollectionSketchVO vo = CopyUtil.copyObject(collectionElement, CollectionSketchVO.class);
                    String url = collectionElement.getUrl();
                    if (url.contains(".")) {
                        String[] split = url.split("\\.");
                        vo.setUrlWithWhiteSide(getMinioUrl(split[0] + "-show." + split[1], true));
                    } else {
                        vo.setUrlWithWhiteSide(getMinioUrl(url + "-show", true));
                    }
                    vo.setIsPin(collectionElement.getHasPin());
                    vo.setLevel2Type(collectionElement.getLevel2Type());
                    vo.setDesignType("Collection");
                    vo.setSketchBoardId(collectionElement.getId());
                    voList.add(vo);
                }
                voList.sort(Comparator.comparing(CollectionSketchVO::getSketchBoardId));
                moduleChooseVO.setBoundingBox(voList);
                moduleChooseVO.setSketchBoard(list);
            } else if (module.equals(Module.design.name())) {
                DesignModuleChooseVO vo = new DesignModuleChooseVO();
                QueryWrapper<CollectionSort> userLikeSortQueryWrapper = new QueryWrapper<>();
                userLikeSortQueryWrapper.lambda().eq(CollectionSort::getProjectId, projectDTO.getId());
                userLikeSortQueryWrapper.lambda().isNull(CollectionSort::getParentId);
                userLikeSortQueryWrapper.lambda().eq(CollectionSort::getRelationType, CollectionType.DESIGN.getValue());
                userLikeSortQueryWrapper.lambda().orderByAsc(CollectionSort::getSort);
                List<CollectionSort> userLikeSortList = collectionSortMapper.selectList(userLikeSortQueryWrapper);

                if (CollectionUtils.isEmpty(userLikeSortList)) {
                    moduleChooseVO.setDesign(vo);
                } else {
                    List<AllCollectionVO> list = new ArrayList<>();

                    for (CollectionSort collectionSort : userLikeSortList) {
                        UserLike userLike = userLikeMapper.selectById(collectionSort.getRelationId());
                        UserLikeVO o = CopyUtil.copyObject(userLike, UserLikeVO.class);
                        TDesignPythonOutfit tDesignPythonOutfit1 = designPythonOutfitMapper.selectById(o.getDesignOutfitId());
                        o.setUrl(tDesignPythonOutfit1.getDesignUrl());
                        if (o.getUrl().contains("/")) {
                            int index = o.getUrl().lastIndexOf("/");
                            o.setPictureName(o.getUrl().substring(index + 1));
                        }
                        o.setDesignOutfitUrl(getMinioUrl(o.getUrl()));
                        QueryWrapper<TDesignPythonOutfit> qw = new QueryWrapper<>();
                        qw.lambda().eq(TDesignPythonOutfit::getDesignItemId, o.getDesignItemId());
                        List<TDesignPythonOutfit> tDesignPythonOutfits = designPythonOutfitMapper.selectList(qw);
                        if (CollectionUtil.isNotEmpty(tDesignPythonOutfits)) {
                            TDesignPythonOutfit tDesignPythonOutfit = tDesignPythonOutfits.get(0);
                            o.setDesignOutfitId(tDesignPythonOutfit.getId());
                        }

                        o.setSort(collectionSort.getSort());
                        o.setUserLikeSortId(collectionSort.getId());
                        o.setRelationType(collectionSort.getRelationType());
                        o.setCollectionType(CollectionType.DESIGN.getValue());
                        o.setResultType(CollectionType.DESIGN.getValue());
                        QueryWrapper<CollectionSort> childCollectionQw = new QueryWrapper<>();
                        childCollectionQw.lambda().eq(CollectionSort::getParentId, collectionSort.getId());
                        childCollectionQw.lambda().orderByAsc(CollectionSort::getSort);
                        List<CollectionSort> childSortList = collectionSortMapper.selectList(childCollectionQw);
                        List<AllCollectionVO> childList = new ArrayList<>();
                        for (CollectionSort userLikeSort : childSortList) {
                            if (userLikeSort.getRelationType().equals(CollectionType.TO_PRODUCT_IMAGE.getValue())) {
                                ToProductImageResult toProductImageResult = toProductImageResultMapper.selectById(userLikeSort.getRelationId());
                                if (isGenerateTaskFailed(toProductImageResult.getStatus(), toProductImageResult.getCreateTime())) {
                                    continue;
                                }
                                toProductImageResult.setUrl(getMinioUrl(toProductImageResult.getUrl()));
                                ToProductImageResultVO toProductImageResultVO = CopyUtil.copyObject(toProductImageResult, ToProductImageResultVO.class);

                                ToProductImageRecord toProductImageRecord = toProductImageRecordMapper.selectById(toProductImageResult.getToProductImageRecordId());
                                if (Objects.isNull(toProductImageRecord)) {
                                    log.warn("toProductRecord不存在，projectId:{}, toProductImageResultId:{}", projectDTO.getId(), toProductImageResult.getId());
                                    continue;
                                }
                                toProductImageResultVO.setPrompt(toProductImageRecord.getPrompt());

                                if (toProductImageResultVO.getElementType().equals("ProductElement")) {
                                    ToProductElement toProductElement = toProductElementMapper.selectById(toProductImageResultVO.getElementId());
                                    toProductImageResultVO.setSourceUrl(getMinioUrl(toProductElement.getUrl()));
                                } else if ((toProductImageResultVO.getElementType().equals("DesignOutfit"))) {
                                    TDesignPythonOutfit tDesignPythonOutfit = designPythonOutfitMapper.selectById(toProductImageResultVO.getElementId());
                                    toProductImageResultVO.setSourceUrl(getMinioUrl(tDesignPythonOutfit.getDesignUrl()));
                                } else {
                                    ToProductImageResult toProductImageResult1 = toProductImageResultMapper.selectById(toProductImageResultVO.getElementId());
                                    toProductImageResultVO.setSourceUrl(getMinioUrl(toProductImageResult1.getUrl()));
                                }
                                toProductImageResultVO.setCollectionType(CollectionType.TO_PRODUCT_IMAGE.getValue());
                                toProductImageResultVO.setSort(userLikeSort.getSort());
                                toProductImageResultVO.setUserLikeSortId(userLikeSort.getId());
                                toProductImageResultVO.setRelationType(userLikeSort.getRelationType());
                                toProductImageResultVO.setParentId(userLikeSort.getParentId());
                                childList.add(toProductImageResultVO);
                            } else if (userLikeSort.getRelationType().equals(CollectionType.RELIGHT.getValue())) {
                                ToProductImageResult toProductImageResult = toProductImageResultMapper.selectById(userLikeSort.getRelationId());
                                if (isGenerateTaskFailed(toProductImageResult.getStatus(), toProductImageResult.getCreateTime())) {
                                    continue;
                                }
                                toProductImageResult.setUrl(getMinioUrl(toProductImageResult.getUrl()));
                                ToProductImageResultVO toProductImageResultVO = CopyUtil.copyObject(toProductImageResult, ToProductImageResultVO.class);

                                ToProductImageRecord toProductImageRecord = toProductImageRecordMapper.selectById(toProductImageResult.getToProductImageRecordId());
                                if (Objects.isNull(toProductImageRecord)) {
                                    log.warn("toProductRecord不存在，projectId:{}, toProductImageResultId:{}", projectDTO.getId(), toProductImageResult.getId());
                                    continue;
                                }
                                toProductImageResultVO.setPrompt(toProductImageRecord.getPrompt());

                                if (toProductImageResultVO.getElementType().equals("ProductElement")) {
                                    ToProductElement toProductElement = toProductElementMapper.selectById(toProductImageResultVO.getElementId());
                                    toProductImageResultVO.setSourceUrl(getMinioUrl(toProductElement.getUrl()));
                                } else if ((toProductImageResultVO.getElementType().equals("DesignOutfit"))) {
                                    TDesignPythonOutfit tDesignPythonOutfit = designPythonOutfitMapper.selectById(toProductImageResultVO.getElementId());
                                    toProductImageResultVO.setSourceUrl(getMinioUrl(tDesignPythonOutfit.getDesignUrl()));
                                } else {
                                    ToProductImageResult toProductImageResult1 = toProductImageResultMapper.selectById(toProductImageResultVO.getElementId());
                                    toProductImageResultVO.setSourceUrl(getMinioUrl(toProductImageResult1.getUrl()));
                                }
                                toProductImageResultVO.setCollectionType(CollectionType.RELIGHT.getValue());
                                toProductImageResultVO.setSort(userLikeSort.getSort());
                                toProductImageResultVO.setUserLikeSortId(userLikeSort.getId());
                                toProductImageResultVO.setRelationType(userLikeSort.getRelationType());
                                toProductImageResultVO.setParentId(userLikeSort.getParentId());
                                childList.add(toProductImageResultVO);
                            } else if (userLikeSort.getRelationType().equals(CollectionType.POSE_TRANSFORM.getValue())) {
                                PoseTransformation item = poseTransformationMapper.selectById(userLikeSort.getRelationId());
                                if (isGenerateTaskFailed(item.getTaskStatus(), item.getCreateTime())) {
                                    continue;
                                }
                                PoseTransformationVO poseTransformationVO = new PoseTransformationVO();
                                poseTransformationVO.setId(item.getId());
                                poseTransformationVO.setTaskId(item.getUniqueId());
                                poseTransformationVO.setProductImage(getMinioUrl(item.getProductImage()));
                                poseTransformationVO.setLastFrameProductImage(getMinioUrl(item.getLastFrameProductImage()));
                                poseTransformationVO.setPrompt(item.getPrompt());
                                poseTransformationVO.setGifUrl(getMinioUrl(item.getGifUrl()));
                                poseTransformationVO.setVideoUrl(getMinioUrl(item.getVideoUrl()));
                                poseTransformationVO.setFirstFrameUrl(getMinioUrl(item.getFirstFrameUrl()));
                                poseTransformationVO.setIsLiked(item.getIsLiked());
                                poseTransformationVO.setCollectionType(CollectionType.POSE_TRANSFORM.getValue());
                                poseTransformationVO.setSort(userLikeSort.getSort());
                                poseTransformationVO.setUserLikeSortId(userLikeSort.getId());
                                poseTransformationVO.setRelationType(userLikeSort.getRelationType());
                                poseTransformationVO.setResultType(CollectionType.POSE_TRANSFORM.getValue());
                                poseTransformationVO.setParentId(userLikeSort.getParentId());
                                poseTransformationVO.setModelName(item.getModelName());
                                poseTransformationVO.setPoseId(item.getPoseId());
                                poseTransformationVO.setStatus(item.getTaskStatus());
                                childList.add(poseTransformationVO);
                            }
                        }
                        o.setChildList(childList);

                        list.add(o);
                    }
                    vo.setUserLikeDetails(list);
                }

                UserLikeGroup group = getByProjectId(projectDTO.getId());
                if (Objects.nonNull(group)) {
                    Long userGroupId = group.getId();
                    vo.setUserGroupId(userGroupId);
                }
                moduleChooseVO.setDesign(vo);
            } else if (module.equals(Module.canvas.name())) {
                CavasModuleChooseVO vo = new CavasModuleChooseVO();

                UserLikeGroup userLikeGroup = getByProjectId(projectDTO.getId());

                Integer beenPublished = 0;
                QueryWrapper<Portfolio> qw = new QueryWrapper<>();
                qw.lambda().eq(Portfolio::getUserLikeGroupSourceId, userLikeGroup.getId());
                List<Portfolio> portfolios = portfolioMapper.selectList(qw);

                PortfolioDTO portfolioDTO = new PortfolioDTO();
                if (CollectionUtil.isNotEmpty(portfolios)) {

                    portfolioDTO = CopyUtil.copyObject(portfolios.get(0), PortfolioDTO.class);
                    beenPublished = 1;
                    portfolioDTO.setTagsDTO(tagsMapper.getTagByPortfolioId(portfolioDTO.getId()));
                }
                vo.setBeenPublished(beenPublished);
                vo.setPortfolioDTO(portfolioDTO);
                moduleChooseVO.setCanvas(vo);
            } else if (module.equals(Module.toProduct.name()) || module.equals(Module.relight.name())) {
                Long projectId = projectDTO.getId();
                String resultType = module.equals(Module.toProduct.name()) ? "ToProductImage" : "Relight";

                // 查询所有结果（包括喜欢和不喜欢的）
                QueryWrapper<ToProductImageResult> qw = new QueryWrapper<>();
                qw.lambda()
                        .eq(ToProductImageResult::getProjectId, projectId)
                        .eq(ToProductImageResult::getResultType, resultType);

                List<ToProductImageResult> allResults = toProductImageResultMapper.selectList(qw);

                // 准备返回对象
                ToProductOrRelightVO resultVO = new ToProductOrRelightVO();

                // 处理URL转换和分类
                List<ToProductImageResultVO> likedList = new ArrayList<>();
                List<ToProductImageResultVO> normalList = new ArrayList<>();

                for (ToProductImageResult result : allResults) {
                    // 转换URL
                    result.setUrl(getMinioUrl(result.getUrl()));
                    // 复制到VO对象
                    ToProductImageResultVO vo = CopyUtil.copyObject(result, ToProductImageResultVO.class);
                    // 设置sourceUrl
                    setSourceUrl(vo);
                    // 设置prompt
                    ToProductImageRecord toProductImageRecord = toProductImageRecordMapper.selectById(result.getToProductImageRecordId());
                    if (Objects.nonNull(toProductImageRecord)) {
                        vo.setPrompt(toProductImageRecord.getPrompt());
                    }
                    vo.setParentId(toProductImageResultService.getUnlikedResultParentId(result, null));
                    // 按isLike分类
                    if (result.getIsLike() != null && result.getIsLike() == 1) {
                        likedList.add(vo);
                    } else {
                        normalList.add(vo);
                    }
                }
                // 设置结果
                resultVO.setLikedList(likedList);
                resultVO.setList(normalList);

                // 根据模块设置返回结果
                if (module.equals(Module.toProduct.name())) {
                    moduleChooseVO.setToProduct(resultVO);
                } else {
                    moduleChooseVO.setRelight(resultVO);
                }
            } else if (module.equals(Module.deReconstruction.name())) {
                SketchReconstructionVO sketchReconstruction = generateService.getSketchReconstruction(projectDTO.getId());
                moduleChooseVO.setDeReconstruction(sketchReconstruction);
            } else if (module.equals(Module.poseTransfer.name())) {
                List<PoseTransformationVO> likedList = generateService.getPoseTransformationResult(null, projectDTO.getId(), true);
                List<PoseTransformationVO> list = generateService.getPoseTransformationResult(null, projectDTO.getId(), false);
                PoseTransferVO vo = new PoseTransferVO();
                vo.setLikedList(likedList);
                vo.setList(list);
                moduleChooseVO.setPoseTransfer(vo);
            } else if (module.equals(Module.patternMaking3D.name())) {
                QueryWrapper<ThreeDModule> qw = new QueryWrapper<>();
                qw.lambda().eq(ThreeDModule::getProjectId, projectDTO.getId());
                List<ThreeDModule> threeDModules = threeDModuleMapper.selectList(qw);
                if (CollectionUtil.isNotEmpty(threeDModules)) {
                    ThreeDModule threeDModule = threeDModules.get(0);
                    if (null != threeDModule.getThreeDSimpleId()) {
                        ThreeDModuleVO threeDModuleVO = CopyUtil.copyObject(threeDModule, ThreeDModuleVO.class);
                        if (null != threeDModule.getCollectionElementId()) {
                            CollectionElement collectionElement = collectionElementMapper.selectById(threeDModule.getCollectionElementId());
                            if (Objects.nonNull(collectionElement)) {
                                threeDModuleVO.setPrintMinioUrl(getMinioUrl(collectionElement.getUrl()));
                            }
                        }
//                        if (!StringUtils.isEmpty(threeDModuleVO.getPrintMinioUrl())) {
//                            threeDModuleVO.setPrintMinioUrl(minioUtil.getPreSignedUrl(threeDModuleVO.getPrintMinioUrl(), CommonConstant.MINIO_IMAGE_EXPIRE_TIME));
//                        }
                        moduleChooseVO.setPatternMaking3D(threeDModuleVO);
                    }
                }
            } else if (module.equals(Module.mannequin.name())) {
                List<CollectionElement> collectionElements = allCollectionElements.stream()
                        .filter(element -> CollectionLevel1TypeEnum.MODEL.getRealName().equals(element.getLevel1Type()))
                        .collect(Collectors.toList());
                List<CollectionElementVO> list = new ArrayList<>();
                if (CollectionUtil.isNotEmpty(collectionElements)) {
                    for (CollectionElement collectionElement : collectionElements) {
                        CollectionElementVO collectionElementVO = CopyUtil.copyObject(collectionElement, CollectionElementVO.class);
                        CollectionElementRelModel relModel = getCollectionElementRelModel(collectionElementVO.getId());
                        collectionElementVO.setUrl(getMinioUrl(collectionElementVO.getUrl()));
                        collectionElementVO.setMannequinRelationId(relModel.getRelationId());
                        collectionElementVO.setMannequinRelationType(relModel.getRelationType());
                        collectionElementVO.setCollectionId(collectionElement.getId());
                        list.add(collectionElementVO);
                    }
                }
                moduleChooseVO.setMannequin(list);
            } else if (module.equals(Module.uploadElement.name())) {
                QueryWrapper<ToProductElement> qw = new QueryWrapper<>();
                qw.lambda().eq(ToProductElement::getProjectId, projectDTO.getId());
                List<ToProductElement> toProductElements = toProductElementMapper.selectList(qw);
                for (ToProductElement toProductElement : toProductElements) {
                    toProductElement.setUrl(getMinioUrl(toProductElement.getUrl()));
                }
                moduleChooseVO.setUploadElement(toProductElements);
            }
        }
        return moduleChooseVO;
    }

    private String getMinioUrl(String minioPath) {
        if (!StringUtil.isNullOrEmpty(minioPath)) {
            return minioUtil.getPreSignedUrl(minioPath, CommonConstant.MINIO_IMAGE_EXPIRE_TIME);
        }
        return null;
    }

    private String getMinioUrl(String minioPath, boolean resetCatch) {
        if (!StringUtil.isNullOrEmpty(minioPath)) {
            return minioUtil.getPreSignedUrl(minioPath, CommonConstant.MINIO_IMAGE_EXPIRE_TIME, resetCatch);
        }
        return null;
    }

    // 提取出的公共方法
    private void setSourceUrl(ToProductImageResultVO vo) {
        if (vo.getElementType().equals("ProductElement")) {
            ToProductElement element = toProductElementMapper.selectById(vo.getElementId());
            vo.setSourceUrl(getMinioUrl(element.getUrl()));
        } else if (vo.getElementType().equals("DesignOutfit")) {
            TDesignPythonOutfit outfit = designPythonOutfitMapper.selectById(vo.getElementId());
            vo.setSourceUrl(getMinioUrl(outfit.getDesignUrl()));
        } else {
            ToProductImageResult result = toProductImageResultMapper.selectById(vo.getElementId());
            vo.setSourceUrl(getMinioUrl(result.getUrl()));
        }
    }

    private CollectionElementRelModel getCollectionElementRelModel(Long id) {
        QueryWrapper<CollectionElementRelModel> qw = new QueryWrapper<>();
        qw.lambda().eq(CollectionElementRelModel::getCollectionElementId, id);
        CollectionElementRelModel collectionElementRelModel = collectionElementRelModelMapper.selectOne(qw);
        return collectionElementRelModel;
    }

    private boolean isGenerateTaskFailed(String taskStatus, LocalDateTime createTime) {
        // 1. 先判断TaskStatus字段是否有值；若有值且为Fail，则失败
        if (!StringUtil.isNullOrEmpty(taskStatus)) {
            return "Fail".equals(taskStatus);
        }
        // 2. 若taskStatus无值，判断记录创建时间距离现在是否超过1小时
        if (createTime == null) {
            // 如果创建时间为null，视为失败（根据业务需求决定）
            return true;
        }
        // 计算当前时间与创建时间的差值
        Duration duration = Duration.between(createTime, LocalDateTime.now());
        // 判断是否超过1小时（3600秒）
        return duration.toHours() >= 1;
    }


    @Override
    @Transactional
    public ModuleChooseVO saveModuleContent(ModuleSaveDTO moduleSaveDTO) {
        ModuleChooseVO result = new ModuleChooseVO();
        Long accountId = UserContext.getUserHolder().getId();
        Long projectId = moduleSaveDTO.getProjectId();
        Project project = projectService.getById(projectId);

        boolean boundingBox = false;
        if (Objects.nonNull(moduleSaveDTO.getMoodBoard())) {
            MoodBoardModuleSaveDTO moodBoard = moduleSaveDTO.getMoodBoard();
            if (moodBoard.getMoodTemplateId() != null) {
                // moodboard合成图存储
                CollectionElement compositeImage = collectionElementMapper.selectById(moodBoard.getMoodTemplateId());
                if (compositeImage.getProjectId() == null) {
                    compositeImage.setProjectId(moduleSaveDTO.getProjectId());
                    compositeImage.setIsCompositeImage(1);
                    collectionElementMapper.updateById(compositeImage);
                    if (!StringUtils.isEmpty(moodBoard.getMoodboardPosition())) {
                        // 合成图位置信息通过collectElementId关联（旧逻辑通过collectionId关联）
                        moodboardPositionService.parseMoodboardPosition(moodBoard.getMoodboardPosition(), compositeImage.getId());
                    }
                }
            }
            List<DesignCollectionElementDTO> moodBoards = moodBoard.getMoodBoards();
            if (Objects.nonNull(moodBoards)) {
                QueryWrapper<CollectionElement> qw = new QueryWrapper<>();
                qw.lambda().eq(CollectionElement::getProjectId, projectId);
                qw.lambda().eq(CollectionElement::getLevel1Type, CollectionLevel1TypeEnum.MOOD_BOARD.getRealName());
                if (moodBoard.getMoodTemplateId() != null) {
                    qw.lambda().ne(CollectionElement::getId, moodBoard.getMoodTemplateId());
                }
//                qw.lambda().ne(CollectionElement::getCollectionId, 0);
                List<CollectionElement> collectionElements = collectionElementMapper.selectList(qw);
                Set<Long> old = collectionElements.stream().map(CollectionElement::getId).collect(Collectors.toSet());

                for (DesignCollectionElementDTO board : moodBoards) {
                    if (board.getDesignType().equals(DesignTypeEnum.LIBRARY.getRealName())) {
                        Library library = libraryMapper.selectById(board.getId());
                        CollectionElement collectionElement = new CollectionElement();
                        collectionElement.setAccountId(accountId);
                        collectionElement.setProjectId(projectId);
                        collectionElement.setLevel1Type(CollectionLevel1TypeEnum.MOOD_BOARD.getRealName());
                        collectionElement.setName(library.getName());
                        collectionElement.setUrl(library.getUrl());
                        collectionElement.setHasPin((byte) 0);
                        collectionElement.setMd5(library.getMd5());
                        collectionElement.setCreateDate(new Date());
                        collectionElementMapper.insert(collectionElement);
                    } else if (board.getDesignType().equals(DesignTypeEnum.GENERATE.getRealName())) {
                        GenerateDetail generateDetail = generateDetailMapper.selectById(board.getId());
                        CollectionElement collectionElement = new CollectionElement();
                        collectionElement.setAccountId(accountId);
                        collectionElement.setProjectId(projectId);
                        collectionElement.setLevel1Type(CollectionLevel1TypeEnum.MOOD_BOARD.getRealName());
//                        collectionElement.setName(generateDetail.get());
                        collectionElement.setUrl(generateDetail.getUrl());
                        collectionElement.setHasPin((byte) 0);
                        collectionElement.setMd5(generateDetail.getMd5());
                        collectionElement.setCreateDate(new Date());
                        collectionElementMapper.insert(collectionElement);
                    } else {
                        if (old.contains(board.getId())) {
                            old.remove(board.getId());
                        } else {
                            CollectionElement collectionElement = collectionElementMapper.selectById(board.getId());
                            collectionElement.setProjectId(projectId);
                            collectionElementMapper.updateById(collectionElement);
                        }
                    }
                }
                if (!CollectionUtils.isEmpty(old)) {
                    collectionElementMapper.deleteBatchIds(old);
                }
            }
        }
        if (Objects.nonNull(moduleSaveDTO.getPrintBoard())) {
            List<DesignCollectionPrintElementDTO> printBoards = moduleSaveDTO.getPrintBoard();
            QueryWrapper<CollectionElement> qw = new QueryWrapper<>();
            qw.lambda().eq(CollectionElement::getProjectId, projectId);
            qw.lambda().eq(CollectionElement::getLevel1Type, CollectionLevel1TypeEnum.PRINT_BOARD.getRealName());
            List<CollectionElement> collectionElements = collectionElementMapper.selectList(qw);
            Set<Long> old = collectionElements.stream().map(CollectionElement::getId).collect(Collectors.toSet());

            for (DesignCollectionPrintElementDTO board : printBoards) {
                if (board.getDesignType().equals(DesignTypeEnum.LIBRARY.getRealName())) {
                    Library library = libraryMapper.selectById(board.getId());
                    CollectionElement collectionElement = new CollectionElement();
                    collectionElement.setAccountId(accountId);
                    collectionElement.setProjectId(projectId);
                    collectionElement.setLevel1Type(CollectionLevel1TypeEnum.PRINT_BOARD.getRealName());
                    collectionElement.setLevel2Type(board.getLevel2Type());
                    collectionElement.setName(library.getName());
                    collectionElement.setUrl(library.getUrl());
                    collectionElement.setHasPin(board.getIsPin());
                    collectionElement.setMd5(library.getMd5());
                    collectionElement.setCreateDate(new Date());
                    collectionElementMapper.insert(collectionElement);
                } else if (board.getDesignType().equals(DesignTypeEnum.GENERATE.getRealName())) {
                    GenerateDetail generateDetail = generateDetailMapper.selectById(board.getId());
                    CollectionElement collectionElement = new CollectionElement();
                    collectionElement.setAccountId(accountId);
                    collectionElement.setProjectId(projectId);
                    collectionElement.setLevel1Type(CollectionLevel1TypeEnum.PRINT_BOARD.getRealName());
                    collectionElement.setLevel2Type(board.getLevel2Type());
//                        collectionElement.setName(generateDetail.get());
                    collectionElement.setUrl(generateDetail.getUrl());
                    collectionElement.setHasPin(board.getIsPin());
                    collectionElement.setMd5(generateDetail.getMd5());
                    collectionElement.setCreateDate(new Date());
                    collectionElementMapper.insert(collectionElement);
                } else {
                    if (old.contains(board.getId())) {
                        CollectionElement collectionElement = collectionElementMapper.selectById(board.getId());
                        collectionElement.setLevel2Type(board.getLevel2Type());
                        collectionElement.setHasPin(board.getIsPin());
                        collectionElement.setUpdateDate(new Date());
                        collectionElementMapper.updateById(collectionElement);
                        old.remove(board.getId());
                    } else {
                        CollectionElement collectionElement = collectionElementMapper.selectById(board.getId());
                        collectionElement.setProjectId(projectId);
                        collectionElement.setLevel2Type(board.getLevel2Type());
                        collectionElement.setHasPin(board.getIsPin());
                        collectionElement.setUpdateDate(new Date());
                        collectionElementMapper.updateById(collectionElement);
                    }
                }
            }
            if (!CollectionUtils.isEmpty(old)) {
                collectionElementMapper.deleteBatchIds(old);
            }
        }
        if (Objects.nonNull(moduleSaveDTO.getColorBoard())) {
            List<CollectionColorDTO> colorBoards = moduleSaveDTO.getColorBoard();
            QueryWrapper<CollectionElement> qw = new QueryWrapper<>();
            qw.lambda().eq(CollectionElement::getProjectId, projectId);
            qw.lambda().eq(CollectionElement::getLevel1Type, CollectionLevel1TypeEnum.COLOR_BOARD.getRealName());
            List<CollectionElement> collectionElements = collectionElementMapper.selectList(qw);
            Set<Long> old = collectionElements.stream().map(CollectionElement::getId).collect(Collectors.toSet());

            for (CollectionColorDTO board : colorBoards) {
                if (Objects.nonNull(board.getId()) && old.contains(Long.valueOf(board.getId()))) {
                    // ???
                    old.remove(Long.valueOf(board.getId()));
                } else {
                    CollectionElement collectionElement = new CollectionElement();
                    collectionElement.setAccountId(accountId);
                    collectionElement.setProjectId(projectId);
                    collectionElement.setLevel1Type(CollectionLevel1TypeEnum.COLOR_BOARD.getRealName());
                    collectionElement.setName(board.getName());
                    collectionElement.setHasPin((byte) 0);
                    collectionElement.setColorRgb(board.getRgbValue());
                    collectionElement.setMd5("0");
                    // 渐变色
                    if (!Objects.isNull(board.getGradient()) && !StringUtil.isNullOrEmpty(board.getGradient().getColorImg())) {
                        board.getGradient().setColorImg(null);
                    }
                    collectionElement.setGradientString(JSON.toJSONString(board.getGradient()));
                    collectionElement.setCreateDate(new Date());
                    collectionElementMapper.insert(collectionElement);
                }
            }
            if (!CollectionUtils.isEmpty(old)) {
                collectionElementMapper.deleteBatchIds(old);
            }
        }
        if (Objects.nonNull(moduleSaveDTO.getSketchBoard())) {
            boundingBox = true;
            QueryWrapper<CollectionElement> qw = new QueryWrapper<>();
            qw.lambda().eq(CollectionElement::getProjectId, projectId);
            qw.lambda().eq(CollectionElement::getLevel1Type, CollectionLevel1TypeEnum.SKETCH_BOARD.getRealName());
            List<CollectionElement> collectionElements = collectionElementMapper.selectList(qw);
            Set<Long> old = collectionElements.stream().map(CollectionElement::getId).collect(Collectors.toSet());
            List<CollectionSketchDTO> sketchBoards = moduleSaveDTO.getSketchBoard();
            for (CollectionSketchDTO board : sketchBoards) {
                if (board.getDesignType().equals(DesignTypeEnum.LIBRARY.getRealName())) {
                    Library library = libraryMapper.selectById(board.getSketchBoardId());
                    CollectionElement collectionElement = new CollectionElement();
                    collectionElement.setAccountId(accountId);
                    collectionElement.setProjectId(projectId);
                    collectionElement.setLevel1Type(CollectionLevel1TypeEnum.SKETCH_BOARD.getRealName());
                    collectionElement.setLevel2Type(board.getLevel2Type());
                    collectionElement.setLevel3Type(workspaceService.getProjectSexById(projectId));
                    collectionElement.setName(library.getName());
                    collectionElement.setUrl(library.getUrl());
                    collectionElement.setHasPin(board.getIsPin());
                    collectionElement.setMd5(library.getMd5());
                    collectionElement.setCreateDate(new Date());
                    collectionElementMapper.insert(collectionElement);
                } else if (board.getDesignType().equals(DesignTypeEnum.GENERATE.getRealName())) {
                    GenerateDetail generateDetail = generateDetailMapper.selectById(board.getSketchBoardId());
                    CollectionElement collectionElement = new CollectionElement();
                    collectionElement.setAccountId(accountId);
                    collectionElement.setProjectId(projectId);
                    collectionElement.setLevel1Type(CollectionLevel1TypeEnum.SKETCH_BOARD.getRealName());
                    collectionElement.setLevel2Type(board.getLevel2Type());
                    collectionElement.setLevel3Type(workspaceService.getProjectSexById(projectId));
//                    collectionElement.setName(generateDetail.get());
                    collectionElement.setUrl(generateDetail.getUrl());
                    collectionElement.setHasPin(board.getIsPin());
                    collectionElement.setMd5(generateDetail.getMd5());
                    collectionElement.setCreateDate(new Date());
                    collectionElementMapper.insert(collectionElement);
                } else {
                    if (old.contains(board.getSketchBoardId())) {
                        CollectionElement collectionElement = collectionElementMapper.selectById(board.getSketchBoardId());
                        collectionElement.setLevel2Type(board.getLevel2Type());
                        collectionElement.setHasPin(board.getIsPin());
                        collectionElement.setUpdateDate(new Date());
                        collectionElementMapper.updateById(collectionElement);
                        old.remove(board.getSketchBoardId());
                    } else {
                        CollectionElement collectionElement = collectionElementMapper.selectById(board.getSketchBoardId());
                        collectionElement.setProjectId(projectId);
                        collectionElement.setLevel2Type(board.getLevel2Type());
                        collectionElement.setHasPin(board.getIsPin());
                        collectionElement.setUpdateDate(new Date());
                        if (CollectionLevel1TypeEnum.SKETCH_BOARD.getRealName().equals(collectionElement.getLevel1Type())) {
                            collectionElement.setLevel3Type(workspaceService.getProjectSexById(project.getId()));
                        }
                        collectionElementMapper.updateById(collectionElement);
                    }
                }
            }
            if (!CollectionUtils.isEmpty(old)) {
                collectionElementMapper.deleteBatchIds(old);
            }
        }
        if (Objects.nonNull(moduleSaveDTO.getPatternMaking3D())) {
            PatternMaking3DDTO patternMaking3D = moduleSaveDTO.getPatternMaking3D();

            QueryWrapper<ThreeDModule> threeDModuleQueryWrapper = new QueryWrapper<>();
            threeDModuleQueryWrapper.lambda().eq(ThreeDModule::getProjectId, projectId);
            List<ThreeDModule> threeDModuleList = threeDModuleMapper.selectList(threeDModuleQueryWrapper);

            if (CollectionUtils.isEmpty(threeDModuleList)) {
                ThreeDModule threeDModule = new ThreeDModule();
                threeDModule.setProjectId(projectId);
                threeDModule.setThreeDSimpleId(patternMaking3D.getThreeDSimpleId());
                threeDModule.setX(patternMaking3D.getX());
                threeDModule.setY(patternMaking3D.getY());
//                threeDModule.setPrintMinioUrl(patternMaking3D.getPrintMinioUrl());
                threeDModule.setCollectionElementId(patternMaking3D.getCollectionElementId());
                threeDModuleMapper.insert(threeDModule);
            } else {
                ThreeDModule threeDModule = threeDModuleList.get(0);
//                if (!Objects.equals(patternMaking3D.getThreeDSimpleId(), threeDModule.getThreeDSimpleId())) {
//
//                }
                threeDModule.setThreeDSimpleId(patternMaking3D.getThreeDSimpleId());
                threeDModule.setX(patternMaking3D.getX());
                threeDModule.setY(patternMaking3D.getY());
//                threeDModule.setPrintMinioUrl(patternMaking3D.getPrintMinioUrl());
                threeDModule.setCollectionElementId(patternMaking3D.getCollectionElementId());
                threeDModuleMapper.updateById(threeDModule);
            }
        }
        if (CollectionUtil.isNotEmpty(moduleSaveDTO.getMannequin())) {
            // 目前已有的模特
            List<CollectionElementRelModel> collectionElementRelModels = collectionElementMapper.selectByProject(projectId);
            // 入参中的模特
            List<MannequinDTO> mannequin = moduleSaveDTO.getMannequin();

            // 新增的模特只有id,没有collectionElementId
            List<Long> inputMannequinIds = mannequin.stream().map(MannequinDTO::getId).collect(Collectors.toList());
            // 既有id又有collectionElementId的，为保持原状的模特（都没有的且又存在于数据库的，即为被删除的模特）
            List<Long> inputCollectionElementIds = mannequin.stream().map(MannequinDTO::getCollectionElementId).collect(Collectors.toList());

            // 创建relationId到Model的映射
            Map<Long, CollectionElementRelModel> relationIdToModelMap = collectionElementRelModels.stream()
                    .collect(Collectors.toMap(
                            CollectionElementRelModel::getRelationId,
                            java.util.function.Function.identity(),
                            (existing, replacement) -> existing
                    ));
            // 创建collectionElementId到Model的映射
            Map<Long, CollectionElementRelModel> collectionElementToModelMap = collectionElementRelModels.stream()
                    .collect(Collectors.toMap(
                            CollectionElementRelModel::getCollectionElementId,
                            java.util.function.Function.identity(),
                            (existing, replacement) -> existing
                    ));
            List<Long> newReletionIds = new ArrayList<>();
            List<Long> toBeDeletedCollectionElementIds = new ArrayList<>();

            if (collectionElementRelModels.isEmpty()) {
                // 如果原本没有记录，所有输入的Mannequin都是新的
                newReletionIds = inputMannequinIds;
            } else {
                // 获取db中所有的relationId集合
                Set<Long> relationIds = relationIdToModelMap.keySet();
                // 获取db中所有的collectionElementId集合
                Set<Long> collectionElementIds = collectionElementToModelMap.keySet();

                // 1. 找出需要删除的：collectionElementIds中有但inputCollectionElementIds中没有的
                toBeDeletedCollectionElementIds = collectionElementIds.stream()
                        .filter(id -> !inputCollectionElementIds.contains(id))
                        .collect(Collectors.toList());

                // 2. 找出新增的：inputMannequinId中有但relationIds中没有的（一定程度避免重复）
                newReletionIds = inputMannequinIds.stream()
                        .filter(id -> !relationIds.contains(id))
                        .collect(Collectors.toList());
            }

            if (!toBeDeletedCollectionElementIds.isEmpty()) {
                /*Set<Long> toBeDeletedElementIdList = toBeDeletedCollectionElementIds.stream()
                        .map(relationIdToModelMap::get) // 获取对应的Model
                        .filter(Objects::nonNull) // 过滤掉可能为null的情况
                        .map(CollectionElementRelModel::getCollectionElementId) // 提取collectionElementId
                        .collect(Collectors.toSet());*/
                collectionElementMapper.deleteBatchIds(toBeDeletedCollectionElementIds);
                // 删除关联关系
                deleteByCollectionElementIdList(toBeDeletedCollectionElementIds);
            }

            for (MannequinDTO dto : mannequin) {
                if (newReletionIds.isEmpty()) {
                    break;
                } else if (!newReletionIds.contains(dto.getId())) {
                    continue;
                }
                if (dto.getType().equals("System")) {
                    SysFile sysFile = sysFileMapper.selectById(dto.getId());

                    CollectionElement collectionElement = new CollectionElement();
                    collectionElement.setAccountId(accountId);
                    collectionElement.setProjectId(projectId);
                    collectionElement.setLevel1Type(CollectionLevel1TypeEnum.MODEL.getRealName());
                    collectionElement.setLevel3Type(workspaceService.getProjectSexById(project.getId()));
//                    collectionElement.setLevel2Type(board.getLevel2Type());
                    collectionElement.setName(sysFile.getName());
                    collectionElement.setUrl(sysFile.getUrl());
//                    collectionElement.setHasPin(board.getIsPin());
                    collectionElement.setMd5(sysFile.getMd5());
                    collectionElement.setCreateDate(new Date());
                    collectionElement.setHasPin((byte) 0);
                    collectionElementMapper.insert(collectionElement);
                    CollectionElementRelModel collectionElementRelModel = new CollectionElementRelModel();
                    collectionElementRelModel.setCollectionElementId(collectionElement.getId());
                    collectionElementRelModel.setRelationId(dto.getId());
                    collectionElementRelModel.setRelationType("System");
                    collectionElementRelModelMapper.insert(collectionElementRelModel);
                } else if (dto.getType().equals("Library")) {
                    Library library = libraryMapper.selectById(dto.getId());

                    CollectionElement collectionElement = new CollectionElement();
                    collectionElement.setAccountId(accountId);
                    collectionElement.setProjectId(projectId);
                    collectionElement.setLevel1Type(CollectionLevel1TypeEnum.MODEL.getRealName());
                    collectionElement.setLevel3Type(workspaceService.getProjectSexById(project.getId()));
//                    collectionElement.setLevel2Type(board.getLevel2Type());
                    collectionElement.setName(library.getName());
                    collectionElement.setUrl(library.getUrl());
//                    collectionElement.setHasPin(board.getIsPin());
                    collectionElement.setMd5(library.getMd5());
                    collectionElement.setCreateDate(new Date());
                    collectionElement.setHasPin((byte) 0);
                    collectionElementMapper.insert(collectionElement);
                    CollectionElementRelModel collectionElementRelModel = new CollectionElementRelModel();
                    collectionElementRelModel.setCollectionElementId(collectionElement.getId());
                    collectionElementRelModel.setRelationId(dto.getId());
                    collectionElementRelModel.setRelationType("Library");
                    collectionElementRelModelMapper.insert(collectionElementRelModel);

                }
            }
        }
        if (boundingBox) {
            QueryWrapper<CollectionElement> qw = new QueryWrapper<>();
            qw.lambda().eq(CollectionElement::getLevel1Type, CollectionLevel1TypeEnum.SKETCH_BOARD.getRealName());
            qw.lambda().eq(CollectionElement::getProjectId, projectId);
            List<CollectionElement> collectionElements = collectionElementMapper.selectList(qw);

            List<CollectionSketchVO> voList = new ArrayList<>();
            for (CollectionElement collectionElement : collectionElements) {
                CollectionSketchVO vo = CopyUtil.copyObject(collectionElement, CollectionSketchVO.class);
                String url = collectionElement.getUrl();
                libraryService.processSketchBoards(url, collectionElement.getLevel2Type());
                if (url.contains(".")) {
                    String[] split = url.split("\\.");
                    vo.setUrlWithWhiteSide(minioUtil.getPreSignedUrl(split[0] + "-show." + split[1], 24 * 60, true));
                } else {
                    vo.setUrlWithWhiteSide(minioUtil.getPreSignedUrl(url + "-show", 24 * 60, true));
                }
                vo.setIsPin(collectionElement.getHasPin());
                vo.setLevel2Type(collectionElement.getLevel2Type());
                vo.setDesignType("Collection");
                vo.setSketchBoardId(collectionElement.getId());
                voList.add(vo);
            }
            voList.sort(Comparator.comparing(CollectionSketchVO::getSketchBoardId));
            result.setBoundingBox(voList);
        }
        project.setUpdateTime(LocalDateTime.now());
        projectService.updateById(project);
        return result;
    }

    private void deleteByCollectionElementIdList(java.util.Collection<Long> old) {
        QueryWrapper<CollectionElementRelModel> qw = new QueryWrapper<>();
        qw.lambda().in(CollectionElementRelModel::getCollectionElementId, old);
        collectionElementRelModelMapper.delete(qw);
    }

    @Override
    public QueryLibraryPageVO getMannequinDetail(MannequinDTO mannequinDTO) {
        QueryLibraryPageVO vo = new QueryLibraryPageVO();
        if (mannequinDTO.getType().equals("System")) {
            SysFile sysFile = sysFileMapper.selectById(mannequinDTO.getId());
            vo.setDesignType("System");
            vo.setLevel1Type(sysFile.getLevel1Type());
            vo.setLevel2Type(sysFile.getLevel2Type());
            vo.setName(sysFile.getName());
            vo.setMinIOPath(minioUtil.getPreSignedUrl(sysFile.getUrl(), 24 * 60));
        } else {
            Library library = libraryMapper.selectById(mannequinDTO.getId());
            vo.setDesignType("Library");
            vo.setLevel1Type(library.getLevel1Type());
            vo.setLevel2Type(library.getLevel2Type());
            vo.setName(library.getName());
            vo.setMinIOPath(minioUtil.getPreSignedUrl(library.getUrl(), 24 * 60));
        }
        QueryWrapper<LibraryModelPoint> qw = new QueryWrapper<>();
        qw.lambda().eq(LibraryModelPoint::getRelationId, mannequinDTO.getId());
        qw.lambda().eq(LibraryModelPoint::getModelType, mannequinDTO.getType());
        List<LibraryModelPoint> libraryModelPoints = libraryModelPointMapper.selectList(qw);
        if (CollectionUtil.isEmpty(libraryModelPoints)) {
            throw new BusinessException("No model doting information available.");
        }
        LibraryModelPoint libraryModelPoint = libraryModelPoints.get(0);
        LibraryModelPointVO libraryModelPointVO = CopyUtil.copyObject(libraryModelPoint, LibraryModelPointVO.class);
        libraryModelPointVO.setTemplateId(libraryModelPoint.getId());
        libraryModelPointVO.setHandLeft(JSON.parseObject(libraryModelPoint.getHandLeft(), List.class));
        libraryModelPointVO.setHandRight(JSON.parseObject(libraryModelPoint.getHandRight(), List.class));
        libraryModelPointVO.setShoulderRight(JSON.parseObject(libraryModelPoint.getShoulderRight(), List.class));
        libraryModelPointVO.setShoulderLeft(JSON.parseObject(libraryModelPoint.getShoulderLeft(), List.class));
        libraryModelPointVO.setWaistbandRight(JSON.parseObject(libraryModelPoint.getWaistbandRight(), List.class));
        libraryModelPointVO.setWaistbandLeft(JSON.parseObject(libraryModelPoint.getWaistbandLeft(), List.class));

        vo.setLibraryModelPoint(libraryModelPointVO);
        return vo;
    }

    @Override
    public BrandLogoUploadVO brandLogoUpload(MultipartFile file) {
        BrandLogoUploadVO vo = new BrandLogoUploadVO();
        AuthPrincipalVo userHolder = UserContext.getUserHolder();
        String path = userHolder.getId().toString() + "/brandLogo";
        vo.setBrandLogo(minioUtil.upload("aida-users", path, file));
        vo.setMinioUrl(minioUtil.getPreSignedUrl(vo.getBrandLogo(), 24 * 60));
        return vo;
//        return null;
    }

    @Override
    public Boolean brandDNASaveOrUpdate(BrandDNADTO brandDNADTO) {
        if (brandDNADTO.getId() != null) {
            BrandDNA brandDNA = CopyUtil.copyObject(brandDNADTO, BrandDNA.class);
            brandDNA.setUpdateTime(LocalDateTime.now());
            brandDNAMapper.updateById(brandDNA);
        } else {
            BrandDNA brandDNA = CopyUtil.copyObject(brandDNADTO, BrandDNA.class);
            AuthPrincipalVo userHolder = UserContext.getUserHolder();
            brandDNA.setAccountId(userHolder.getId());
            brandDNA.setCreateTime(LocalDateTime.now());
            brandDNAMapper.insert(brandDNA);
        }
        return Boolean.TRUE;
    }

    @Override
    public LibraryUpdateVo brandDNAUpload(MultipartFile file, Long brandId) throws IOException {
        AuthPrincipalVo userHolder = UserContext.getUserHolder();
        String path = userHolder.getId().toString() + "/brandLogo";
        String upload = minioUtil.upload("aida-users", path, file);
        Library library = new Library();
        library.setAccountId(userHolder.getId());
        library.setLevel1Type(LibraryLevel1TypeEnum.BRAND_DNA.getRealName());
        library.setName(file.getOriginalFilename());
        library.setUrl(upload);
        library.setMd5(MD5Utils.encryptFile(file.getInputStream()));
        library.setCreateDate(new Date());
        libraryMapper.insert(library);

        BrandRelLibrary brandRelLibrary = new BrandRelLibrary();
        brandRelLibrary.setLibraryId(library.getId());
        brandRelLibrary.setBrandId(brandId);
        brandRelLibraryMapper.insert(brandRelLibrary);

        LibraryUpdateVo vo = CopyUtil.copyObject(library, LibraryUpdateVo.class);
        vo.setMinIOPath(minioUtil.getPreSignedUrl(vo.getUrl(), 24 * 60));

        return vo;
    }

    @Override
    public PageBaseResponse<BrandDNAVO> brandDNAPage(BrandDNAQueryDTO brandDNAQueryDTO) {
        AuthPrincipalVo userHolder = UserContext.getUserHolder();
        QueryWrapper<BrandDNA> qw = new QueryWrapper<>();
        qw.lambda().eq(BrandDNA::getAccountId, userHolder.getId());
        IPage<BrandDNA> page = brandDNAMapper.selectPage(new Page<>(brandDNAQueryDTO.getPage(), brandDNAQueryDTO.getSize()), qw);
        IPage<BrandDNAVO> convert = page.convert((Function<BrandDNA, BrandDNAVO>) brand -> {
            if (Objects.nonNull(brand)) {
                BrandDNAVO brandDNAVO = CopyUtil.copyObject(brand, BrandDNAVO.class);
                brandDNAVO.setMinioUrl(minioUtil.getPreSignedUrl(brandDNAVO.getBrandLogo(), 24 * 60));
                return brandDNAVO;
            }
            return null;
        });
        return PageBaseResponse.success(convert);
    }

    @Override
    public BrandDNAGenerateVO brandDNAGenerate(String prompt) {
        BrandDNAGenerateVO vo = new BrandDNAGenerateVO();
        JSONObject jsonObject = pythonService.brandDNAGenerate(prompt);
        JSONObject data = jsonObject.getJSONObject("data");
        vo.setBrandSlogan(data.getString("brand_slogan"));
        vo.setBrandName(data.getString("brand_name"));
        vo.setBrandLogo(data.getString("brand_logo"));
        vo.setMinioUrl(minioUtil.getPreSignedUrl(vo.getBrandLogo(), 24 * 60));
        return vo;
    }

    @Override
    public IPage<ThreeDLayoutVO> getThreeDLayoutPage(ThreeDLayoutQueryDTO query) {
//        AuthPrincipalVo authPrincipalVo = UserContext.getUserHolder();
//        Long workspaceServiceByProjectId = workspaceService.getByProjectId(query.getProjectId());
//        Workspace byId = workspaceService.getById(workspaceServiceByProjectId);
        // 分页数据
        QueryWrapper<ThreeDLayout> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(ThreeDLayout::getType, "front");
        queryWrapper.lambda().eq(ThreeDLayout::getGender, query.getSex().toLowerCase());
        IPage<ThreeDLayout> page = threeDLayoutMapper.selectPage(
                new Page<>(query.getPage(), query.getSize()), queryWrapper);
        if (CollectionUtils.isEmpty(page.getRecords())) {
            return new Page<>();
        }

        IPage<ThreeDLayoutVO> convert = page.convert((Function<ThreeDLayout, ThreeDLayoutVO>) threeDLayout -> {
            if (threeDLayout != null) {
                ThreeDLayoutVO threeDLayoutVO = CopyUtil.copyObject(threeDLayout, ThreeDLayoutVO.class);
                threeDLayoutVO.setUrl(minioUtil.getPreSignedUrl(threeDLayoutVO.getUrl(), 24 * 60));
                return threeDLayoutVO;
            }
            return null;
        });
        return convert;
    }

    @Override
    public ThreeDVO getLayoutDetail(Long threeDSimpleId) {
        ThreeDVO result = new ThreeDVO();

        QueryWrapper<ThreeDLayout> qw = new QueryWrapper<>();
        qw.lambda().eq(ThreeDLayout::getThreeDSimpleId, threeDSimpleId);
        List<ThreeDLayout> threeDLayoutList = threeDLayoutMapper.selectList(qw);
        for (ThreeDLayout threeDLayout : threeDLayoutList) {
            threeDLayout.setUrl(minioUtil.getPreSignedUrl(threeDLayout.getUrl(), 24 * 60));
        }
        result.setThreeDLayoutList(threeDLayoutList);

        QueryWrapper<ThreeDPatternLayout> threeDPatternLayoutQueryWrapper = new QueryWrapper<>();
        threeDPatternLayoutQueryWrapper.lambda().eq(ThreeDPatternLayout::getThreeDSimpleId, threeDSimpleId);
        List<ThreeDPatternLayout> threeDPatternLayoutList = threeDPatternLayoutMapper.selectList(threeDPatternLayoutQueryWrapper);
        if (CollectionUtil.isNotEmpty(threeDPatternLayoutList)) {
            ThreeDPatternLayout threeDPatternLayout = threeDPatternLayoutList.get(0);
//            threeDPatternLayout.setUrl(minioUtil.getPreSignedUrl(threeDPatternLayout.getUrl(), 24 * 60));
            result.setThreeDPatternLayoutUrl(minioUtil.getPreSignedUrl(threeDPatternLayout.getUrl(), 24 * 60));
        }
        ThreeDSimple threeDSimple = threeDSimpleMapper.selectById(threeDSimpleId);
        result.setThreeDSimpleUrl(minioUtil.getPreSignedUrl(threeDSimple.getUrl(), 24 * 60));
        return result;
    }

    @Override
    public ThreeDSizeVO getThreeDSize(Long threeDSimpleId) {
        ThreeDSizeVO result = new ThreeDSizeVO();
        QueryWrapper<ThreeDDetail> threeDDetailQueryWrapper = new QueryWrapper<>();
        threeDDetailQueryWrapper.lambda().eq(ThreeDDetail::getThreeDSimpleId, threeDSimpleId);
        List<ThreeDDetail> threeDDetailList = threeDDetailMapper.selectList(threeDDetailQueryWrapper);
        if (CollectionUtil.isNotEmpty(threeDDetailList)) {
            // 以 sizeType 分组
            Map<String, List<String>> sizeTypeMap = new HashMap<>();
            for (ThreeDDetail detail : threeDDetailList) {
                sizeTypeMap
                        .computeIfAbsent(detail.getSizeType(), k -> new ArrayList<>())
                        .add(detail.getSize());
            }
            result.setSizeTypeMap(sizeTypeMap);
        }
        return result;
    }

    @Override
    public void getThreeDGlb(Long threeDSimpleId, HttpServletResponse response) throws MinioException, IOException {
        ThreeDSimple threeDSimple = threeDSimpleMapper.selectById(threeDSimpleId);
        if (ObjectUtils.isAllFieldNull(threeDSimple)) {
            throw new BusinessException("3D file is not exist");
        }
        InputStream inputStream = minioUtil.download(threeDSimple.getUrl());

        // 设置响应头
        response.setContentType("model/gltf-binary"); // 确保 MIME 类型正确
        response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
        String fileName = threeDSimple.getName();
        if (!fileName.toLowerCase().endsWith(".glb")) {
            fileName += ".glb";
        }
        response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + URLEncoder.encode(fileName, StandardCharsets.UTF_8.toString()));
        // 将文件内容写入响应输出流
        try {
            byte[] buffer = new byte[8192];
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                response.getOutputStream().write(buffer, 0, bytesRead);
            }
            inputStream.close();
            response.getOutputStream().flush();
        } catch (Exception e) {
            throw new RuntimeException("Failed to get 3D .glb file", e);
        }
    }

    @Override
    public String downloadZip(Long threeDSimpleId, String sizeType, String size, HttpServletResponse response) throws MinioException, IOException {
        QueryWrapper<ThreeDDetail> qw = new QueryWrapper<>();
        qw.lambda().eq(ThreeDDetail::getThreeDSimpleId, threeDSimpleId);
        qw.lambda().eq(ThreeDDetail::getSizeType, sizeType);
        qw.lambda().eq(ThreeDDetail::getSize, size);
        ThreeDDetail threeDDetail = threeDDetailMapper.selectOne(qw);
        if (ObjectUtils.isAllFieldNull(threeDDetail)) {
            throw new BusinessException("3D file is not exist");
        }
        return minioUtil.getPreSignedUrl(threeDDetail.getUrl(), 24 * 60);

//        // 设置响应头
//        response.setContentType("application/zip"); // 确保 ZIP 格式
//        response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
//        String fileName = threeDDetail.getName();
//        if (!fileName.toLowerCase().endsWith(".zip")) {
//            fileName += ".zip";
//        }
//        response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + URLEncoder.encode(fileName, StandardCharsets.UTF_8.toString()));
//
//        // 将文件内容写入响应输出流
//        try {
//            byte[] buffer = new byte[8192];
//            int bytesRead;
//            while ((bytesRead = inputStream.read(buffer)) != -1) {
//                response.getOutputStream().write(buffer, 0, bytesRead);
//            }
//            inputStream.close();
//            response.getOutputStream().flush();
//        } catch (Exception e) {
//            throw new RuntimeException("Failed to download ZIP file", e);
//        }
    }

    @Override
    public Boolean delete(Long projectId) {
        projectService.removeById(projectId);
        return Boolean.TRUE;
    }

    @Override
    public Boolean brandDNADelete(BrandDNADTO brandDNADTO) {
        brandDNAMapper.deleteById(brandDNADTO.getId());
        return Boolean.TRUE;
    }

    @Override
    @Transactional(isolation = Isolation.SERIALIZABLE)
    public void toProductBatch(String taskId, String url, String progress) throws InterruptedException {
        QueryWrapper<ToProductImageResult> qw = new QueryWrapper<>();
        qw.lambda().eq(ToProductImageResult::getTaskId, taskId);
        ToProductImageResult toProductImageResult = toProductImageResultMapper.selectOne(qw);
        if (Objects.nonNull(toProductImageResult)) {
            toProductImageResult.setUrl(url);
            toProductImageResult.setStatus("Success");
            toProductImageResultMapper.updateById(toProductImageResult);
            String taskIdBatch = toProductImageResult.getTaskIdBatch();
            log.info("toProductImage云生成 batchTaskId:" + taskIdBatch + " 完成数+1");

            CloudTask task = cloudTaskMapper.selectForUpdate(taskIdBatch);
            log.info("排查完成数量" + task.getCompletedNum());
            task.setCompletedNum(task.getCompletedNum() + 1);
            cloudTaskMapper.updateById(task);

            String key = toProductImageResultKey + ":" + taskId;
            String imageName = url.substring(url.lastIndexOf("/") + 1);
            String status = imageName.equals("white_image.jpg") ? "Invalid" : "Success";
            GenerateResultVO generateResultVO = new GenerateResultVO(taskId, toProductImageResult.getId(), url, status, null);
            redisUtil.addToString(key, new Gson().toJson(generateResultVO), CommonConstant.GENERATE_RESULT_EXPIRE_TIME);

            /*Long accountId = Long.parseLong(taskId.substring(taskId.lastIndexOf("-") + 1));
            if (!status.equals("Invalid")) {
                // 4、扣除积分
                Boolean b = creditsService.taskCreditsDeduction(accountId, taskId);
                // 3、记录积分变更
                if (b) creditsService.updateChangedCredits(String.valueOf(accountId), taskId);
            }*/
        }

    }

    @Override
    @Transactional
    public void relightBatch(String taskId, String url, String progress) {
        QueryWrapper<ToProductImageResult> qw = new QueryWrapper<>();
        qw.lambda().eq(ToProductImageResult::getTaskId, taskId);
        ToProductImageResult toProductImageResult = toProductImageResultMapper.selectOne(qw);
        if (Objects.nonNull(toProductImageResult)) {
            if (toProductImageResult.getBrightenValue() != null && toProductImageResult.getBrightenValue() != 1.0) {
                pythonService.bright(url, toProductImageResult.getBrightenValue());
            }
            toProductImageResult.setUrl(url);
//            toProductImageResult.setResultType("Relight");
            toProductImageResult.setStatus("Success");
            toProductImageResultMapper.updateById(toProductImageResult);

            String taskIdBatch = toProductImageResult.getTaskIdBatch();
//            QueryWrapper<CloudTask> cloudTaskQueryWrapper = new QueryWrapper<>();
//            cloudTaskQueryWrapper.lambda().eq(CloudTask::getTaskId, taskIdBatch);
//            CloudTask cloudTask = cloudTaskMapper.selectOne(cloudTaskQueryWrapper);
//            if (Objects.nonNull(cloudTask)) {
//                if (cloudTask.getCompletedNum() == null) {
//                    cloudTask.setCompletedNum(1);
//                }else {
//                    cloudTask.setCompletedNum(cloudTask.getCompletedNum() + 1);
//                }
//                if (progress.equals("OK")) {
//                    cloudTask.setStatus(1);
//                    cloudTask.setCompletedNum(cloudTask.getNums());
//                }
//                cloudTaskMapper.updateById(cloudTask);
//            }
            cloudTaskMapper.increaseCompletedNum(taskIdBatch);

            String key = relightResultKey + ":" + taskId;
            String imageName = url.substring(url.lastIndexOf("/") + 1);
            String status = imageName.equals("white_image.jpg") ? "Invalid" : "Success";
            GenerateResultVO generateResultVO = new GenerateResultVO(taskId, toProductImageResult.getId(), url, status, null);
            redisUtil.addToString(key, new Gson().toJson(generateResultVO), CommonConstant.GENERATE_RESULT_EXPIRE_TIME);

            /*Long accountId = Long.parseLong(taskId.substring(taskId.lastIndexOf("-") + 1));
            if (!status.equals("Invalid")) {
                // 4、扣除积分
                Boolean b = creditsService.taskCreditsDeduction(accountId, taskId);
                // 3、记录积分变更
                if (b) creditsService.updateChangedCredits(String.valueOf(accountId), taskId);
            }*/
        }
    }

    @Override
    @Transactional
    public Boolean collectionLikeUpdate(CollectionLikeUpdateDTO collectionLikeUpdateDTO) {
        QueryWrapper<CollectionSort> qw = new QueryWrapper<>();
        qw.lambda().eq(CollectionSort::getRelationId, collectionLikeUpdateDTO.getOldRelationId());
        qw.lambda().eq(CollectionSort::getRelationType, collectionLikeUpdateDTO.getRelationType());
        CollectionSort collectionSort = collectionSortMapper.selectOne(qw);
//        Long relationIdOld = collectionSort.getRelationId();
        collectionSort.setRelationId(collectionLikeUpdateDTO.getRelationId());
        collectionSortMapper.updateById(collectionSort);
        if (collectionLikeUpdateDTO.getRelationType().equals(CollectionType.TO_PRODUCT_IMAGE.getValue()) || collectionLikeUpdateDTO.getRelationType().equals(CollectionType.RELIGHT.getValue())) {
            ToProductImageResult toProductImageResult = toProductImageResultMapper.selectById(collectionLikeUpdateDTO.getRelationId());
            toProductImageResult.setIsLike(1);
            toProductImageResultMapper.updateById(toProductImageResult);
            ToProductImageResult toProductImageResultOld = toProductImageResultMapper.selectById(collectionLikeUpdateDTO.getOldRelationId());
            toProductImageResultOld.setIsLike(0);
            toProductImageResultMapper.updateById(toProductImageResultOld);
        } else if (collectionLikeUpdateDTO.getRelationType().equals(CollectionType.POSE_TRANSFORM.getValue())) {
            PoseTransformation poseTransformation = poseTransformationMapper.selectById(collectionLikeUpdateDTO.getRelationId());
            poseTransformation.setIsLiked((byte) 1);
            poseTransformationMapper.updateById(poseTransformation);
            PoseTransformation poseTransformationOld = poseTransformationMapper.selectById(collectionLikeUpdateDTO.getOldRelationId());
            poseTransformationOld.setIsLiked((byte) 0);
            poseTransformationMapper.updateById(poseTransformationOld);
        }
        return Boolean.TRUE;
    }

    @Override
    public Boolean toProductImageElementDelete(Long id) {
        UpdateWrapper<ToProductElement> updateWrapper = new UpdateWrapper<>();
        updateWrapper
                .set("project_id", null) // 显式设置 NULL
                .eq("id", id);            // 指定条件
        toProductElementMapper.update(null, updateWrapper);
        return Boolean.TRUE;
    }

    @Override
    public ToProductElementVO convertRelightElement(Long id) {
        ToProductImageResult toProductImageResult = toProductImageResultMapper.selectById(id);

        ToProductElement toProductElement = new ToProductElement();
        toProductElement.setUrl(toProductImageResult.getUrl());
//        toProductElement.setUserLikeGroupId(userLikeGroupId);
        toProductElement.setProjectId(toProductImageResult.getProjectId());
        toProductElement.setCreateTime(LocalDateTime.now());
        toProductElementMapper.insert(toProductElement);
        ToProductElementVO toProductElementVO = CopyUtil.copyObject(toProductElement, ToProductElementVO.class);
        toProductElementVO.setMinioUrl(toProductElementVO.getUrl());
        toProductElementVO.setUrl(minioUtil.getPreSignedUrl(toProductElementVO.getUrl(), 24 * 60));
        return toProductElementVO;
    }

    private String buildAdvancedPrompt(Long projectId, String prompt) {
        String process = projectService.getById(projectId).getProcess();
        String ageGroup = null;
        if (!"TO_PRODUCT_IMAGE".equals(process)) {
            //高级工具转产品图不需要这个字段
            ageGroup = workspaceService.getWSByProjectId(projectId).getAgeGroup();
        }
        String suffixCommon = "Pay attention to the size of the garment, the print, and the fabric texture, real photo, 8K, HDR, DOF, soft lighting, high detail, high quality, Do not return the original image.";
        String suffixModelAdult = "Transform this image into a real model standing," + suffixCommon;
        String suffixModelChild = "Transform this image into a real child model standing," + suffixCommon;
        if ("SINGLE_DESIGN".equals(process) && "Adult".equals(ageGroup)) {
            if (StringUtil.isNullOrEmpty(prompt)) {
                return "Transform this image into a real garment showing in the white studio: garment on invisible mannequin" + suffixCommon;
            } else {
                return prompt + suffixCommon;
            }
        } else if ("SINGLE_DESIGN".equals(process) && "Child".equals(ageGroup)) {
            if (StringUtil.isNullOrEmpty(prompt)) {
                return "Transform this image into a real child model stand and wear this garment, in the white studio, facing camera, standing posture." + suffixCommon;
            } else {
                return prompt + suffixCommon;
            }
        } else if ("SERIES_DESIGN".equals(process) && "Adult".equals(ageGroup)) {
            if (StringUtil.isNullOrEmpty(prompt)) {
                return "in the white studio, facing camera, standing posture." + suffixModelAdult;
            } else {
                return prompt + suffixModelAdult;
            }
        } else if ("SERIES_DESIGN".equals(process) && "Child".equals(ageGroup)) {
            if (StringUtil.isNullOrEmpty(prompt)) {
                return "in the white studio, facing camera, standing posture." + suffixModelChild + "\n";
            } else {
                return prompt + suffixModelChild;
            }
        } else if ("TO_PRODUCT_IMAGE".equals(process)) {
            if (StringUtil.isNullOrEmpty(prompt)) {
                throw new BusinessException("Please enter the prompt.");
            } else {
                return prompt + suffixCommon;
            }
        } else {
            return "Transform this image into a realistic, studio-quality photograph." + "Pay attention to the size of the garment, the print, and the fabric texture. the white background. 8K, HDR, DOF, soft lighting" + ", high detail, high quality,Do not return the original image";
        }
    }
}
