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.context.UserContext;
import com.ai.da.common.enums.CollectionLevel1TypeEnum;
import com.ai.da.common.response.PageBaseResponse;
import com.ai.da.common.response.ResultEnum;
import com.ai.da.common.utils.CopyUtil;
import com.ai.da.common.utils.MinioUtil;
import com.ai.da.common.utils.RedisUtil;
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.model.dto.*;
import com.ai.da.model.enums.CollectionType;
import com.ai.da.model.enums.DesignProcess;
import com.ai.da.model.enums.Position;
import com.ai.da.model.enums.Sex;
import com.ai.da.model.vo.*;
import com.ai.da.service.*;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
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 io.netty.util.internal.StringUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
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 java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
public class PortfolioServiceImpl extends ServiceImpl<PortfolioMapper, Portfolio> implements PortfolioService {

    private final AccountMapper accountMapper;
    private final CanvasMapper canvasMapper;
    private final CollectionMapper collectionMapper;
    private final CollectionElementMapper collectionElementMapper;
    private final CollectionElementService collectionElementService;
    private final CollectionSortMapper collectionSortMapper;
    private final CollectionSortService collectionSortService;
    private final CollectionElementRelModelMapper collectionElementRelModelMapper;
    private final TCollectionElementRelationMapper collectionElementRelationMapper;
    private final DesignMapper designMapper;
    private final DesignItemMapper designItemMapper;
    private final DesignItemDetailMapper designItemDetailMapper;
    private final DesignItemDetailPrintMapper designItemDetailPrintMapper;
    private final TDesignPythonOutfitMapper designPythonOutfitMapper;
    private final TDesignPythonOutfitDetailMapper designPythonOutfitDetailMapper;
    private final MinioUtil minioUtil;
    private final ProjectMapper projectMapper;
    private final PortfolioMapper portfolioMapper;
    private final PortfolioTagsMapper portfolioTagsMapper;
    private final PoseTransformationMapper poseTransformationMapper;
    private final TagsMapper tagsMapper;
    private final TagsService tagsService;
    private final ToProductImageResultMapper toProductImageResultMapper;
    private final ToProductImageRecordMapper toProductImageRecordMapper;
    private final UserFollowMapper userFollowMapper;
    private final UserFollowService userFollowService;
    private final UserLikeService userLikeService;
    private final UserLikeMapper userLikeMapper;
    private final UserLikeGroupMapper userLikeGroupMapper;
    private final UserLikeGroupService userLikeGroupService;
    private final WorkspaceMapper workspaceMapper;
    private final WorkspaceService workspaceService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long publish(MultipartFile file, String data) {
        Long resultPortfolioId = null;
        AuthPrincipalVo authPrincipalVo = UserContext.getUserHolder();
        PortfolioDTO portfolioDTO = JSONObject.parseObject(data, PortfolioDTO.class);
        QueryWrapper<Portfolio> existSameNameQw = new QueryWrapper<>();
        if (null != portfolioDTO.getId()) {
            existSameNameQw.lambda().ne(Portfolio::getId, portfolioDTO.getId());
        }
        existSameNameQw.lambda().eq(Portfolio::getPortfolioName, portfolioDTO.getPortfolioName());
        existSameNameQw.lambda().eq(Portfolio::getAccountId, authPrincipalVo.getId());
        List<Portfolio> portfoliosSameName = portfolioMapper.selectList(existSameNameQw);
        if (!CollectionUtils.isEmpty(portfoliosSameName)) {
            throw new BusinessException("title.has.been.used");
        }
        // 判断用户是否参与#RCAworkshop_2024的活动
//        if (hasParticipatedRCAWorkshop(authPrincipalVo.getId(), portfolioDTO.getTagsDTO(), portfolioDTO.getId(), portfolioDTO.getUserLikeGroupId())){
//            throw new BusinessException("you.have.participated.in.the.event", ResultEnum.PROMPT.getCode());
//        }
        if (file != null && file.getOriginalFilename() != null) {
            Long portfolioId;
            // 上传画布到minio
            String upload = minioUtil.upload("aida-canvas", String.valueOf(authPrincipalVo.getId()), file);
            Canvas canvas = new Canvas();
            canvas.setUrl(upload);
            canvas.setCreateTime(LocalDateTime.now());
            canvas.setAccountId(authPrincipalVo.getId());
            canvasMapper.insert(canvas);

            // 创建portfolio
            Portfolio portfolio = new Portfolio();
            if (null != portfolioDTO.getId()) {
                portfolio = portfolioMapper.selectById(portfolioDTO.getId());
            }
            // 关联的项目ID
            Long projectId = portfolioDTO.getProjectId();
            // 复制project表
            Project project = projectMapper.selectById(projectId);
            if (project.getOriginal() != null && project.getOriginal() == 0) {
                portfolio.setOriginal(0);
                portfolio.setOriginalAccountId(project.getOriginalAccountId());
                portfolio.setOriginalPortfolioId(project.getOriginalPortfolioId());
            } else {
                portfolio.setOriginal(1);
            }
            portfolio.setPortfolioName(portfolioDTO.getPortfolioName());
            portfolio.setAccountId(authPrincipalVo.getId());
            portfolio.setCreateDate(LocalDateTime.now());
            portfolio.setUpdateDate(LocalDateTime.now());
            portfolio.setStatus(1);
            portfolio.setIsDeleted(0);
            portfolio.setCanvasId(canvas.getId());
            portfolio.setPortfolioDes(portfolioDTO.getPortfolioDes());
            if (Objects.isNull(portfolioDTO.getIsPublic())) {
                portfolio.setIsPublic(1);
            } else {
                portfolio.setIsPublic(portfolioDTO.getIsPublic());
            }
            portfolio.setOrganizationId(accountMapper.selectById(authPrincipalVo.getId()).getOrganizationId());

            if (portfolioDTO.getOpenSource() == 1) {
                // 副本存储对象
                ProjectSnapshot projectSnapshot = new ProjectSnapshot();
                // 根据项目ID获取项目设置
                Long workspaceId = workspaceService.getByProjectId(projectId);
                Workspace workspace = workspaceMapper.selectById(workspaceId);

                project.setId(projectId);
                projectSnapshot.setProject(project);
                workspace.setId(null);
                projectSnapshot.setWorkspace(workspace);

                portfolio.setPortfolioType("History");
                portfolio.setOpenSource(1);

                List<CollectionElement> collectionElementListOld = collectionElementService.getByProjectId(projectId);
                projectSnapshot.setCollectionElementList(collectionElementListOld);

                UserLikeGroup userLikeGroup = userLikeService.getUserLikeGroupByProjectId(projectId);
                if (Objects.nonNull(userLikeGroup)) {
                    projectSnapshot.setUserLikeGroup(userLikeGroup);

                    List<UserLike> userLikeList = userLikeService.getByUserLikeGroupId(userLikeGroup.getId());
                    List<UserLikeSnapshot> list = new ArrayList<>();
                    for (UserLike userLike : userLikeList) {
                        UserLikeSnapshot userLikeSnapshot = CopyUtil.copyObject(userLike, UserLikeSnapshot.class);

                        Long designOutfitIdOld = userLike.getDesignOutfitId();
                        TDesignPythonOutfit designPythonOutfit = designPythonOutfitMapper.selectById(designOutfitIdOld);

                        Long designItemIdOld = userLike.getDesignItemId();
                        DesignItem designItemOld = designItemMapper.selectById(designItemIdOld);

                        userLikeSnapshot.setDesignItem(designItemOld);
                        userLikeSnapshot.setDesignPythonOutfit(designPythonOutfit);

                        QueryWrapper<TDesignPythonOutfitDetail> qw = new QueryWrapper<>();
                        qw.lambda().eq(TDesignPythonOutfitDetail::getDesignPythonOutfitId, designOutfitIdOld);
                        List<TDesignPythonOutfitDetail> tDesignPythonOutfitDetailList = designPythonOutfitDetailMapper.selectList(qw);
                        userLikeSnapshot.setTDesignPythonOutfitDetailList(tDesignPythonOutfitDetailList);


                        QueryWrapper<DesignItemDetail> designItemDetailQueryWrapper = new QueryWrapper<>();
                        designItemDetailQueryWrapper.lambda().eq(DesignItemDetail::getDesignItemId, designItemIdOld);
                        List<DesignItemDetail> designItemDetailListOld = designItemDetailMapper.selectList(designItemDetailQueryWrapper);
                        List<DesignItemDetailSnapshot> designItemDetailSnapshotList = new ArrayList<>();
                        for (DesignItemDetail designItemDetailOld : designItemDetailListOld) {
                            DesignItemDetailSnapshot designItemDetailSnapshot = CopyUtil.copyObject(designItemDetailOld, DesignItemDetailSnapshot.class);
                            Long designItemDetailIdOld = designItemDetailOld.getId();

                            QueryWrapper<DesignItemDetailPrint> designItemDetailPrintQueryWrapper = new QueryWrapper<>();
                            designItemDetailPrintQueryWrapper.lambda().eq(DesignItemDetailPrint::getDesignItemDetailId, designItemDetailIdOld);
                            List<DesignItemDetailPrint> designItemDetailPrintList = designItemDetailPrintMapper.selectList(designItemDetailPrintQueryWrapper);
                            designItemDetailSnapshot.setDesignItemDetailPrintList(designItemDetailPrintList);
                            designItemDetailSnapshotList.add(designItemDetailSnapshot);
                        }
                        userLikeSnapshot.setDesignItemDetailList(designItemDetailSnapshotList);
                        list.add(userLikeSnapshot);
                    }
                    projectSnapshot.setUserLikeList(list);
                }
                String snapshotJson = JSONObject.toJSONString(projectSnapshot, SerializerFeature.DisableCircularReferenceDetect);
                portfolio.setSnapshot(snapshotJson);
            } else {

                portfolio.setPortfolioType("Canvas");

                portfolio.setOpenSource(0);
            }
            if (null != portfolioDTO.getId()) {
                portfolioMapper.updateById(portfolio);
            } else {
                portfolioMapper.insert(portfolio);
            }
            resultPortfolioId = portfolio.getId();
            portfolioId = portfolio.getId();
            // id不为空 表示更新发布；为空，表示新发布
            if (!Objects.isNull(portfolioDTO.getId())) {
                portfolioId = portfolioDTO.getId();
                // 删除作品的所有与标签的关联关系
                portfolioTagsMapper.deleteByPortfolioId(portfolioId);
            }
            // 记录作品添加的标签
            if (!portfolioDTO.getTagsDTO().isEmpty()) {
                addTagsForPortfolio(portfolioDTO.getTagsDTO(), portfolioId);
            }
        }

        return resultPortfolioId;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PortfolioVO update(PortfolioDTO portfolioDTO) {
        AuthPrincipalVo authPrincipalVo = UserContext.getUserHolder();
        QueryWrapper<Portfolio> existSameNameQw = new QueryWrapper<>();
        existSameNameQw.lambda().ne(Portfolio::getId, portfolioDTO.getId());
        existSameNameQw.lambda().eq(Portfolio::getPortfolioName, portfolioDTO.getPortfolioName());
        existSameNameQw.lambda().eq(Portfolio::getAccountId, authPrincipalVo.getId());
        List<Portfolio> portfoliosSameName = portfolioMapper.selectList(existSameNameQw);
        if (!CollectionUtils.isEmpty(portfoliosSameName)) {
            throw new BusinessException("title.has.been.used");
        }
        if (portfolioDTO.getPortfolioType().equals("History")) {
            Long userLikeGroupId;
            if (Objects.nonNull(portfolioDTO.getUserLikeGroupId())) {
                userLikeGroupId = portfolioDTO.getUserLikeGroupId();
            } else if (Objects.nonNull(portfolioDTO.getProjectId())) {
                UserLikeGroup likeGroup = userLikeGroupMapper.selectOne(new QueryWrapper<UserLikeGroup>().eq("project_id", portfolioDTO.getProjectId()));
                if (Objects.isNull(likeGroup)) {
                    return null;
                }
                userLikeGroupId = likeGroup.getId();
            } else {
                return null;
            }

            UserLikeGroup userLikeGroup = userLikeGroupMapper.selectById(userLikeGroupId);
            UserLikeGroup userLikeGroupNew = userLikeGroup.setId(null);
            userLikeGroupNew.setAccountId(-1L);
            Long collectionIdOld = userLikeGroup.getCollectionId();
            Collection collectionOld = collectionMapper.selectById(collectionIdOld);
            List<CollectionElement> collectionElementListOld = collectionElementService.getByCollectionId(collectionIdOld);
            collectionOld.setId(null);
            collectionMapper.insert(collectionOld);
            Long collectionIdNew = collectionOld.getId();
            userLikeGroupNew.setCollectionId(collectionIdNew);
            userLikeGroupMapper.insert(userLikeGroupNew);
//        List<TCollectionElementRelation> collectionElementRelationListNew = new ArrayList<>();
            for (CollectionElement element : collectionElementListOld) {
                element.setCollectionId(collectionIdNew);
                element.setId(null);
                collectionElementMapper.insert(element);
                TCollectionElementRelation collectionElementRelationNew = new TCollectionElementRelation();
                collectionElementRelationNew.setCollectionId(collectionIdNew);
                collectionElementRelationNew.setElementId(element.getId());
                collectionElementRelationMapper.insert(collectionElementRelationNew);
            }
            Portfolio portfolio = getPortfolioByUserGroupIdSource(userLikeGroupId);
            Long coverIdOld = portfolioDTO.getCoverId();
            portfolio.setPortfolioName(portfolioDTO.getPortfolioName());
//        portfolio.setPortfolioType("History");
            portfolio.setCollectionId(collectionIdNew);
            portfolio.setAccountId(authPrincipalVo.getId());
            portfolio.setCreateDate(LocalDateTime.now());
            portfolio.setUpdateDate(LocalDateTime.now());
            portfolio.setStatus(1);
            portfolio.setIsDeleted(0);
            portfolioMapper.updateById(portfolio);

            List<UserLike> userLikeList = userLikeService.getUserLikeList(userLikeGroupId);

            Long coverIdNew = null;
            Boolean flag = false;
            for (UserLike userLike : userLikeList) {
                Long designOutfitIdOld = userLike.getDesignOutfitId();
                TDesignPythonOutfit designPythonOutfit = designPythonOutfitMapper.selectById(designOutfitIdOld);
                designPythonOutfit.setDesignId(-1L);
                designPythonOutfit.setDesignItemId(-1L);
                designPythonOutfit.setCollectionId(collectionIdNew);
                if (!flag && designPythonOutfit.getId() == coverIdOld) {
                    flag = true;
                }
                designPythonOutfit.setId(null);
                designPythonOutfitMapper.insert(designPythonOutfit);
                Long designOutfitIdNew = designPythonOutfit.getId();
                userLike.setDesignOutfitId(designOutfitIdNew);
                QueryWrapper<TDesignPythonOutfitDetail> qw = new QueryWrapper<>();
                qw.lambda().eq(TDesignPythonOutfitDetail::getDesignPythonOutfitId, designOutfitIdOld);
                List<TDesignPythonOutfitDetail> tDesignPythonOutfitDetails = designPythonOutfitDetailMapper.selectList(qw);
                for (TDesignPythonOutfitDetail tDesignPythonOutfitDetail : tDesignPythonOutfitDetails) {
//                Long designPythonOutfitDetailIdOld = tDesignPythonOutfitDetail.getId();
                    tDesignPythonOutfitDetail.setId(null);
                    tDesignPythonOutfitDetail.setDesignId(-1L);
                    tDesignPythonOutfitDetail.setDesignPythonOutfitId(designOutfitIdNew);
                    designPythonOutfitDetailMapper.insert(tDesignPythonOutfitDetail);
                }

                if (flag) {
                    coverIdNew = designPythonOutfit.getId();
                    portfolio.setCoverId(coverIdNew);
                    portfolioMapper.updateById(portfolio);
                }

                Long designItemIdOld = userLike.getDesignItemId();
                DesignItem designItemOld = designItemMapper.selectById(designItemIdOld);
                designItemOld.setId(null);
                designItemOld.setAccountId(-1L);
                designItemOld.setDesignId(-1L);
                designItemOld.setCollectionId(collectionIdNew);
                designItemMapper.insert(designItemOld);
                Long designItemIdNew = designItemOld.getDesignId();

                designPythonOutfit.setDesignItemId(designItemIdNew);
                designPythonOutfitMapper.updateById(designPythonOutfit);

                userLike.setDesignItemId(designItemIdNew);
                userLike.setId(null);
                userLike.setDesignId(-1L);
                userLike.setUserLikeGroupId(userLikeGroupNew.getId());
                userLikeMapper.insert(userLike);
                QueryWrapper<DesignItemDetail> designItemDetailQueryWrapper = new QueryWrapper<>();
                designItemDetailQueryWrapper.lambda().eq(DesignItemDetail::getDesignItemId, designItemOld);
                List<DesignItemDetail> designItemDetailListOld = designItemDetailMapper.selectList(designItemDetailQueryWrapper);
                for (DesignItemDetail designItemDetailOld : designItemDetailListOld) {
                    Long designItemDetailIdOld = designItemDetailOld.getId();
                    designItemDetailOld.setAccountId(-1L);
                    designItemDetailOld.setDesignId(-1L);
                    designItemDetailOld.setDesignItemId(designItemIdNew);
                    designItemDetailMapper.insert(designItemDetailOld);
                    Long designItemDetailIdNew = designItemDetailOld.getId();
                    QueryWrapper<DesignItemDetailPrint> designItemDetailPrintQueryWrapper = new QueryWrapper<>();
                    designItemDetailPrintQueryWrapper.lambda().eq(DesignItemDetailPrint::getDesignItemDetailId, designItemDetailIdOld);
                    DesignItemDetailPrint designItemDetailPrint = designItemDetailPrintMapper.selectOne(designItemDetailPrintQueryWrapper);
                    if (Objects.nonNull(designItemDetailPrint)) {
                        designItemDetailPrint.setId(null);
                        designItemDetailPrint.setDesignItemDetailId(designItemDetailIdNew);
                        designItemDetailPrintMapper.insert(designItemDetailPrint);
                    }
                }
            }
        }

        return null;
    }

    private Portfolio getPortfolioByUserGroupIdSource(Long userLikeGroupId) {
        QueryWrapper<Portfolio> qw = new QueryWrapper<>();
        qw.lambda().eq(Portfolio::getUserLikeGroupSourceId, userLikeGroupId);
        return portfolioMapper.selectOne(qw);
    }

    @Override
    public PageBaseResponse<PortfolioVO> page(QueryPortfolioPageDTO query) {
//        AuthPrincipalVo userHolder = UserContext.getUserHolder();
        QueryWrapper<Portfolio> qw = new QueryWrapper<>();

        // 查询用户的作品集
        if (query.getGetMyPortfolio() == 1) {
            qw.lambda().eq(Portfolio::getAccountId, query.getAccountId());
        } else if (!Objects.isNull(query.getAccountId()) && !query.getAccountId().equals(0L) && query.getGetLikePortfolio() != 1) {
            qw.lambda().eq(Portfolio::getAccountId, query.getAccountId());
        }

        // 查询用户喜欢的作品集
        if (query.getGetLikePortfolio() == 1) {
            List<Long> likedPortfolioIdList = redisUtil.getLikedPortfolios(query.getAccountId());
            if (!CollectionUtils.isEmpty(likedPortfolioIdList)) {
                qw.lambda().in(Portfolio::getId, likedPortfolioIdList);
            } else {
                return PageBaseResponse.success(new Page<>());
            }
        }

        if (!Objects.isNull(query.getTagId()) && !query.getTagId().equals(0L)) {
            return queryPortfolioByTag(null, query.getTagId(), query.getPage(), query.getSize());
        }

        if (Objects.nonNull(query.getOrganizationId())) {
            qw.eq("organization_id", query.getOrganizationId());
        } else if (query.getGetMyPortfolio() == 0) {
            qw.eq("is_public", 1);
        }

        /*List<Portfolio> topThree = new ArrayList<>();
        List<Long> excludeIds = new ArrayList<>(); // 存放需要排除的 ID 列表
        // 获取前三点赞和前三浏览的作品集，并将其排除在分页查询之外
        if (query.getPage() == 1 && (query.getGetMyPortfolio() != 1 || query.getGetLikePortfolio() != 1)) {
            // 获取前三点赞的作品集 ID
            List<Long> topThreeLike = getTopThreeLikeFromRedis(RedisUtil.PORTFOLIO_LIKE_KEY);
            List<Long> topThreeView = getTopThreeViewFromRedis(RedisUtil.PORTFOLIO_VIEW_KEY, topThreeLike);
            // 获取前三点赞的作品集
            if (!CollectionUtils.isEmpty(topThreeLike)) {
                QueryWrapper<Portfolio> queryLike = new QueryWrapper<>();
                queryLike.in("id", topThreeLike);
                List<Portfolio> topThreeLikePortfolio = baseMapper.selectList(queryLike);
                topThree.addAll(topThreeLikePortfolio);
                excludeIds.addAll(topThreeLike); // 添加到排除 ID 列表
            }
            // 获取前三浏览的作品集
            if (!CollectionUtils.isEmpty(topThreeView)) {
                QueryWrapper<Portfolio> queryView = new QueryWrapper<>();
                queryView.in("id", topThreeView);
                List<Portfolio> topThreeViewPortfolio = baseMapper.selectList(queryView);
                topThree.addAll(topThreeViewPortfolio);
                excludeIds.addAll(topThreeView); // 添加到排除 ID 列表
            }
        }
        // 在正常分页查询中排除前三点赞和前三浏览的作品集
        if (!CollectionUtils.isEmpty(excludeIds)) {
            qw.lambda().notIn(Portfolio::getId, excludeIds);
        }*/

        // 按更新时间排序
        qw.lambda().orderByDesc(Portfolio::getUpdateDate);

        // 执行分页查询
        IPage<Portfolio> page = portfolioMapper.selectPage(new Page<>(query.getPage(), query.getSize()), qw);

        /*// 如果前三点赞和浏览不为空，将它们添加到分页查询的结果最前面
        if (!topThree.isEmpty()) {
            List<Portfolio> records = page.getRecords();
            records.addAll(0, topThree);  // 添加到查询结果的开头
            page.setRecords(records);
        }*/

        // 将 Portfolio 转换为 PortfolioVO 并进行相关处理
        IPage<PortfolioVO> convert = page.convert((Function<Portfolio, PortfolioVO>) portfolio -> {
            if (portfolio != null) {
                PortfolioVO vo = CopyUtil.copyObject(portfolio, PortfolioVO.class);
                Canvas canvas = canvasMapper.selectById(vo.getCanvasId());
                vo.setCanvasUrl(minioUtil.getPreSignedUrl(canvas.getUrl(), 24 * 60));
                vo.setLikeNum(redisUtil.getLikeCount(vo.getId()));
                vo.setViewNums(redisUtil.getViewCount(vo.getId()));
                Long accountId = vo.getAccountId();
                Account account = accountMapper.selectById(accountId);
                if (!Objects.isNull(account)) {
                    vo.setUserName(account.getUserName());
                    if (vo.getOriginal() == 0) {
                        vo.setOriginalUserName(accountMapper.selectById(vo.getOriginalAccountId()).getUserName());
                    }
                    return vo;
                }
            }
            return null;
        });

        return PageBaseResponse.success(convert);
    }

    @Override
    public PortfolioVO detail(PortfolioDTO portfolioDTO) {
//        AuthPrincipalVo userHolder = UserContext.getUserHolder();
        Portfolio portfolio = portfolioMapper.selectById(portfolioDTO.getId());
        PortfolioVO vo = CopyUtil.copyObject(portfolio, PortfolioVO.class);
        if (vo.getOpenSource() == 1) {
            if (!StringUtils.isEmpty(portfolio.getSnapshot())) {
                ProjectSnapshot projectSnapshot = JSONObject.parseObject(portfolio.getSnapshot(), ProjectSnapshot.class, Feature.DisableCircularReferenceDetect);
                List<CollectionElement> collectionElementList = projectSnapshot.getCollectionElementList();
                for (CollectionElement element : collectionElementList) {
                    if (StringUtils.isEmpty(element.getUrl())) {
                        continue;
                    }
                    element.setUrl(minioUtil.getPreSignedUrl(element.getUrl(), 24 * 60));
                }
                vo.setCollectionElementList(collectionElementList);
                List<UserLikeSnapshot> userLikeList = projectSnapshot.getUserLikeList();
                if (userLikeList != null && !userLikeList.isEmpty()) {
                    List<TDesignPythonOutfit> list = new ArrayList<>();
                    for (UserLikeSnapshot userLikeSnapshot : userLikeList) {
                        TDesignPythonOutfit designPythonOutfit = userLikeSnapshot.getDesignPythonOutfit();
                        if (designPythonOutfit != null && !StringUtils.isEmpty(designPythonOutfit.getDesignUrl())) {
                            designPythonOutfit.setDesignUrl(minioUtil.getPreSignedUrl(designPythonOutfit.getDesignUrl(), 24 * 60));
                            list.add(designPythonOutfit);
                        }
                    }
                    vo.setDesignPythonOutfitList(list);
                }
            }
        }
        Canvas canvas = canvasMapper.selectById(vo.getCanvasId());
        vo.setCanvasUrl(minioUtil.getPreSignedUrl(canvas.getUrl(), 24 * 60));
        vo.setLikeNum(redisUtil.getLikeCount(vo.getId()));
        String avatar;
        Account account = accountMapper.selectById(vo.getAccountId());
        if (Objects.isNull(portfolioDTO.getAccountId())) {
            vo.setIsLike(0);
            vo.setIsFollow(0);
            avatar = CommonConstant.DEFAULT_AVATAR;
        } else {
            boolean postLikedByUser = redisUtil.isPostLikedByUser(portfolioDTO.getId(), portfolioDTO.getAccountId());
            if (postLikedByUser) {
                vo.setIsLike(1);
            } else {
                vo.setIsLike(0);
            }
            // 设置当前用户是否关注了所查看作品的作者
            Integer ifFollowed = userFollowService.getIfFollowed(portfolio.getAccountId(), portfolioDTO.getAccountId());
            vo.setIsFollow(ifFollowed);
            avatar = StringUtil.isNullOrEmpty(account.getAvatar()) ? CommonConstant.DEFAULT_AVATAR : account.getAvatar();
        }
        vo.setAvatar(minioUtil.getPreSignedUrl(avatar, CommonConstant.MINIO_IMAGE_EXPIRE_TIME));
        redisUtil.increaseViewCount(portfolioDTO.getId());
        vo.setViewNums(redisUtil.getViewCount(portfolioDTO.getId()));
        vo.setUserName(account.getUserName());
        if (vo.getOriginal() == 0) {
            vo.setOriginalUserName(accountMapper.selectById(vo.getOriginalAccountId()).getUserName());
            Portfolio byId = portfolioMapper.getByIdAll(vo.getOriginalPortfolioId());
            if (Objects.nonNull(byId)) {
                String portfolioName = byId.getPortfolioName();
                vo.setOriginalPortfolioName(portfolioName);
                if (byId.getIsDeleted() == 0) {
                    vo.setJumpable(1);
                } else {
                    vo.setJumpable(0);
                }
            }
        }
        if (Objects.isNull(portfolioDTO.getAccountId())) {
            vo.setIsMine(0);
            vo.setSelected(0);
        } else {
            if (Objects.equals(vo.getAccountId(), portfolioDTO.getAccountId()) || Objects.equals(vo.getOriginalAccountId(), portfolioDTO.getAccountId())) {
                vo.setIsMine(1);
                vo.setSelected(1);
            } else {
                vo.setIsMine(0);
                QueryWrapper<UserLikeGroup> getSelectedQw = new QueryWrapper<>();
                getSelectedQw.lambda().eq(UserLikeGroup::getAccountId, portfolioDTO.getAccountId());
                getSelectedQw.lambda().eq(UserLikeGroup::getOriginalPortfolioId, vo.getId());
                List<UserLikeGroup> userLikeGroups = userLikeGroupMapper.selectList(getSelectedQw);
                if (CollectionUtils.isEmpty(userLikeGroups)) {
                    vo.setSelected(0);
                } else {
                    vo.setSelected(1);
                }
            }
        }

        return vo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ProjectChooseVO choose(PortfolioDTO portfolioDTO) {
        Long accountId = UserContext.getUserHolder().getId();
        Portfolio portfolio = portfolioMapper.selectById(portfolioDTO.getId());

        String snapshot = portfolio.getSnapshot();
        ProjectSnapshot projectSnapshot = JSONObject.parseObject(snapshot, ProjectSnapshot.class);
        Project projectOld = projectSnapshot.getProject();
        Workspace workspaceOld = projectSnapshot.getWorkspace();
        List<CollectionElement> collectionElementListOld = projectSnapshot.getCollectionElementList();
        UserLikeGroup userLikeGroupOld = projectSnapshot.getUserLikeGroup();
        List<UserLikeSnapshot> userLikeListOld = projectSnapshot.getUserLikeList();
        Project project = CopyUtil.copyObject(projectOld, Project.class);

        project.setCreateTime(LocalDateTime.now());
        project.setId(null);
        project.setAccountId(accountId);
        project.setUpdateTime(LocalDateTime.now());
        project.setName(project.getName() + "_copy");

        if (portfolio.getOriginal() == 1) {
            if (Objects.equals(portfolio.getAccountId(), accountId)) {
                project.setOriginal(1);
            } else {
                project.setOriginal(0);
                project.setOriginalAccountId(portfolio.getAccountId());
                project.setOriginalPortfolioId(portfolio.getId());
            }
        } else {
            project.setOriginal(0);
            project.setOriginalAccountId(portfolio.getOriginalAccountId());
            project.setOriginalPortfolioId(portfolio.getId());
        }

        projectMapper.insert(project);

        Long projectIdNew = project.getId();

        workspaceOld.setAccountId(accountId);
        workspaceOld.setProjectId(projectIdNew);
        workspaceOld.setId(null);
        workspaceMapper.insert(workspaceOld);

        // 复制collectionElement
        for (CollectionElement element : collectionElementListOld) {
            if (element.getLevel1Type().equals(CollectionLevel1TypeEnum.MODEL.getRealName())) {
                LambdaQueryWrapper<CollectionElementRelModel> relModelLambdaQueryWrapper = new LambdaQueryWrapper<>();
                relModelLambdaQueryWrapper.eq(CollectionElementRelModel::getCollectionElementId, element.getId());
                CollectionElementRelModel collectionElementRelModelCopy = collectionElementRelModelMapper.selectOne(relModelLambdaQueryWrapper);
//                element.setCollectionId(collectionIdNew);
                element.setId(null);
                element.setCreateDate(new Date());
                element.setUpdateDate(null);
                element.setAccountId(accountId);
                element.setProjectId(projectIdNew);
                if (element.getLevel3Type() == null) {
                    element.setLevel3Type(workspaceOld.getSex());
                }
                collectionElementMapper.insert(element);
                Long collectionElementNewID = element.getId();
                if (collectionElementRelModelCopy != null) {
                    collectionElementRelModelCopy.setId(null);
                    collectionElementRelModelCopy.setCollectionElementId(collectionElementNewID);
                    collectionElementRelModelMapper.insert(collectionElementRelModelCopy);
                }
                ;
            } else if (element.getLevel1Type().equals(CollectionLevel1TypeEnum.SKETCH_BOARD.getRealName())) {
//                element.setCollectionId(collectionIdNew);
                if (element.getLevel3Type() == null) {
                    element.setLevel3Type(workspaceOld.getSex());
                }
                element.setId(null);
                element.setCreateDate(new Date());
                element.setUpdateDate(null);
                element.setAccountId(accountId);
                element.setProjectId(projectIdNew);
                collectionElementMapper.insert(element);
            } else {
//                element.setCollectionId(collectionIdNew);
                element.setId(null);
                element.setCreateDate(new Date());
                element.setUpdateDate(null);
                element.setAccountId(accountId);
                element.setProjectId(projectIdNew);
                collectionElementMapper.insert(element);
            }

        }


        if (userLikeGroupOld != null) {

            Long collectionIdOld = userLikeGroupOld.getCollectionId();
            Collection collectionCopy = collectionMapper.selectById(collectionIdOld);
            collectionCopy.setId(null);
            collectionCopy.setAccountId(accountId);
            collectionCopy.setCreateDate(new Date());
            collectionMapper.insert(collectionCopy);
            Long collectionIdNew = collectionCopy.getId();

            userLikeGroupOld.setId(null);
            userLikeGroupOld.setCollectionId(collectionIdNew);
            userLikeGroupOld.setCreateDate(new Date());
            userLikeGroupOld.setProjectId(projectIdNew);
            if (portfolio.getOriginal() == 1) {
                if (Objects.equals(portfolio.getAccountId(), accountId)) {
                    userLikeGroupOld.setOriginal(1);
                } else {
                    userLikeGroupOld.setOriginal(0);
                    userLikeGroupOld.setOriginalAccountId(portfolio.getAccountId());
                    userLikeGroupOld.setOriginalPortfolioId(portfolio.getId());
                }
            } else {
                userLikeGroupOld.setOriginal(0);
                userLikeGroupOld.setOriginalAccountId(portfolio.getOriginalAccountId());
                userLikeGroupOld.setOriginalPortfolioId(portfolio.getId());
            }
            userLikeGroupOld.setAccountId(accountId);
            userLikeGroupOld.setUpdateDate(new Date());
            userLikeGroupMapper.insert(userLikeGroupOld);
            Long userLikeGroupIdNew = userLikeGroupOld.getId();


            //根据designId进行分组
            Map<Long, List<UserLikeSnapshot>> userLikeMapByDesignId = userLikeListOld.stream()
                    .filter(userLikeSnapshot -> userLikeSnapshot.getDesignItem() != null)
                    .collect(Collectors.groupingBy(userLikeSnapshot -> userLikeSnapshot.getDesignItem().getDesignId()));
            userLikeMapByDesignId.forEach((designId, userLikeListOld1) -> {
                Design design = designMapper.selectById(designId);
                //数据库中存在designId为-1的情况
                if (design == null) {
                    design = new Design();
                    //此处值从workspace里取
                    design.setSystemScale(BigDecimal.valueOf(workspaceOld.getSystemDesignerPercentage()).movePointLeft(2));
                    //根据CollectionElement存在model来判断是否是single
                    List<CollectionElement> modelTypeElements = collectionElementListOld.stream()
                            .filter(element -> element.getLevel1Type().equals(CollectionLevel1TypeEnum.MODEL.getRealName()))
                            .collect(Collectors.toList());
                    if (CollectionUtil.isNotEmpty(modelTypeElements)) {
                        design.setSingleOverall("overall");
                    } else {
                        design.setSingleOverall("single");
                    }

                }
                design.setId(null);
                design.setCollectionId(collectionIdNew);
                design.setAccountId(accountId);
                design.setCreateDate(new Date());
                designMapper.insert(design);

                for (UserLikeSnapshot userLikeSnapshot : userLikeListOld1) {


                    // 4. 处理DesignItem数据
                    DesignItem designItem = userLikeSnapshot.getDesignItem();
                    if (designItem != null) {
                        designItem.setId(null);
                        designItem.setAccountId(accountId);
                        designItem.setDesignId(design.getId());
                        designItem.setCollectionId(collectionIdNew);
                        designItem.setCreateDate(new Date());
                        designItemMapper.insert(designItem);

                        // 5. 处理DesignItemDetailSnapshot数据
                        List<DesignItemDetailSnapshot> itemDetailSnapshots = userLikeSnapshot.getDesignItemDetailList();
                        if (itemDetailSnapshots != null && !itemDetailSnapshots.isEmpty()) {
                            for (DesignItemDetailSnapshot itemDetailSnapshot : itemDetailSnapshots) {
                                //只复制未删除的
                                if (itemDetailSnapshot.getIsDeleted() == 1) {
                                    continue;
                                }
                                // 转换为原实体类
                                DesignItemDetail designItemDetail = CopyUtil.copyObject(itemDetailSnapshot, DesignItemDetail.class);
                                designItemDetail.setId(null);
                                // 更新外键为新插入的designItem的ID
                                designItemDetail.setDesignItemId(designItem.getId());
                                designItemDetail.setDesignId(design.getId());
                                designItemDetail.setCreateDate(new Date());
                                designItemDetail.setAccountId(accountId);
                                designItemDetailMapper.insert(designItemDetail);

                                // 6. 处理DesignItemDetailPrint数据
                                List<DesignItemDetailPrint> prints = itemDetailSnapshot.getDesignItemDetailPrintList();
                                if (prints != null && !prints.isEmpty()) {
                                    for (DesignItemDetailPrint print : prints) {
                                        print.setId(null);
                                        print.setCreateDate(LocalDateTime.now());
                                        // 更新外键为新插入的designItemDetail的ID
                                        print.setDesignItemDetailId(designItemDetail.getId());
                                        designItemDetailPrintMapper.insert(print);
                                    }
                                }
                            }
                        }
                    }


                    // 2. 处理DesignPythonOutfit数据
                    TDesignPythonOutfit outfit = userLikeSnapshot.getDesignPythonOutfit();
                    if (outfit != null) {
                        // 清除原有ID，使用新ID插入
                        outfit.setId(null);
                        outfit.setDesignId(design.getId());
                        outfit.setCollectionId(collectionIdNew);
                        outfit.setCreateDate(LocalDateTime.now());
                        outfit.setDesignItemId(designItem.getId());
                        designPythonOutfitMapper.insert(outfit);

                        // 3. 处理TDesignPythonOutfitDetail数据
                        List<TDesignPythonOutfitDetail> outfitDetails = userLikeSnapshot.getTDesignPythonOutfitDetailList();
                        if (outfitDetails != null && !outfitDetails.isEmpty()) {
                            for (TDesignPythonOutfitDetail detail : outfitDetails) {
                                detail.setId(null);
                                // 更新外键为新插入的outfit的ID
                                detail.setDesignPythonOutfitId(outfit.getId());
                                detail.setCreateDate(LocalDateTime.now());
                                detail.setUpdateDate(LocalDateTime.now());
                                detail.setUserId(accountId);
                                detail.setDesignId(design.getId());
                                designPythonOutfitDetailMapper.insert(detail);
                            }
                        }
                    }

                    UserLike userLike = CopyUtil.copyObject(userLikeSnapshot, UserLike.class);

                    userLike.setId(null);
                    userLike.setDesignId(design.getId());
                    userLike.setUserLikeGroupId(userLikeGroupIdNew);
                    userLike.setDesignItemId(designItem.getId());
                    userLike.setDesignOutfitId(outfit.getId());
                    userLikeService.save(userLike);
                    CollectionSort collectionSortDesign = new CollectionSort();
                    collectionSortDesign.setProjectId(project.getId());
                    collectionSortDesign.setRelationId(userLike.getId());
                    collectionSortDesign.setRelationType(CollectionType.DESIGN.getValue());
                    collectionSortDesign.setCreateTime(LocalDateTime.now());
                    int nextSort = collectionSortService.getNextSort(projectIdNew, null);
                    collectionSortDesign.setSort(nextSort);
                    collectionSortMapper.insert(collectionSortDesign);

                    //此集合为根据UserLikeId查询到的非Design类型的集合
                    List<CollectionSort> collectionSorts = collectionSortMapper.queryCollectionSortsIsNotDesignByUserLikeRelationId(userLikeSnapshot.getId());
                    if (collectionSorts != null && !collectionSorts.isEmpty()) {
                        for (CollectionSort collectionSort : collectionSorts) {

                            CollectionSort collectionSortNew = new CollectionSort();
                            if (collectionSort.getRelationType().equals(CollectionType.TO_PRODUCT_IMAGE.getValue()) || collectionSort.getRelationType().equals(CollectionType.RELIGHT.getValue())) {
                                ToProductImageResult toProductImageResult = toProductImageResultMapper.selectById(collectionSort.getRelationId());
                                ToProductImageRecord toProductImageRecord = toProductImageRecordMapper.selectById(toProductImageResult.getToProductImageRecordId());
                                toProductImageRecord.setId(null);
                                toProductImageRecord.setProjectId(projectIdNew);
                                toProductImageRecord.setCreateTime(LocalDateTime.now());
                                toProductImageRecord.setUserLikeGroupId(userLikeGroupIdNew);
                                toProductImageRecordMapper.insert(toProductImageRecord);
                                toProductImageResult.setId(null);
                                toProductImageResult.setProjectId(projectIdNew);
                                toProductImageResult.setToProductImageRecordId(toProductImageRecord.getId());
                                toProductImageResult.setCreateTime(LocalDateTime.now());
                                toProductImageResult.setUserLikeGroupId(userLikeGroupIdNew);
                                toProductImageResultMapper.insert(toProductImageResult);
                                collectionSortNew.setRelationId(toProductImageResult.getId());
                            } else if (collectionSort.getRelationType().equals(CollectionType.POSE_TRANSFORM.getValue())) {
                                PoseTransformation poseTransformation = poseTransformationMapper.selectById(collectionSort.getRelationId());
                                poseTransformation.setId(null);
                                poseTransformation.setProjectId(projectIdNew);
                                poseTransformation.setCreateTime(LocalDateTime.now());
                                poseTransformation.setUpdateTime(LocalDateTime.now());
                                poseTransformation.setAccountId(accountId);
                                poseTransformationMapper.insert(poseTransformation);
                                collectionSortNew.setRelationId(poseTransformation.getId());

                            }
                            collectionSortNew.setProjectId(project.getId());
                            collectionSortNew.setRelationType(collectionSort.getRelationType());
                            collectionSortNew.setCreateTime(LocalDateTime.now());
                            collectionSortNew.setParentId(collectionSortDesign.getId());
                            int nextSort2 = collectionSortService.getNextSort(projectIdNew, collectionSortDesign.getId());
                            collectionSortNew.setSort(nextSort2);
                            collectionSortMapper.insert(collectionSortNew);
                        }
                    }

                }
            });


        }
        ProjectDTO projectDTO = new ProjectDTO();
        projectDTO.setId(project.getId());

        return userLikeGroupService.choose(projectDTO);
    }

    @Override
    public Boolean designWorksRegister(DesignWorksRegisterDTO designWorksRegisterDTO) {
        return null;
    }

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private MessageCenterService messageCenterService;

    @Override
    public Boolean like(Long id) {
        AuthPrincipalVo userHolder = UserContext.getUserHolder();
        redisUtil.likePost(id, userHolder.getId());
        Portfolio byIdAll = baseMapper.getByIdAll(id);
        messageCenterService.prePushMessage(new Notification("like", userHolder.getId(), byIdAll.getAccountId(), id));
        return Boolean.TRUE;
    }

    @Resource
    private CommentMapper commentMapper;

    @Override
    public Boolean comment(CommentDTO commentDTO) {
        AuthPrincipalVo userHolder = UserContext.getUserHolder();
        Comment comment = CopyUtil.copyObject(commentDTO, Comment.class);
        comment.setCreateTime(LocalDateTime.now());
        comment.setAccountId(userHolder.getId());
        commentMapper.insert(comment);
        Portfolio portfolio = baseMapper.selectById(comment.getPortfolioId());
        messageCenterService.prePushMessage(new Notification("comment", userHolder.getId(), portfolio.getAccountId(), portfolio.getId(), commentDTO.getComment(), comment.getId()));
        return Boolean.TRUE;
    }

    @Override
    public PageBaseResponse<CommentVO> commentPage(CommentPageDTO commentPageDTO) {
        QueryWrapper<Comment> qw = new QueryWrapper<>();
        qw.lambda().eq(Comment::getPortfolioId, commentPageDTO.getPortfolioId());
        qw.lambda().eq(Comment::getParentLevel1Id, 0L);
        qw.lambda().orderByDesc(Comment::getCreateTime);
        Page<Comment> commentPage = commentMapper.selectPage(new Page<>(commentPageDTO.getPage(), commentPageDTO.getSize()), qw);
        IPage<CommentVO> convert = commentPage.convert(o -> {
            CommentVO commentVO = CopyUtil.copyObject(o, CommentVO.class);
            commentVO.setUserName(accountMapper.selectById(commentVO.getAccountId()).getUserName());
            List<CommentVO> childList = getChildCommentVOList(commentVO.getId());
            if (!CollectionUtils.isEmpty(childList)) {
                commentVO.setChildCommentVOList(childList);
            }
            return commentVO;
        });
        return PageBaseResponse.success(convert);
    }

    @Override
    public Boolean unlike(Long id) {
        AuthPrincipalVo userHolder = UserContext.getUserHolder();
        redisUtil.unLikePost(id, userHolder.getId());
        Portfolio portfolio = baseMapper.selectById(id);
        messageCenterService.cancelPushMessage("like", userHolder.getId(), portfolio.getAccountId(), portfolio.getId(), null);
        return Boolean.TRUE;
    }

    @Override
    public Long getLikeCount(Long id) {
        return redisUtil.getLikeCount(id);
    }

    @Override
    public Boolean viewsIncrease(Long id) {
        redisUtil.increaseViewCount(id);
        return Boolean.TRUE;
    }

    @Override
    public Long viewsGet(Long id) {
        return redisUtil.getViewCount(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean commentDelete(CommentDTO commentDTO) {

        Long id = commentDTO.getId();
        Portfolio portfolio = portfolioMapper.selectById(commentDTO.getPortfolioId());
        Comment comment = commentMapper.selectById(id);
        AuthPrincipalVo userHolder = UserContext.getUserHolder();
        if (!Objects.equals(portfolio.getAccountId(), userHolder.getId())) {
            if (!Objects.equals(comment.getAccountId(), userHolder.getId())) {
                throw new BusinessException("do.not.have.the.permission.to.delete.this.comment");
            }
        }

        // 获取消息接收者id（即该操作的接收者)
        Long receiverId;
        if (!comment.getParentLevel1Id().equals(0L)) {
            receiverId = commentMapper.selectById(comment.getParentLevel1Id()).getAccountId();
        } else {
            receiverId = portfolio.getAccountId();
        }

        // 删除主评论
        commentMapper.deleteById(id);

        // 删除子评论
        LambdaQueryWrapper<Comment> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Comment::getParentLevel1Id, id)
                .or()
                .eq(Comment::getParentLevel2Id, id);
        commentMapper.delete(lambdaQueryWrapper);

        messageCenterService.cancelPushMessage("comment", userHolder.getId(), receiverId, portfolio.getId(), id);
        return Boolean.TRUE;
    }

    @Override
    public Boolean delete(Long id) {
        AuthPrincipalVo userHolder = UserContext.getUserHolder();
        Portfolio portfolio = portfolioMapper.selectById(id);
        if (!Objects.equals(portfolio.getAccountId(), userHolder.getId())) {
            throw new BusinessException("You do not have the permission to delete portfolio.");
        }
        portfolioMapper.deleteById(id);

        // 删除作品与标签的关联记录
        portfolioTagsMapper.deleteByPortfolioId(id);
        return Boolean.TRUE;
    }

    @Override
    public Portfolio getByIdAll(Long originalPortfolioId) {
        return portfolioMapper.getByIdAll(originalPortfolioId);
    }

    private List<CommentVO> getChildCommentVOList(Long id) {
        QueryWrapper<Comment> qw = new QueryWrapper<>();
        qw.lambda().eq(Comment::getParentLevel1Id, id);
        qw.lambda().orderByDesc(Comment::getCreateTime);
        List<Comment> comments = commentMapper.selectList(qw);
        if (CollectionUtils.isEmpty(comments)) {
            return new ArrayList<>();
        }
        List<CommentVO> resultList = new ArrayList<>();
        for (Comment comment : comments) {
            CommentVO commentVO = CopyUtil.copyObject(comment, CommentVO.class);
            commentVO.setUserName(accountMapper.selectById(commentVO.getAccountId()).getUserName());
            if (null != commentVO.getParentLevel2Id()) {
                Comment comment1 = commentMapper.selectById(commentVO.getParentLevel2Id());
                commentVO.setReplyTo(accountMapper.selectById(comment1.getAccountId()).getUserName());
            }
            resultList.add(commentVO);
        }
//        List<CommentVO> commentVOS = CopyUtil.copyList(comments, CommentVO.class);
//        for (CommentVO commentVO : commentVOS) {
//            List<CommentVO> childCommentVOList = getChildCommentVOList(commentVO.getId());
//            if (!CollectionUtils.isEmpty(childCommentVOList)) {
//                commentVO.setChildCommentVOList(childCommentVOList);
//            }
//        }
        return resultList;
    }

    private List<Long> getTopThreeLikeFromRedis(String prefix) {
        // 获取所有与 PORTFOLIO_LIKE_KEY 相关的 keys
        Set<String> keys = redisUtil.getKeysFromString(prefix + "*");

        List<Map.Entry<String, Long>> portfolioSizes = new ArrayList<>();

        if (keys != null) {
            for (String key : keys) {
                // 获取 Set 的 size
                Long size = redisUtil.getSize(key);
                // 保存 key 和 size
                portfolioSizes.add(new AbstractMap.SimpleEntry<>(key, size));
            }
            // 按 size 倒序排序
            portfolioSizes.sort((e1, e2) -> e2.getValue().compareTo(e1.getValue()));
            // 获取 size 最大的前三个
            // 去掉前缀，获取 portfolioId
            // 输出 top3PortfolioIds
//            top3PortfolioIds.forEach(System.out::println);
            return portfolioSizes.stream()
                    .limit(3)
                    .map(Map.Entry::getKey)
                    .map(key -> key.replace(prefix, "")) // 去掉前缀，获取 portfolioId
                    .map(Long::valueOf)
                    .collect(Collectors.toList());
        }
        return null;
    }

    private List<Long> getTopThreeViewFromRedis(String prefix, List<Long> excludeIds) {
        // Step 1: Get all keys with the specific prefix
        Set<String> keys = redisUtil.getKeysFromString(prefix + "*");

        // Step 2: Create a map to store portfolioId and its corresponding value
        Map<Long, Long> portfolioViews = new HashMap<>();
        if (keys != null) {
            for (String key : keys) {
                // Get the value associated with the key
                Long value = redisUtil.getViewCount(key);
                if (!Objects.isNull(value)) {
                    // Extract the portfolioId from the key (assuming the key structure is consistent)
                    Long portfolioId = Long.valueOf(key.replace(prefix, ""));
                    // 只将不在点赞前三的 portfolioId 加入
                    if (!excludeIds.contains(portfolioId)) {
                        portfolioViews.put(portfolioId, value);
                    }
                }
            }
        }

        // Step 3: Find the top 3 portfolio IDs with the largest values
        if (!portfolioViews.isEmpty()) {

//            System.out.println("Top 3 Portfolio IDs after exclusion: " + top3PortfolioIds);
            return portfolioViews.entrySet().stream()
                    .sorted(Map.Entry.<Long, Long>comparingByValue().reversed())
                    .limit(3)
                    .map(Map.Entry::getKey)
                    .collect(Collectors.toList());
        }
        return null;
    }

    // 验证该用户是否已参加活动
    public Boolean hasParticipatedRCAWorkshop(Long accountId, List<TagsDTO> tags, Long portfolioId, Long userLikeGroupId) {
        List<String> collect = tags.stream().map(Tags::getTagName).collect(Collectors.toList());
        if (!collect.contains(CommonConstant.RCA_WORKSHOP_TAG)) {
            return false;
        } else {
            UserLikeGroup userLikeGroup = userLikeGroupMapper.selectById(userLikeGroupId);
            // 不是原创的作品不能参与活动
            if (userLikeGroup.getOriginal().equals(0)) {
                throw new BusinessException("only.original.works.can.participate.in.the.event", ResultEnum.PROMPT.getCode());
            }
            List<Portfolio> byTag = baseMapper.getByTag(accountId, CommonConstant.RCA_WORKSHOP_TAG);
            if (byTag.isEmpty()) {
                return false;
            } else if (!Objects.isNull(portfolioId)) {
                boolean contains = byTag.stream().map(Portfolio::getId).collect(Collectors.toList()).contains(portfolioId);
                return !contains;
            } else {
                return true;
            }
        }
    }

    public void addTagsForPortfolio(List<TagsDTO> tagsDTOS, Long portfolioId) {
        // 遍历数组，添加到t_portfolio_tags表中，没有id的tag，添加到t_tags表中
        tagsDTOS.forEach(tag -> {
            Long tagId;
            if (Objects.isNull(tag.getId())) {
                Tags tags = tagsService.addTag(tag.getTagName());
                tagId = tags.getId();
            } else {
                tagId = tag.getId();
            }
            portfolioTagsMapper.insertIgnore(portfolioId, tagId, LocalDateTime.now());
        });
    }

    public PageBaseResponse<PortfolioVO> queryPortfolioByTag(String tagName, Long tagId, Integer page, Integer size) {
        long bestMatchTagId;
        if (Objects.isNull(tagId)) {

            List<Map<String, String>> matchingTags = tagsMapper.getMatchingTags(tagName);
            Map<String, String> tagMap = matchingTags.get(0);
            bestMatchTagId = Long.parseLong(tagMap.get("id"));
        } else {
            bestMatchTagId = tagId;
        }

        QueryWrapper<PortfolioTags> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("tag_id", bestMatchTagId).select("portfolio_id");

        List<PortfolioTags> portfolioTags = portfolioTagsMapper.selectList(queryWrapper);
        List<Long> portfolioIdList = portfolioTags.stream().map(PortfolioTags::getPortfolioId).collect(Collectors.toList());

        if (!portfolioIdList.isEmpty()) {
            QueryWrapper<Portfolio> qw = new QueryWrapper<>();
            qw.in("id", portfolioIdList);
            Page<Portfolio> portfolioPage = baseMapper.selectPage(new Page<>(page, size), qw);

            // 将 Portfolio 转换为 PortfolioVO 并进行相关处理
            IPage<PortfolioVO> convert = portfolioPage.convert((Function<Portfolio, PortfolioVO>) portfolio -> {
                if (portfolio != null) {
                    PortfolioVO vo = CopyUtil.copyObject(portfolio, PortfolioVO.class);
                    Canvas canvas = canvasMapper.selectById(vo.getCanvasId());
                    vo.setCanvasUrl(minioUtil.getPreSignedUrl(canvas.getUrl(), 24 * 60));
                    vo.setLikeNum(redisUtil.getLikeCount(vo.getId()));
                    vo.setViewNums(redisUtil.getViewCount(vo.getId()));
                    Long accountId = vo.getAccountId();
                    vo.setUserName(accountMapper.selectById(accountId).getUserName());
                    if (vo.getOriginal() == 0) {
                        vo.setOriginalUserName(accountMapper.selectById(vo.getOriginalAccountId()).getUserName());
                    }
                    return vo;
                }
                return null;
            });
            return PageBaseResponse.success(convert);
        } else {
            return PageBaseResponse.success(new Page<>());
        }

    }

    public void follow(Long followeeId) {
        Long accountId = UserContext.getUserHolder().getId();
        // 1、不能关注自己
        if (Objects.equals(followeeId, accountId)) {
            throw new BusinessException("you.cannot.follow.yourself", 1);
        }
        // 2、不能重复关注
        QueryWrapper<UserFollow> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("followee_id", followeeId).eq("follower_id", accountId);
        UserFollow userFollow = userFollowMapper.selectOne(queryWrapper);
        if (!Objects.isNull(userFollow)) {
            throw new BusinessException("you.have.already.followed.this.user", 1);
        }
        // 3、添加新follower到关注列表
        UserFollow newFollower = new UserFollow(followeeId, accountId);
        newFollower.setCreateTime(LocalDateTime.now());
        userFollowMapper.insert(newFollower);
        // 4、推送消息
        messageCenterService.prePushMessage(new Notification("follow", accountId, followeeId));
        messageCenterService.pushMessage("follow", accountId);
    }

    // 取消关注
    public void cancelFollow(Long followeeId) {
        Long accountId = UserContext.getUserHolder().getId();
        // 1、确定是否关注了该用户
        QueryWrapper<UserFollow> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("followee_id", followeeId).eq("follower_id", accountId);
        UserFollow userFollow = userFollowMapper.selectOne(queryWrapper);
        // 2、删除关注记录
        if (!Objects.isNull(userFollow)) {
            userFollowMapper.deleteById(userFollow.getId());
            // 3、逻辑删除关注消息
            messageCenterService.cancelPushMessage("follow", accountId, followeeId, null, null);
        } else {
            throw new BusinessException("you.have.not.followed.the.current.user", 1);
        }
        // 3、更新关注人数
        messageCenterService.pushMessage("follow", accountId);
        messageCenterService.pushMessage("follow", followeeId);
    }

    public Long getPortfolioCount(Long accountId) {
        QueryWrapper<Portfolio> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("account_id", accountId);

        return baseMapper.selectCount(queryWrapper);
    }


    public void setPortfolioToPublic(Long portfolioId) {
        // 判断当前用户与作品用户是不是一家公司的
        Long accountId = UserContext.getUserHolder().getId();
        Account currentAccount = accountMapper.selectById(accountId);
        Portfolio portfolio = baseMapper.selectById(portfolioId);

        if (Objects.isNull(portfolio)) {
            throw new BusinessException("unknown portfolio");
        }
        if (Objects.nonNull(portfolio.getOrganizationId())
                && Objects.nonNull(currentAccount.getOrganizationId())
                && portfolio.getOrganizationId().equals(currentAccount.getOrganizationId())) {
            portfolio.setIsPublic(1);
            portfolio.setUpdateDate(LocalDateTime.now());
            baseMapper.updateById(portfolio);
        } else {
            throw new BusinessException("have.no.permission", ResultEnum.PROMPT.getCode());
        }
    }

}
