package com.ai.da.common.config;

import com.ai.da.common.enums.CollectionLevel1TypeEnum;
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.model.dto.*;
import com.ai.da.model.enums.CollectionType;
import com.ai.da.model.enums.DesignProcess;
import com.ai.da.model.enums.Sex;
import com.ai.da.model.vo.ValidateElementVO;
import com.ai.da.python.PythonService;
import com.ai.da.python.vo.DesignPythonObjects;
import com.ai.da.service.*;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.security.core.parameters.P;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StopWatch;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
@Slf4j
@Component
public class MyTaskScheduler {

    @PostConstruct
    public void test() {
//        clearMinio();
//        addSystemFileStyle();
//        sendTrialOrderExcelToManagements();
//        createLikeSketchData();
//        statisticalCoincidenceDegree();
//        freqAddTest();
//        runMetricsComparison();
//        testAverageHitRatio();
//        saveUserLikedSketchDataToRedis(4L);
//        runComparisonAndRecordResults(5);
//        saveDataToNumpyFormat();
//        projectDataCreate();
//        collectionSortData();
    }

    private void collectionSortData() {
        // ToProductElement更新project_id及type字段 不需要了
//        QueryWrapper<ToProductImageResult> toProductImageResultQueryWrapper = new QueryWrapper<>();
//        toProductImageResultQueryWrapper.lambda().eq(ToProductImageResult::getIsLike, 1);
//        toProductImageResultQueryWrapper.lambda().eq(ToProductImageResult::getElementType, "ProductElement");
//        List<ToProductImageResult> toProductImageResultList = toProductImageResultMapper.selectList(toProductImageResultQueryWrapper);
//        for (ToProductImageResult toProductImageResult : toProductImageResultList) {
//            Long elementId = toProductImageResult.getElementId();
//            Long userLikeGroupId = toProductImageResult.getUserLikeGroupId();
//            ToProductElement toProductElement = toProductELementMapper.selectById(elementId);
//            UserLikeGroup userLikeGroup = userLikeGroupMapper.selectById(userLikeGroupId);
//            if (Objects.nonNull(userLikeGroup)) {
//                toProductElement.setProjectId(userLikeGroup.getProjectId());
//                toProductElement.setType(toProductImageResult.getResultType());
//                toProductELementMapper.updateById(toProductElement);
//            }
//        }

        // collection_sort表数据添加
        QueryWrapper<CollectionSort> qw = new QueryWrapper<>();
        List<CollectionSort> collectionSortList = collectionSortMapper.selectList(qw);
        for (CollectionSort collectionSort : collectionSortList) {
            Long userLikeGroupId = collectionSort.getUserLikeGroupId();
            QueryWrapper<UserLikeGroup> userLikeGroupQueryWrapper = new QueryWrapper<>();
            userLikeGroupQueryWrapper.lambda().eq(UserLikeGroup::getId, userLikeGroupId);
            UserLikeGroup userLikeGroup = userLikeGroupMapper.selectOne(userLikeGroupQueryWrapper);
            if (Objects.nonNull(userLikeGroup)) {
                collectionSort.setProjectId(userLikeGroup.getProjectId());
                collectionSort.setRelationId(collectionSort.getUserLikeId());
                collectionSort.setRelationType(CollectionType.DESIGN.getValue());
                collectionSortMapper.updateById(collectionSort);
            }
            // 根据关联查询是否有相关的喜欢的toproduct及relight结果
            UserLike userLike = userLikeMapper.selectById(collectionSort.getRelationId());
            if (Objects.nonNull(userLike)) {
                Long designOutfitId = userLike.getDesignOutfitId();
                QueryWrapper<ToProductImageResult> toProductImageResultQueryWrapper1 = new QueryWrapper<>();
                toProductImageResultQueryWrapper1.lambda().eq(ToProductImageResult::getElementId, designOutfitId);
                toProductImageResultQueryWrapper1.lambda().eq(ToProductImageResult::getIsLike, 1);
                List<ToProductImageResult> toProductImageResultList1 = toProductImageResultMapper.selectList(toProductImageResultQueryWrapper1);
                if (!CollectionUtils.isEmpty(toProductImageResultList1)) {
                    for (ToProductImageResult toProductImageResult : toProductImageResultList1) {
                        collectionSortService.addCollectionSort(toProductImageResult.getId(), CollectionType.TO_PRODUCT_IMAGE.getValue(), collectionSort.getProjectId(), collectionSort.getId());

                        QueryWrapper<ToProductImageResult> relightResultQueryWrapper = new QueryWrapper<>();
                        relightResultQueryWrapper.lambda().eq(ToProductImageResult::getElementId, toProductImageResult.getId());
                        relightResultQueryWrapper.lambda().eq(ToProductImageResult::getIsLike, 1);
                        List<ToProductImageResult> toProductImageResultList2 = toProductImageResultMapper.selectList(relightResultQueryWrapper);

                        if (!CollectionUtils.isEmpty(toProductImageResultList2)) {
                            for (ToProductImageResult relight : toProductImageResultList2) {
                                collectionSortService.addCollectionSort(relight.getId(), CollectionType.RELIGHT.getValue(), collectionSort.getProjectId(), collectionSort.getId());
                            }
                        }

                    }
                }
            }
        }
    }

    @Resource
    private CollectionSortMapper collectionSortMapper;
    @Resource
    private DesignService designService;

    @Resource
    private ToProductElementMapper toProductELementMapper;

    @Resource
    private AccountMapper accountMapper;

    @Resource
    private TrialOrderMapper trialOrderMapper;

    @Resource
    private DesignMapper designMapper;
    @Resource
    private ProjectMapper projectMapper;
    @Resource
    private WorkspaceMapper workspaceMapper;
    @Resource
    private WorkspaceService workspaceService;
    @Resource
    private UserLikeGroupService userLikeGroupService;
    @Resource
    private ExportFileMapper exportFileMapper;
    @Resource
    private PortfolioMapper portfolioMapper;
    @Resource
    private CollectionSortService collectionSortService;
    @Autowired
    private Environment environment;

    // 定时任务，每十五天执行一次
//    @Scheduled(cron = "0 0 0 ? * MON")
//    @Scheduled(cron = "0 0 0 */15 * ?")
    public void checkExpiry() {
        // 检测正式用户是否快要过期
        QueryWrapper<Account> qw = new QueryWrapper<>();
        qw.lambda().eq(Account::getIsTrial, 0);
//        qw.lambda().eq(Account::getId, 88);
        List<Account> accountList = accountMapper.selectList(qw);
        for (Account account : accountList) {
            // 用户到期时间戳
            Long timestamp = account.getValidEndTime(); // 替换为你的时间戳

            if (null == timestamp) {
                continue;
            }
            // 获取当前时间戳
            Long currentTimestamp = System.currentTimeMillis();

            // 计算时间差（毫秒）
            long timeDifference = currentTimestamp - timestamp;

            if (timeDifference < 0) {
                continue;
            }

            // 判断是否在30天以内（30天的毫秒数）
            long thirtyDaysInMillis = 30L * 24 * 60 * 60 * 1000;
            boolean within30Days = timeDifference <= thirtyDaysInMillis;

            String[] activeProfiles = environment.getActiveProfiles();
            boolean env = activeProfiles.length == 1 && Objects.equals(activeProfiles[0], "prod");
            if (within30Days && env) {
                // 发邮件
                SendEmailUtil.sendWillBeExpiredEmail(account, null);
            }
        }
    }

    @Scheduled(cron = "0 0 9 * * ?")
    public void sendTrialOrderExcelToManagements() {
        // 获取前一天日期
        LocalDate yesterday = LocalDate.now().minusDays(1);

        // 查询前一天的试用订单
        QueryWrapper<TrialOrder> qw = new QueryWrapper<>();
        qw.lambda().between(TrialOrder::getCreateTime, yesterday.atStartOfDay(), yesterday.atTime(23, 59, 59));
        List<TrialOrder> trialOrders = trialOrderMapper.selectList(qw);

        String[] activeProfiles = environment.getActiveProfiles();
        boolean env = activeProfiles.length == 1 && Objects.equals(activeProfiles[0], "prod");
        if (!trialOrders.isEmpty() && env) {
            // 创建Excel工作簿
            try (Workbook workbook = new XSSFWorkbook()) {
                // 创建工作表
                Sheet sheet = workbook.createSheet("Trial Orders");
                // 创建标题行
                Row headerRow = sheet.createRow(0);
                headerRow.createCell(0).setCellValue("ID");
                headerRow.createCell(1).setCellValue("Title");
                headerRow.createCell(2).setCellValue("Surname");
                headerRow.createCell(3).setCellValue("Given Name");
                headerRow.createCell(4).setCellValue("Username");
                headerRow.createCell(5).setCellValue("Email");
                headerRow.createCell(6).setCellValue("Country");
                headerRow.createCell(7).setCellValue("Occupation");
                headerRow.createCell(8).setCellValue("Create Time");
                headerRow.createCell(9).setCellValue("Update Time");
                headerRow.createCell(10).setCellValue("Status");

                // 填充数据
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                int rowNum = 1;
                for (TrialOrder trialOrder : trialOrders) {
                    Row row = sheet.createRow(rowNum++);
                    row.createCell(0).setCellValue(trialOrder.getId());
                    row.createCell(1).setCellValue(trialOrder.getTitle());
                    row.createCell(2).setCellValue(trialOrder.getSurname());
                    row.createCell(3).setCellValue(trialOrder.getGivenName());
                    row.createCell(4).setCellValue(trialOrder.getUserName());
                    row.createCell(5).setCellValue(trialOrder.getEmail());
                    row.createCell(6).setCellValue(trialOrder.getCountry());
                    row.createCell(7).setCellValue(trialOrder.getOccupation());
                    row.createCell(8).setCellValue(trialOrder.getCreateTime().format(formatter));
                    row.createCell(9).setCellValue(trialOrder.getUpdateTime().format(formatter));
                    row.createCell(10).setCellValue(trialOrder.getStatus());
                }

                // 保存Excel文件
                String fileName = "trialOrder-" + yesterday.format(DateTimeFormatter.ofPattern("yyyyMMdd")) + ".xlsx";
                try (FileOutputStream fileOut = new FileOutputStream(fileName)) {
                    workbook.write(fileOut);
//                    SendEmailUtil.sendExcelEmail("1023316923@qq.com", null, Files.readAllBytes(Paths.get(fileName)), fileName);
                    SendEmailUtil.sendExcelEmail("calvinwong@aidlab.hk", null, Files.readAllBytes(Paths.get(fileName)), fileName);
                    SendEmailUtil.sendExcelEmail("kaicpang.pang@connect.polyu.hk", null, Files.readAllBytes(Paths.get(fileName)), fileName);
                    SendEmailUtil.sendExcelEmail("kimwong@code-create.com.hk", null, Files.readAllBytes(Paths.get(fileName)), fileName);
//                    SendEmailUtil.sendExcelEmail("ningning@code-create.com.hk", null, Files.readAllBytes(Paths.get(fileName)), fileName);
                    SendEmailUtil.sendExcelEmail("johnnyho@code-create.com.hk", null, Files.readAllBytes(Paths.get(fileName)), fileName);
//                    SendEmailUtil.sendExcelEmail("ringolau@code-create.com.hk", null, Files.readAllBytes(Paths.get(fileName)), fileName);
                    SendEmailUtil.sendExcelEmail("chelseayu@code-create.com.hk", null, Files.readAllBytes(Paths.get(fileName)), fileName);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }else if (env) {
//            SendEmailUtil.sendNoExcelEmail("1023316923@qq.com", null);
            SendEmailUtil.sendNoExcelEmail("calvinwong@aidlab.hk", null);
            SendEmailUtil.sendNoExcelEmail("kaicpang.pang@connect.polyu.hk", null);
            SendEmailUtil.sendNoExcelEmail("kimwong@code-create.com.hk", null);
//            SendEmailUtil.sendNoExcelEmail("ningning@code-create.com.hk", null);
            SendEmailUtil.sendNoExcelEmail("johnnyho@code-create.com.hk", null);
//            SendEmailUtil.sendNoExcelEmail("ringolau@code-create.com.hk", null);
            SendEmailUtil.sendNoExcelEmail("chelseayu@code-create.com.hk", null);
        }
    }

    @Resource
    private UserLikeGroupMapper userLikeGroupMapper;
    @Resource
    private UserLikeMapper userLikeMapper;
    @Resource
    private TDesignPythonOutfitMapper designPythonOutfitMapper;
    @Resource
    private TDesignPythonOutfitDetailMapper designPythonOutfitDetailMapper;
    @Resource
    private DesignItemMapper designItemMapper;
    @Resource
    private DesignItemDetailMapper designItemDetailMapper;

    @Resource
    private DesignItemDetailPrintMapper designItemDetailPrintMapper;

    @Resource
    private GenerateDetailMapper generateDetailMapper;

    @Resource
    private ToProductImageResultMapper toProductImageResultMapper;

    @Resource
    private ToProductImageRecordMapper toProductImageRecordMapper;

    @Resource
    private MinioUtil minioUtil;
    @Resource
    private UserLikeService userLikeService;
    public void clearMinio() {
        List<CollectionElement> collectionElements = collectionElementMapper.selectDeleteList();
        for (CollectionElement collectionElement : collectionElements) {
            String url = collectionElement.getUrl();
            if (StringUtils.isNotBlank(url)) {
                if (url.startsWith("aida-collection-element")) {
                    QueryWrapper<Library> lQw = new QueryWrapper<>();
                    lQw.lambda().eq(Library::getUrl, url);
                    List<Library> libraries = libraryMapper.selectList(lQw);
                    if (CollectionUtils.isEmpty(libraries)) {
                        if (!url.contains("/")) {
                            continue;
                        }
                        minioUtil.deleteObject(url);
                    }
                }
            }
//            collectionElementMapper.deleteById(collectionElement);
        }

//        List<Design> designList = designMapper.selectDeleteList();
//        designMapper.deleteBatchIds(designList);
//
//        List<Collection> collectionList = collectionMapper.selectDeleteList();
//        collectionMapper.deleteBatchIds(collectionList);

        // 获取当前所有history
        QueryWrapper<UserLikeGroup> userLikeGroupQueryWrapper = new QueryWrapper<>();
        List<UserLikeGroup> userLikeGroupList = userLikeGroupMapper.selectList(userLikeGroupQueryWrapper);
        Set<Long> userLikeGroupIdSet = userLikeGroupList.stream().map(UserLikeGroup::getId).collect(Collectors.toSet());
        QueryWrapper<UserLike> userLikeQueryWrapper = new QueryWrapper<>();
        userLikeQueryWrapper.lambda().in(UserLike::getUserLikeGroupId, userLikeGroupIdSet);
        // 所有喜欢的图片
        List<UserLike> userLikes = userLikeMapper.selectList(userLikeQueryWrapper);
        Set<Long> designOutfitIdSet = userLikes.stream().map(UserLike::getDesignOutfitId).collect(Collectors.toSet());
        QueryWrapper<TDesignPythonOutfit> designPythonOutfitQueryWrapper = new QueryWrapper<>();
        designPythonOutfitQueryWrapper.lambda().notIn(TDesignPythonOutfit::getId, designOutfitIdSet);
        List<TDesignPythonOutfit> tDesignPythonOutfits = designPythonOutfitMapper.selectList(designPythonOutfitQueryWrapper);
        int i = 0;
        int designPythonOutfitMapperDelete = 0;
        int designPythonOutfitDetailMapperDelete = 0;
        int designItemMapperDelete = 0;
        int designItemDetailPrintMapperDelete = 0;
        int designItemDetailMapperDelete = 0;
        for (TDesignPythonOutfit tDesignPythonOutfit : tDesignPythonOutfits) {
            String designUrl = tDesignPythonOutfit.getDesignUrl();
            if (StringUtils.isNotBlank(designUrl)) {
                minioUtil.deleteObject(designUrl);
                i ++;
            }
            QueryWrapper<TDesignPythonOutfitDetail> designPythonOutfitDetailQueryWrapper = new QueryWrapper<>();
            designPythonOutfitDetailQueryWrapper.lambda().eq(TDesignPythonOutfitDetail::getDesignPythonOutfitId, tDesignPythonOutfit.getId());
            List<TDesignPythonOutfitDetail> tDesignPythonOutfitDetails = designPythonOutfitDetailMapper.selectList(designPythonOutfitDetailQueryWrapper);
            for (TDesignPythonOutfitDetail tDesignPythonOutfitDetail : tDesignPythonOutfitDetails) {
                if (!tDesignPythonOutfitDetail.getImageCategory().equals("body")) {
                    if (StringUtils.isNotBlank(tDesignPythonOutfitDetail.getImageUrl())) {
                        minioUtil.deleteObject(tDesignPythonOutfitDetail.getImageUrl());
                        i ++;
                    }
                    if (StringUtils.isNotBlank(tDesignPythonOutfitDetail.getMaskUrl())) {
                        minioUtil.deleteObject(tDesignPythonOutfitDetail.getMaskUrl());
                        i ++;
                    }
                }
            }
            designPythonOutfitDetailMapperDelete += tDesignPythonOutfitDetails.size();
            if (!CollectionUtils.isEmpty(tDesignPythonOutfitDetails)) {
                designPythonOutfitDetailMapper.deleteBatchIds(tDesignPythonOutfitDetails);
            }
        }
        designPythonOutfitMapperDelete = tDesignPythonOutfits.size();
        if (!CollectionUtils.isEmpty(tDesignPythonOutfits)) {
            designPythonOutfitMapper.deleteBatchIds(tDesignPythonOutfits);
        }
        System.out.println("i");
        List<DesignItem> designItemIdList = designItemMapper.selectDeleteList();
//        for (DesignItem designItem : designItemIdList) {
//            QueryWrapper<DesignItemDetail> designItemDetailQueryWrapper = new QueryWrapper<>();
//            designItemDetailQueryWrapper.lambda().eq(DesignItemDetail::getDesignItemId, designItem.getId());
//            List<DesignItemDetail> designItemDetails = designItemDetailMapper.selectList(designItemDetailQueryWrapper);
//        }
//        QueryWrapper<DesignItem> designItemQueryWrapper = new QueryWrapper<>();
//        designItemQueryWrapper.lambda().in(DesignItem::getId,designItemIdList);
//        List<DesignItem> designItems = designItemMapper.selectList(designItemQueryWrapper);
        designItemMapperDelete = designItemIdList.size();
        for (DesignItem designItem : designItemIdList) {
            QueryWrapper<DesignItemDetail> designItemDetailQueryWrapper = new QueryWrapper<>();
            designItemDetailQueryWrapper.lambda().eq(DesignItemDetail::getDesignItemId, designItem.getId());
            List<DesignItemDetail> designItemDetails = designItemDetailMapper.selectList(designItemDetailQueryWrapper);
            for (DesignItemDetail designItemDetail : designItemDetails) {
                QueryWrapper<DesignItemDetailPrint> didpQw = new QueryWrapper<>();
                didpQw.lambda().eq(DesignItemDetailPrint::getDesignItemDetailId, designItemDetail.getId());
                List<DesignItemDetailPrint> designItemDetailPrintList = designItemDetailPrintMapper.selectList(didpQw);
                designItemDetailPrintMapperDelete += designItemDetailPrintList.size();
                if (!CollectionUtils.isEmpty(designItemDetailPrintList)) {
                    if (!CollectionUtils.isEmpty(designItemDetailPrintList)) {
                        designItemDetailPrintMapper.deleteBatchIds(designItemDetailPrintList);
                    }
                }
            }
            designItemDetailMapperDelete += designItemDetails.size();
            if (!CollectionUtils.isEmpty(designItemDetails)) {
                designItemDetailMapper.deleteBatchIds(designItemDetails);
            }
        }
        if (!CollectionUtils.isEmpty(designItemIdList)) {
            designItemMapper.deleteBatchIds(designItemIdList);
        }

        System.out.println(designPythonOutfitMapperDelete);
        System.out.println(designPythonOutfitDetailMapperDelete);
        System.out.println(designItemMapperDelete);
        System.out.println(designItemDetailPrintMapperDelete);
        System.out.println(designItemDetailMapperDelete);

        QueryWrapper<GenerateDetail> gdQw = new QueryWrapper<>();
        gdQw.lambda().eq(GenerateDetail::getIsLike, 0);
        List<GenerateDetail> generateDetails = generateDetailMapper.selectList(gdQw);
        for (GenerateDetail generateDetail : generateDetails) {
            String url = generateDetail.getUrl();
            if (StringUtils.isNotBlank(url)) {
                QueryWrapper<Library> lQw = new QueryWrapper<>();
                lQw.lambda().eq(Library::getUrl, url);
                List<Library> libraries = libraryMapper.selectList(lQw);
                if (CollectionUtils.isEmpty(libraries)) {
                    minioUtil.deleteObject(url);
                }
            }
        }
//
//        QueryWrapper<ToProductImageResult> tpirQw = new QueryWrapper<>();
//        tpirQw.lambda().eq(ToProductImageResult::getIsLike, 0);
//        List<ToProductImageResult> toProductImageResults = toProductImageResultMapper.selectList(tpirQw);
//        for (ToProductImageResult toProductImageResult : toProductImageResults) {
//            String url = toProductImageResult.getUrl();
//            if (StringUtils.isNotBlank(url)) {
//                minioUtil.deleteObject(url);
//            }
//        }
//        QueryWrapper<TDesignPythonOutfit> qw1 = new QueryWrapper<>();
//        qw1.lambda().eq(TDesignPythonOutfit::getIsDeleted, 1);
//        List<TDesignPythonOutfit> tDesignPythonOutfits = designPythonOutfitMapper.selectListDelete();
//        for (TDesignPythonOutfit tDesignPythonOutfit : tDesignPythonOutfits) {
//            String designUrl = tDesignPythonOutfit.getDesignUrl();
//            if (StringUtils.isNotBlank(designUrl)) {
//                System.out.println(minioUtil.doesObjectExist(designUrl));
//            }
//        }
//
////        QueryWrapper<TDesignPythonOutfitDetail> qw2 = new QueryWrapper<>();
////        qw2.lambda().eq(TDesignPythonOutfitDetail::getIsDeleted, 1);
//        List<TDesignPythonOutfitDetail> tDesignPythonOutfitDetails = designPythonOutfitDetailMapper.selectListDelete();
//        for (TDesignPythonOutfitDetail tDesignPythonOutfitDetail : tDesignPythonOutfitDetails) {
//            if (!tDesignPythonOutfitDetail.getImageCategory().equals("body")) {
//                if (StringUtils.isNotBlank(tDesignPythonOutfitDetail.getImageUrl())) {
//                    System.out.println(minioUtil.doesObjectExist(tDesignPythonOutfitDetail.getImageUrl()));
//                }
//                if (StringUtils.isNotBlank(tDesignPythonOutfitDetail.getMaskUrl())) {
//                    System.out.println(minioUtil.doesObjectExist(tDesignPythonOutfitDetail.getMaskUrl()));;
//                }
//            }
//        }
//        String preSignedUrl = minioUtil.getPreSignedUrl("aida-clothing/image/image_1698374859.3031476.png", 10000);
//        System.out.println(preSignedUrl);
    }

    @Resource
    private AttributeRetrievalMapper attributeRetrievalMapper;

    public void addSystemFileStyle() {
//        ExecutorService executorService = Executors.newFixedThreadPool(5);

//        try {
//            String[] filePaths = {
//                    "C:\\Users\\10233\\Downloads\\OneDrive_1_2024-10-3\\Mens bottom style output.xlsx",
//                    "C:\\Users\\10233\\Downloads\\OneDrive_1_2024-10-3\\Mens outer style output.xlsx",
//                    "C:\\Users\\10233\\Downloads\\OneDrive_1_2024-10-3\\Mens top style output.xlsx"
////                    "/workspace/shb/Mens_bottom_style_output.xlsx",
////                    "/workspace/shb/Mens_outer_style_output.xlsx",
////                    "/workspace/shb/Mens_top_style_output.xlsx"
//            };
//
//            for (String filePath : filePaths) {
////                executorService.submit(() -> processExcelFile(filePath));
//                processExcelFile(filePath);
//            }
//        }catch (Exception e) {
//
//        }
//        } finally {
//            executorService.shutdown();
//            try {
//                if (!executorService.awaitTermination(60, TimeUnit.MINUTES)) {
//                    executorService.shutdownNow();
//                }
//            } catch (InterruptedException e) {
//                executorService.shutdownNow();
//            }
//        }
        String[] filePaths = {
                "C:\\Users\\10233\\Downloads\\OneDrive_1_2024-10-3\\Mens bottom style output.xlsx",
                "C:\\Users\\10233\\Downloads\\OneDrive_1_2024-10-3\\Mens outer style output.xlsx",
                "C:\\Users\\10233\\Downloads\\OneDrive_1_2024-10-3\\Mens top style output.xlsx"
//                    "/workspace/shb/Mens_bottom_style_output.xlsx",
//                    "/workspace/shb/Mens_outer_style_output.xlsx",
//                    "/workspace/shb/Mens_top_style_output.xlsx"
        };

        for (String filePath : filePaths) {
//                executorService.submit(() -> processExcelFile(filePath));
            processExcelFile(filePath);
        }
    }

    private void processExcelFile(String filePath) {
        System.out.println("线程开始");
        try {
            List<List<String>> excelData = ExcelReader.readExcel(filePath);
            String tableName = getTableNameFromFilePath(filePath);
            String prefix = getPrefixFromFilePath(filePath);

            for (List<String> columnData : excelData) {
                String style = columnData.get(0);
                for (int i = 1; i < columnData.size(); i++) {
                    String fileName = columnData.get(i);
                    if (StringUtils.isBlank(fileName)) {
                        continue;
                    }
                    if ("X".equals(style)) {
                        attributeRetrievalMapper.updateStyleByFileName("X", prefix + fileName, tableName);
                        System.out.println(fileName);
                    } else {
//                        if (style.equals("Y2K 风")) {
//                            StyleEnum.COUNTRY_STYLE
//                        }else if (style.equals("")) {
//
//                        }else if (style.equals("")) {
//
//                        }else if (style.equals("")) {
//
//                        }else if (style.equals("")) {
//
//                        }else if (style.equals("")) {
//
//                        }else if (style.equals("")) {
//
//                        }else if (style.equals("")) {
//
//                        }else if (style.equals("")) {
//
//                        }else if (style.equals("")) {
//
//                        }else if (style.equals("")) {
//
//                        }else if (style.equals("")) {
//
//                        }else if (style.equals("")) {
//
//                        }else if (style.equals("")) {
//
//                        }else if (style.equals("")) {
//
//                        }
                        attributeRetrievalMapper.updateStyleByFileName(style, prefix + fileName, tableName);
                        System.out.println(fileName);
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private String getTableNameFromFilePath(String filePath) {
        if (filePath.contains("Blouse")) {
            return "female_top";
        } else if (filePath.contains("Dress")) {
            return "female_dress";
        } else if (filePath.contains("Outerwear")) {
            return "female_outwear";
        } else if (filePath.contains("Skirt")) {
            return "female_skirt";
        } else if (filePath.contains("Trousers")) {
            return "female_pants";
        } else if (filePath.contains("bottom")) {
            return "male_bottom";
        } else if (filePath.contains("outer")) {
            return "male_outwear";
        } else if (filePath.contains("top")) {
            return "male_top";
        }
        return "";
    }

    private String getPrefixFromFilePath(String filePath) {
        if (filePath.contains("Blouse")) {
            return "blouse/";
        } else if (filePath.contains("Dress")) {
            return "dress/";
        } else if (filePath.contains("Outerwear")) {
            return "outwear/";
        } else if (filePath.contains("Skirt")) {
            return "skirt/";
        } else if (filePath.contains("Trousers")) {
            return "trousers/";
        } else if (filePath.contains("bottom")) {
            return "bottom/";
        } else if (filePath.contains("outer")) {
            return "outer/";
        } else if (filePath.contains("top")) {
            return "top/";
        }
        return "";
    }

//    public static List<String> getFileNames(String directoryPath) {
//        List<String> fileNames = new ArrayList<>();
//        Path path = Paths.get(directoryPath);
//
//        try (DirectoryStream<Path> stream = Files.newDirectoryStream(path)) {
//            for (Path entry : stream) {
//                if (Files.isRegularFile(entry)) {
//                    fileNames.add(entry.getFileName().toString());
//                }
//            }
//        } catch (IOException e) {
//            System.err.println("Error reading directory: " + e.getMessage());
//        }
//
//        return fileNames;
//    }

    @Resource
    private UserPreferenceLogMapper userPreferenceLogMapper;

    @Resource
    private UserPreferenceLogPredictionMapper userPreferenceLogPredictionMapper;

    public void createLikeSketchData() {
        List<UserLikeGroup> userLikeGroups = userLikeGroupMapper.getMoreThan50UserLikeAccount();
        List<Long> accountIdList = userLikeGroups.stream().map(UserLikeGroup::getAccountId).collect(Collectors.toList());

//        List<Long> accountIdList = new ArrayList<>();
//        accountIdList.add(4L);

        for (Long accountId : accountIdList) {
            QueryWrapper<UserLikeGroup> userLikeQw = new QueryWrapper<>();
            userLikeQw.lambda().eq(UserLikeGroup::getAccountId, accountId);
            userLikeQw.lambda().orderByDesc(UserLikeGroup::getCreateDate);
            List<UserLikeGroup> userLikeGroups1 = userLikeGroupMapper.selectList(userLikeQw);

            // 总集合
            List<UserLike> allUserLikes = new ArrayList<>();

            // 将所有 UserLike 收集到一个集合中
            for (UserLikeGroup likeGroup : userLikeGroups1) {
                QueryWrapper<UserLike> userLikeQueryWrapper = new QueryWrapper<>();
                userLikeQueryWrapper.lambda().eq(UserLike::getUserLikeGroupId, likeGroup.getId());
                List<UserLike> userLikes = userLikeMapper.selectList(userLikeQueryWrapper);
                allUserLikes.addAll(userLikes);
            }

//            // 根据时间排序
//            allUserLikes.sort(Comparator.comparing(UserLike::getCreateDate));
//
//            // 计算 80% 和 20% 的分割
//            int totalLikesSize = allUserLikes.size();
//            int splitIndexLikes = (int) Math.ceil(totalLikesSize * 0.8);
//
//            // 分割用户喜欢的集合
//            List<UserLike> first80PercentLikes = allUserLikes.subList(0, splitIndexLikes);
//            List<UserLike> last20PercentLikes = allUserLikes.subList(splitIndexLikes, totalLikesSize);

            // 分别处理前 80% 和后 20% 的数据

            // 处理前 80%
            for (UserLike userLike : allUserLikes) {
                Long designItemId = userLike.getDesignItemId();
                QueryWrapper<DesignItemDetail> designItemDetailQueryWrapper = new QueryWrapper<>();
                designItemDetailQueryWrapper.lambda().eq(DesignItemDetail::getDesignItemId, designItemId);
                List<DesignItemDetail> designItemDetails = designItemDetailMapper.selectList(designItemDetailQueryWrapper);
                for (DesignItemDetail designItemDetail : designItemDetails) {
                    if (designItemDetail.getType().equals("Body") || !designItemDetail.getPath().contains("aida-sys-image")) {
                        continue;
                    }
                    UserPreferenceLogTest userPreferenceLogTest = new UserPreferenceLogTest();
                    userPreferenceLogTest.setPath(designItemDetail.getPath());
                    userPreferenceLogTest.setAccountId(accountId);
                    userPreferenceLogTest.setUserLikeGroupId(userLike.getUserLikeGroupId());
                    userPreferenceLogTest.setDataTime(designItemDetail.getCreateDate().toInstant()
                            .atZone(ZoneId.systemDefault())
                            .toLocalDateTime());
                    userPreferenceLogMapper.insert(userPreferenceLogTest);
                }
            }

            // 处理后 20%
//            if (last20PercentLikes.size() == 0) {
//                // 输出没有记录的用户 ID
//                log.info("用户 ID: " + accountId + " 在后 20% 的 userLike 列表为空");
//            }
//
//            for (UserLike userLike : last20PercentLikes) {
//                Long designItemId = userLike.getDesignItemId();
//                QueryWrapper<DesignItemDetail> designItemDetailQueryWrapper = new QueryWrapper<>();
//                designItemDetailQueryWrapper.lambda().eq(DesignItemDetail::getDesignItemId, designItemId);
//                List<DesignItemDetail> designItemDetails = designItemDetailMapper.selectList(designItemDetailQueryWrapper);
//                for (DesignItemDetail designItemDetail : designItemDetails) {
//
//                    if (designItemDetail.getType().equals("Body") || !designItemDetail.getPath().contains("aida-sys-image")) {
//                        continue;
//                    }
//
//                    UserPreferenceLogPrediction userPreferenceLogPrediction = new UserPreferenceLogPrediction();
//                    userPreferenceLogPrediction.setPath(designItemDetail.getPath());
//                    userPreferenceLogPrediction.setAccountId(accountId);
//                    userPreferenceLogPrediction.setUserLikeGroupId(userLike.getUserLikeGroupId());
//                    userPreferenceLogPrediction.setDataTime(designItemDetail.getCreateDate().toInstant()
//                            .atZone(ZoneId.systemDefault())
//                            .toLocalDateTime());
//                    userPreferenceLogPredictionMapper.insert(userPreferenceLogPrediction);
//                }
//            }
        }
    }

    @Resource
    private CollectionMapper collectionMapper;

    @Resource
    private CollectionElementMapper collectionElementMapper;
    @Resource
    private CollectionElementRelModelMapper collectionElementRelModelMapper;

    @Resource
    private CollectionElementService collectionElementService;

    @Resource
    private PythonService pythonService;

    @Resource
    private SysFileMapper sysFileMapper;
    @Resource
    private LibraryMapper libraryMapper;


    public List<UserLikeGroup> getTop20Percent(List<UserLikeGroup> userLikeGroups) {
        // 检查列表是否为空
        if (userLikeGroups == null || userLikeGroups.isEmpty()) {
            return new ArrayList<>(); // 返回空列表
        }

        // 计算需要取的记录数量
        int size = userLikeGroups.size();
        int topCount = (int) Math.ceil(size * 0.2); // 取 20%，向上取整

        // 返回前 20% 的记录
        return userLikeGroups.stream()
                .limit(topCount)
                .collect(Collectors.toList());
    }
    public double freqAddTest() {
//        List<UserLikeGroup> userLikeGroups = userLikeGroupMapper.getMoreThan50UserLikeAccount();
//        List<Long> accountIdList = userLikeGroups.stream().map(UserLikeGroup::getAccountId).collect(Collectors.toList());
        long totalAssemblyTime = 0L; // 总耗时（毫秒）
        int assemblyCount = 0; // 组装次数

        List<Long> accountIdList = new ArrayList<>();
        accountIdList.add(4L);

        for (Long accountId : accountIdList) {
            QueryWrapper<UserLikeGroup> qw = new QueryWrapper<>();
            qw.lambda().eq(UserLikeGroup::getAccountId, accountId);
            qw.lambda().orderByDesc(UserLikeGroup::getCreateDate);
            List<UserLikeGroup> userLikeGroups1 = userLikeGroupMapper.selectList(qw);

            // 取前 20%
            List<UserLikeGroup> top20Percent = getTop20Percent(userLikeGroups1);
            List<Long> collectionIdList = top20Percent.stream().map(UserLikeGroup::getCollectionId).collect(Collectors.toList());
            // size 51
            for (Long collectionId : collectionIdList) {
                QueryWrapper<Design> designQueryWrapper = new QueryWrapper<>();
                designQueryWrapper.lambda().eq(Design::getCollectionId, collectionId);
                Design design = designMapper.selectList(designQueryWrapper).get(0);

                Collection collection = collectionMapper.selectById(collectionId);

                QueryWrapper<CollectionElement> elementQueryWrapper = new QueryWrapper<>();
                elementQueryWrapper.lambda().eq(CollectionElement::getCollectionId, collectionId);
                List<CollectionElement> collectionElements = collectionElementMapper.selectList(elementQueryWrapper);

                List<CollectionElement> sketchboard = collectionElements.stream().filter(o -> o.equals("Sketchboard")).collect(Collectors.toList());

                if (design.getSingleOverall().equals("single")) {
                    continue;
                }

                DesignCollectionDTO designCollectionDTO = new DesignCollectionDTO();
                designCollectionDTO.setSketchBoards(CopyUtil.copyList(sketchboard, CollectionSketchDTO.class));
                designCollectionDTO.setSystemScale(design.getSystemScale());
                designCollectionDTO.setTemplateId(design.getTemplateId());
                designCollectionDTO.setModelType(design.getModelType());
                designCollectionDTO.setSingleOverall(design.getSingleOverall());
                designCollectionDTO.setTimeZone(new Date().toString());
                designCollectionDTO.setDesignNum(8);

                Long templateId = design.getTemplateId();
                String modelType = design.getModelType();
                if (modelType.equals("System")) {
                    SysFile sysFile = sysFileMapper.selectById(templateId);
                    designCollectionDTO.setModelSex(sysFile.getLevel2Type());
                } else {
                    Library library = libraryMapper.selectById(templateId);
                    if (Objects.isNull(library)) {
                        designCollectionDTO.setModelSex("Female");
                    } else {
                        designCollectionDTO.setModelSex(library.getLevel2Type());
                    }
                }

                ValidateElementVO elementVO = collectionElementService.validateElement(designCollectionDTO);
                elementVO.setAccountId(accountId);

                // 记录开始时间
                long startTime = System.currentTimeMillis();
                log.info("组装开始时间：" + new Date(startTime).toString());

//                pythonService.covertDesignParamTest(
//                        designCollectionDTO.getSystemScale(),
//                        designCollectionDTO.getSingleOverall(),
//                        designCollectionDTO.getSwitchCategory(),
//                        elementVO,
//                        "testProcessId",
//                        null,
//                        collectionId
//                );

                // 记录结束时间
                long endTime = System.currentTimeMillis();
                log.info("组装结束时间：" + new Date(endTime).toString());

                // 累加组装耗时
                totalAssemblyTime += (endTime - startTime);
                assemblyCount++;
            }
        }

        // 计算平均组装时间
        if (assemblyCount > 0) {
            double averageAssemblyTimeInSeconds = totalAssemblyTime / (double) assemblyCount / 1000.0;
            log.info("平均组装时间：{} 秒", averageAssemblyTimeInSeconds);
            return averageAssemblyTimeInSeconds;
        } else {
            log.info("没有执行任何组装操作。");
            return 0.0;
        }
    }

//    public void statisticalCoincidenceDegree() {
//        // 创建工作簿和表格
//        Workbook workbook = new XSSFWorkbook();
//        Sheet sheet = workbook.createSheet("用户数据");
//
//        // 创建表头
//        Row headerRow = sheet.createRow(0);
//        headerRow.createCell(0).setCellValue("用户 ID");
//        headerRow.createCell(1).setCellValue("Test 匹配路径数量");
//        headerRow.createCell(2).setCellValue("Prediction 总路径数量");
//        headerRow.createCell(3).setCellValue("重合度");
//
//        // 假设 userLikeGroupMapper 和其他映射器已经定义并初始化
//        List<UserLikeGroup> userLikeGroups = userLikeGroupMapper.getMoreThan50UserLikeAccount();
//        List<Long> accountIdList = userLikeGroups.stream().map(UserLikeGroup::getAccountId).collect(Collectors.toList());
//
//        int rowIndex = 1; // 从第二行开始插入数据
//        for (Long accountId : accountIdList) {
//            QueryWrapper<UserPreferenceLogTest> qw1 = new QueryWrapper<>();
//            qw1.lambda().eq(UserPreferenceLogTest::getAccountId, accountId);
//            List<UserPreferenceLogTest> testList = userPreferenceLogMapper.selectList(qw1);
//
//            QueryWrapper<UserPreferenceLogPrediction> qw2 = new QueryWrapper<>();
//            qw2.lambda().eq(UserPreferenceLogPrediction::getAccountId, accountId);
//            List<UserPreferenceLogPrediction> predictionList = userPreferenceLogPredictionMapper.selectList(qw2);
//
//            // 将 testPaths 和 predictionPaths 转为 Set 来计算重合度
//            Set<String> testPaths = testList.stream()
//                    .map(UserPreferenceLogTest::getPath)
//                    .collect(Collectors.toSet());
//
//            Set<String> predictionPaths = predictionList.stream()
//                    .map(UserPreferenceLogPrediction::getPath)
//                    .collect(Collectors.toSet());
//
//            // 计算匹配的路径数量（重合部分）
//            Set<String> intersection = new HashSet<>(testPaths);
//            intersection.retainAll(predictionPaths); // 计算交集
//
//            // 计算重合度
//            double overlapRatio = (double) intersection.size() / predictionPaths.size();
//
//            // 将结果写入 Excel 文件
//            Row row = sheet.createRow(rowIndex++);
//            row.createCell(0).setCellValue(accountId);
//            row.createCell(1).setCellValue(intersection.size()); // 匹配路径数量
//            row.createCell(2).setCellValue(predictionPaths.size()); // Prediction 总路径数量
//            row.createCell(3).setCellValue(overlapRatio); // 重合度
//
//            // 输出到日志
//            log.info("用户 ID: " + accountId);
//            log.info("Test 匹配路径数量: " + intersection.size());
//            log.info("Prediction 总路径数量: " + predictionPaths.size());
//            log.info("重合度: " + overlapRatio);
//        }
//
//        // 自动调整列宽
//        for (int i = 0; i < 4; i++) {
//            sheet.autoSizeColumn(i);
//        }
//
//        // 写入 Excel 文件
//        try (FileOutputStream fileOut = new FileOutputStream("用户数据.xlsx")) {
//            workbook.write(fileOut);
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
//
//        System.out.println("Excel 文件已成功生成!");
//    }

    @Resource
    private SketchDataMapper sketchDataMapper;

    public void runMetricsComparison() {
        Long accountId = 13765L;
        Map<String, Map<String, Double>> metricsComparison = calculateMetricsComparison(accountId);

        System.out.println("Old Algorithm Metrics: " + metricsComparison.get("OldAlgorithm"));
        System.out.println("New Algorithm Metrics: " + metricsComparison.get("NewAlgorithm"));
    }

    public Map<String, Map<String, Double>> calculateMetricsComparison(Long accountId) {
        // 定义结果存储
        Map<String, Map<String, Double>> comparisonMetrics = new HashMap<>();

        // 分别计算新旧算法的指标
        Map<String, Double> oldAlgorithmMetrics = calculateMetricsForType(accountId, 1); // 旧算法
        Map<String, Double> newAlgorithmMetrics = calculateMetricsForType(accountId, 2); // 新算法

        // 存入对比结果
        comparisonMetrics.put("OldAlgorithm", oldAlgorithmMetrics);
        comparisonMetrics.put("NewAlgorithm", newAlgorithmMetrics);

        return comparisonMetrics;
    }

    private Map<String, Double> calculateMetricsForType(Long accountId, int type) {
        // 查询指定算法类型的预测池 Sketch 列表
        List<String> predictionPaths = sketchDataMapper.selectList(
                new QueryWrapper<SketchData>()
                        .lambda()
                        .eq(SketchData::getAccountId, accountId)
                        .eq(SketchData::getType, type)
        ).stream().map(SketchData::getPath).collect(Collectors.toList());

        if (CollectionUtils.isEmpty(predictionPaths)) {
            throw new IllegalArgumentException("算法类型 " + type + " 的预测池为空，无法计算指标");
        }

        // 查询用户喜欢的 Sketch 列表
        Set<String> likedPaths = userPreferenceLogPredictionMapper.selectList(
                new QueryWrapper<UserPreferenceLogPrediction>()
                        .lambda()
                        .eq(UserPreferenceLogPrediction::getAccountId, accountId)
        ).stream().map(UserPreferenceLogPrediction::getPath).collect(Collectors.toSet());

        if (CollectionUtils.isEmpty(likedPaths)) {
            throw new IllegalArgumentException("用户喜欢的列表为空，无法计算指标");
        }

        // 计算预测池中用户喜欢的 Sketch 数量
        long likedInPrediction = predictionPaths.stream()
                .filter(likedPaths::contains)
                .count();

//        // 计算 Precision 和 Recall
//        double precision = (double) likedInPrediction / predictionPaths.size();
//        double recall = (double) likedInPrediction / likedPaths.size();
//
//        // 计算 F1 Score
//        double f1Score = (precision + recall > 0)
//                ? 2 * precision * recall / (precision + recall)
//                : 0;

        // 计算 Hit Ratio (HR)
        double hitRatio = (double) likedInPrediction / likedPaths.size();

        // 返回结果
        Map<String, Double> metrics = new HashMap<>();
//        metrics.put("precision", precision);
//        metrics.put("recall", recall);
//        metrics.put("f1Score", f1Score);
        metrics.put("hitRatio", hitRatio);
        return metrics;
    }

    public Map<String, Double> calculateMetrics(Long accountId, Long collectionId) {
        // 查询预测池 Sketch 列表
        List<String> predictionPaths = sketchDataMapper.selectList(
                new QueryWrapper<SketchData>()
                        .lambda()
                        .eq(SketchData::getAccountId, accountId)
                        .eq(SketchData::getCollectionId, collectionId)
                        .eq(SketchData::getType, 2) // 2: 新算法
        ).stream().map(SketchData::getPath).collect(Collectors.toList());

        if (CollectionUtils.isEmpty(predictionPaths)) {
            throw new IllegalArgumentException("预测池为空，无法计算指标");
        }

        // 查询用户喜欢的 Sketch 列表
        List<String> likedPaths = userPreferenceLogPredictionMapper.selectList(
                new QueryWrapper<UserPreferenceLogPrediction>()
                        .lambda()
                        .eq(UserPreferenceLogPrediction::getAccountId, accountId)
        ).stream().map(UserPreferenceLogPrediction::getPath).collect(Collectors.toList());

        if (CollectionUtils.isEmpty(likedPaths)) {
            throw new IllegalArgumentException("用户喜欢的列表为空，无法计算指标");
        }

        // 计算预测池中用户喜欢的 Sketch 数量
        long likedInPrediction = predictionPaths.stream()
                .filter(likedPaths::contains)
                .count();

        // 计算 Precision 和 Recall
        double precision = (double) likedInPrediction / predictionPaths.size();
        double recall = (double) likedInPrediction / likedPaths.size();

        // 返回结果
        Map<String, Double> metrics = new HashMap<>();
        metrics.put("precision", precision);
        metrics.put("recall", recall);
        return metrics;
    }

    @Resource
    private RedisUtil redisUtil;

    private void runComparisonAndRecordResults(int iterations) {
        // 创建工作簿和表格
        Workbook workbook = new XSSFWorkbook();
        Sheet sheet = workbook.createSheet("Metrics Data");

        // 创建表头
        Row headerRow = sheet.createRow(0);
        headerRow.createCell(0).setCellValue("Iteration");
        headerRow.createCell(1).setCellValue("Algorithm Sketch Num");
        headerRow.createCell(2).setCellValue("Old Algorithm HitRatio");
        headerRow.createCell(3).setCellValue("New Algorithm HitRatio");
        headerRow.createCell(4).setCellValue("Average Assembly Time (s)");
        headerRow.createCell(5).setCellValue("确定第一件sketch时间 (s)");  // 第一部分时间
        headerRow.createCell(6).setCellValue("获取特征值时间 (s)");  // 第二部分时间
        headerRow.createCell(7).setCellValue("搭配另外sketch时间 (s)");  // 第三部分时间

        int rowIndex = 1; // 数据起始行

        for (int i = 1; i <= iterations; i++) {
            // 清除 sketch_data 表
            sketchDataMapper.delete(new QueryWrapper<>());

            // 获取平均组装时间
            double averageAssemblyTime = freqAddTest();

            // 动态获取用户的 collectionIds
            Long accountId = 4L; // 假设用户 ID 为 4
            List<Long> collectionIds = getCollectionIdsByAccount(accountId);

            if (CollectionUtils.isEmpty(collectionIds)) {
                log.warn("用户 {} 没有相关的 collectionId 数据，跳过当前迭代", accountId);
                continue;
            }

            // 记录每次迭代的命中率和总时间
            double totalOldHitRatio = 0.0;
            double totalNewHitRatio = 0.0;

//            List<Long> collectionIds = getCollectionIdsByAccount(4L);

            for (Long collectionId : collectionIds) {
                Map<Integer, Double> hitRatios = calculateHitRatioByType(accountId, collectionId);
                totalOldHitRatio += hitRatios.getOrDefault(1, 0.0); // type=1 的命中率
                totalNewHitRatio += hitRatios.getOrDefault(2, 0.0); // type=2 的命中率
            }

            // 计算平均命中率
            double averageOldHitRatio = totalOldHitRatio / collectionIds.size();
            double averageNewHitRatio = totalNewHitRatio / collectionIds.size();

            // 获取 Sketch 数量
            Long newAlgorithmSketchNum = sketchDataMapper.selectCount(
                    new QueryWrapper<SketchData>().lambda().eq(SketchData::getType, 2)
            );

            // 从 Redis 获取三部分的耗时（秒）
            double part1Time = redisUtil.getFirstSketchTime() / collectionIds.size();  // 第一部分：Sketch 耗时
            double part2Time = redisUtil.getGetAttributeRecognitionTime() / collectionIds.size();  // 第二部分：特征值获取耗时
            double part3Time = redisUtil.getOtherSketchTime() / collectionIds.size();  // 第三部分：搭配 Sketch 耗时

            // 记录数据到 Excel 表格
            Row row = sheet.createRow(rowIndex++);
            row.createCell(0).setCellValue(i);
            row.createCell(1).setCellValue(newAlgorithmSketchNum);
            row.createCell(2).setCellValue(averageOldHitRatio); // 旧算法命中率
            row.createCell(3).setCellValue(averageNewHitRatio); // 新算法命中率
            row.createCell(4).setCellValue(averageAssemblyTime); // 平均组装时间
            row.createCell(5).setCellValue(part1Time); // 第一部分耗时
            row.createCell(6).setCellValue(part2Time); // 第二部分耗时
            row.createCell(7).setCellValue(part3Time); // 第三部分耗时

            log.info("Iteration {}: Old Algorithm Avg HitRatio = {}, New Algorithm Avg HitRatio = {}, New Sketch Num = {}, Average Assembly Time = {} s, " +
                            "Part 1 Time = {} s, Part 2 Time = {} s, Part 3 Time = {} s",
                    i, averageOldHitRatio, averageNewHitRatio, newAlgorithmSketchNum, averageAssemblyTime, part1Time, part2Time, part3Time);

            // 清除 Redis 缓存
            redisUtil.clearTaskElapsedTimeCache();
        }

        // 写入 Excel 文件
        try (FileOutputStream fileOut = new FileOutputStream("metrics_data.xlsx")) {
            workbook.write(fileOut);
            log.info("Excel 文件已成功生成: metrics_data.xlsx");
        } catch (IOException e) {
            log.error("写入 Excel 文件失败", e);
        }
    }

    public Map<Integer, Double> calculateHitRatioByType(Long accountId, Long collectionId) {
        // 存储 type=1 和 type=2 的命中率
        Map<Integer, Double> hitRatios = new HashMap<>();

        // 获取用户 likedSketch 列表
        Set<String> likedPaths = userPreferenceLogPredictionMapper.selectList(
                new QueryWrapper<UserPreferenceLogPrediction>()
                        .lambda()
                        .eq(UserPreferenceLogPrediction::getAccountId, accountId)
        ).stream().map(UserPreferenceLogPrediction::getPath).collect(Collectors.toSet());

        if (CollectionUtils.isEmpty(likedPaths)) {
            throw new IllegalArgumentException("用户喜欢的列表为空，无法计算命中率");
        }

        // 遍历 type=1 和 type=2
        for (int type : Arrays.asList(1, 2)) {
            // 查询当前类型的预测池数据
            List<String> predictionPaths = sketchDataMapper.selectList(
                    new QueryWrapper<SketchData>()
                            .lambda()
                            .eq(SketchData::getAccountId, accountId)
                            .eq(SketchData::getCollectionId, collectionId)
                            .eq(SketchData::getType, type)
            ).stream().map(SketchData::getPath).collect(Collectors.toList());

            if (CollectionUtils.isEmpty(predictionPaths)) {
                log.warn("类型 {} 的 collectionId {} 的预测池为空，命中率设置为 0", type, collectionId);
                hitRatios.put(type, 0.0);
                continue;
            }

            // 计算命中数量
            long likedInPrediction = predictionPaths.stream()
                    .filter(likedPaths::contains)
                    .count();

            // 计算命中率
            double hitRatio = (double) likedInPrediction / predictionPaths.size();
            hitRatios.put(type, hitRatio);
        }

        return hitRatios;
    }


//    private double getAverageAssemblyTime() {
//        // 假设 freqAddTest 中已经累加了总组装时间和次数
//        // 替换为实际的获取平均组装时间的逻辑
//        return totalAssemblyTime / (double) assemblyCount / 1000.0; // 转换为秒
//    }

    public double calculateSingleDesignHitRatio(Long accountId, int type) {
        // 查询指定算法类型的预测池 Sketch 列表
        List<String> predictionPaths = sketchDataMapper.selectList(
                new QueryWrapper<SketchData>()
                        .lambda()
                        .eq(SketchData::getAccountId, accountId)
                        .eq(SketchData::getType, type) // type: 1 旧算法，2 新算法
        ).stream().map(SketchData::getPath).collect(Collectors.toList());

        if (CollectionUtils.isEmpty(predictionPaths)) {
            throw new IllegalArgumentException("预测池为空，无法计算指标");
        }

        // 查询用户喜欢的 Sketch 列表
        Set<String> likedPaths = userPreferenceLogPredictionMapper.selectList(
                new QueryWrapper<UserPreferenceLogPrediction>()
                        .lambda()
                        .eq(UserPreferenceLogPrediction::getAccountId, accountId)
        ).stream().map(UserPreferenceLogPrediction::getPath).collect(Collectors.toSet());

        if (CollectionUtils.isEmpty(likedPaths)) {
            throw new IllegalArgumentException("用户喜欢的列表为空，无法计算指标");
        }

        // 计算预测池中用户喜欢的 Sketch 数量
        long likedInPrediction = predictionPaths.stream()
                .filter(likedPaths::contains)
                .count();

        // 计算 Hit Ratio (HR)
        return (double) likedInPrediction / likedPaths.size();
    }

    public Map<Integer, Double> calculateAverageHitRatio(Long accountId, List<Long> collectionIds) {
        // 存储新旧算法的平均命中率
        Map<Integer, Double> averageHitRatios = new HashMap<>();
        Map<Integer, List<Double>> hitRatiosByType = new HashMap<>();

        // 初始化列表存储每个 collection 的命中率
        hitRatiosByType.put(1, new ArrayList<>()); // type=1
        hitRatiosByType.put(2, new ArrayList<>()); // type=2

        // 获取用户 likedSketch 列表
        Set<String> likedPaths = userPreferenceLogPredictionMapper.selectList(
                new QueryWrapper<UserPreferenceLogPrediction>()
                        .lambda()
                        .eq(UserPreferenceLogPrediction::getAccountId, accountId)
        ).stream().map(UserPreferenceLogPrediction::getPath).collect(Collectors.toSet());

        if (CollectionUtils.isEmpty(likedPaths)) {
            throw new IllegalArgumentException("用户喜欢的列表为空，无法计算命中率");
        }

        // 遍历每个 collectionId
        for (Long collectionId : collectionIds) {
            // 遍历 type=1 和 type=2
            for (int type : Arrays.asList(1, 2)) {
                // 获取当前类型的生成数据
                List<String> predictionPaths = sketchDataMapper.selectList(
                        new QueryWrapper<SketchData>()
                                .lambda()
                                .eq(SketchData::getAccountId, accountId)
                                .eq(SketchData::getCollectionId, collectionId)
                                .eq(SketchData::getType, type)
                ).stream().map(SketchData::getPath).collect(Collectors.toList());

                if (CollectionUtils.isEmpty(predictionPaths)) {
                    log.warn("类型 {} 的 collectionId {} 的预测池为空，跳过计算", type, collectionId);
                    continue;
                }

                // 计算命中数量
                long likedInPrediction = predictionPaths.stream()
                        .filter(likedPaths::contains)
                        .count();

                // 计算命中率
                double hitRatio = (double) likedInPrediction / predictionPaths.size();
                hitRatiosByType.get(type).add(hitRatio); // 存储每个 collection 的命中率
            }
        }

        // 计算平均命中率
        hitRatiosByType.forEach((type, hitRatios) -> {
            double averageHitRatio = hitRatios.stream().mapToDouble(Double::doubleValue).average().orElse(0.0);
            averageHitRatios.put(type, averageHitRatio);
        });

        return averageHitRatios;
    }

    public void testAverageHitRatio(Long accountId) {

        // 动态获取 collectionId 列表
        List<Long> collectionIds = getCollectionIdsByAccount(accountId);

        if (CollectionUtils.isEmpty(collectionIds)) {
            log.warn("用户 {} 没有相关的 collectionId 数据", accountId);
            return;
        }

        // 计算平均命中率
        Map<Integer, Double> averageHitRatios = calculateAverageHitRatio(accountId, collectionIds);

        // 输出结果
        log.info("用户 {} 的平均命中率：{}", accountId, averageHitRatios);

        double ratioType1 = averageHitRatios.getOrDefault(1, 0.0);
        double ratioType2 = averageHitRatios.getOrDefault(2, 0.0);
        log.info("命中率对比：type=1 的平均命中率为 {:.2%}，type=2 的平均命中率为 {:.2%}", ratioType1, ratioType2);
    }

    public List<Long> getCollectionIdsByAccount(Long accountId) {
        // 查询该用户的所有 collectionId
        return sketchDataMapper.selectList(
                new QueryWrapper<SketchData>()
                        .lambda()
                        .eq(SketchData::getAccountId, accountId) // 筛选用户
                        .select(SketchData::getCollectionId) // 只查询 collectionId
        ).stream()
                .map(SketchData::getCollectionId)
                .distinct() // 去重，确保 collectionId 唯一
                .collect(Collectors.toList());
    }

    @Resource
    private RedisTemplate<String, String> redisTemplate;

    public void saveUserLikedSketchDataToRedis(Long userId) {
        // Redis 键前缀
        String redisKey = "user_liked_sketch:" + userId;
        // 1. 清除该用户相关的 Redis 缓存
        // 删除所有 sketch 的喜欢次数记录
        redisTemplate.delete(redisKey);

        // 删除最大喜欢次数的缓存
        redisTemplate.delete(redisKey + ":maxLikes");

        // 1. 查询用户喜欢的所有 sketch 数据
        QueryWrapper<UserPreferenceLogTest> qw = new QueryWrapper<>();
        qw.lambda().eq(UserPreferenceLogTest::getAccountId, userId);
        List<UserPreferenceLogTest> userPreferenceLogTests = userPreferenceLogMapper.selectList(qw);


        // 最大喜欢次数
        int maxLikes = 0;

        // 2. 遍历所有用户的喜欢记录，更新 Redis 中的喜欢次数
        for (UserPreferenceLogTest userPreferenceLogTest : userPreferenceLogTests) {
            String sketchPath = userPreferenceLogTest.getPath();

            // 使用 Redis HINCRBY 增加某个 sketch path 的喜欢次数
            Long newCount = redisTemplate.opsForHash().increment(redisKey, sketchPath, 1);

            // 更新最大喜欢次数
            maxLikes = Math.max(maxLikes, newCount.intValue());
        }

        // 3. 将最大喜欢次数存入 Redis
        redisTemplate.opsForValue().set(redisKey + ":maxLikes", String.valueOf(maxLikes));
    }

//    public void getAccountLikedNumRedis() {
//        String redisKey = "user_liked_sketch:" + 4L;
//
//        redisUtil
//
//        // 尝试从 Redis 获取该 sketch path 的喜欢次数
//        Integer likedCount = (Integer) redisTemplate.opsForHash().get(redisKey);
//    }

    public void saveDataToNumpyFormat() {
        Long accountId = 4L; // 目标用户 ID

        // 保存历史数据
        saveHistoryData(accountId);

        // 保存目标数据
        saveTargetData(accountId);
    }

    private void saveHistoryData(Long accountId) {
        // 查询用户历史喜欢的 Sketch 及其次数
        QueryWrapper<UserPreferenceLogTest> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(UserPreferenceLogTest::getAccountId, accountId)
                .groupBy(UserPreferenceLogTest::getPath);

        queryWrapper.select("path", "COUNT(*) AS count");

        List<Map<String, Object>> historyData = userPreferenceLogMapper.selectMaps(queryWrapper);

        // 将数据保存为文本文件
        try (FileWriter writer = new FileWriter("history_data.txt")) {
            for (Map<String, Object> row : historyData) {
                String path = (String) row.get("path");
                Long count = (Long) row.get("count");
                writer.write(path + "," + count + "\n");
            }
            System.out.println("历史数据已保存到 history_data.txt");
        } catch (IOException e) {
            System.err.println("保存历史数据时发生错误: " + e.getMessage());
        }
    }

    private void saveTargetData(Long accountId) {
        // 查询用户即将喜欢的 Sketch 集合
        QueryWrapper<UserPreferenceLogPrediction> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(UserPreferenceLogPrediction::getAccountId, accountId)
                .groupBy(UserPreferenceLogPrediction::getPath);

        queryWrapper.select("path");

        List<Map<String, Object>> targetData = userPreferenceLogPredictionMapper.selectMaps(queryWrapper);

        // 将数据保存为文本文件
        try (FileWriter writer = new FileWriter("target_data.txt")) {
            for (Map<String, Object> row : targetData) {
                String path = (String) row.get("path");
                writer.write(path + "\n");
            }
            System.out.println("目标数据已保存到 target_data.txt");
        } catch (IOException e) {
            System.err.println("保存目标数据时发生错误: " + e.getMessage());
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void projectDataCreate() {
        StopWatch stopWatch = new StopWatch("projectDataCreate");

        try {
            // UserLikeGroup转project
            stopWatch.start("userLikeGroupConvertProject");
            userLikeGroupConvertProject();
            stopWatch.stop();
            log.info("userLikeGroupConvertProject 执行完成，耗时: {} ms", stopWatch.getLastTaskTimeMillis());

            // 必须先完成project数据新增后再执行 toProductImage relight数据关联project
            stopWatch.start("toProductRelightRelationProject");
            toProductRelightRelationProject();
            stopWatch.stop();
            log.info("toProductRelightRelationProject 执行完成，耗时: {} ms", stopWatch.getLastTaskTimeMillis());

            // 画布数据
            stopWatch.start("canvasData");
            canvasData();
            stopWatch.stop();
            log.info("canvasData 执行完成，耗时: {} ms", stopWatch.getLastTaskTimeMillis());

            // 作品关联数据转json数据
            stopWatch.start("portfolioData");
            portfolioData();
            stopWatch.stop();
            log.info("portfolioData 执行完成，耗时: {} ms", stopWatch.getLastTaskTimeMillis());

            // 添加喜欢的design到排序表
            stopWatch.start("userLikeAddToCollectionSort");
            userLikeAddToCollectionSort();
            stopWatch.stop();
            log.info("userLikeAddToCollectionSort 执行完成，耗时: {} ms", stopWatch.getLastTaskTimeMillis());

            // 打印总耗时
            log.info("项目数据创建总耗时: {} ms", stopWatch.getTotalTimeMillis());
            log.info("详细统计:\n{}", stopWatch.prettyPrint());

        } catch (Exception e) {
            log.error("projectDataCreate执行失败", e);
            throw e;
        }
    }

    public void portfolioData() {
        QueryWrapper<Portfolio> updateQueryWrapper = new QueryWrapper<>();
        updateQueryWrapper.lambda().eq(Portfolio::getOpenSource, 1);
        List<Portfolio> portfolioListUpdate = portfolioMapper.selectList(updateQueryWrapper);
        for (Portfolio portfolio : portfolioListUpdate) {
            Long userLikeGroupSourceId = portfolio.getUserLikeGroupSourceId();
            UserLikeGroup userLikeGroup = userLikeGroupMapper.selectById(userLikeGroupSourceId);
            if (Objects.nonNull(userLikeGroup)) {
                portfolio.setProjectId(userLikeGroup.getProjectId());
                portfolioMapper.updateById(portfolio);
            }else {
                // TODO:考虑关闭二创
                // 如果没有关联的项目元素等信息，则无法回溯，故设为不可二创
                portfolio.setOpenSource(0);
                portfolioMapper.updateById(portfolio);
            }
        }
        // 查询作品
        QueryWrapper<Portfolio> portfolioQueryWrapper = new QueryWrapper<>();
        portfolioQueryWrapper.lambda().eq(Portfolio::getOpenSource, 1);
        List<Portfolio> portfolioList = portfolioMapper.selectList(portfolioQueryWrapper);
        int size = portfolioList.size();
        int count = 0;
        for (Portfolio portfolio : portfolioList) {
            count ++;
            log.info("portfolio 迁移进度 {} / {}", count, size);
            if (portfolio.getCollectionId() != null) {
                QueryWrapper<UserLikeGroup> userLikeGroupQueryWrapper = new QueryWrapper<>();
                userLikeGroupQueryWrapper.lambda().eq(UserLikeGroup::getCollectionId, portfolio.getCollectionId());
                UserLikeGroup userLikeGroup = userLikeGroupMapper.selectOne(userLikeGroupQueryWrapper);
                if (Objects.nonNull(userLikeGroup)) {
                    // 副本存储对象
                    ProjectSnapshot projectSnapshot = new ProjectSnapshot();
//                    Long projectId = userLikeGroup.getProjectId();
//                    Project project = projectMapper.selectById(projectId);
                    // 根据项目ID获取项目设置
                    Long collectionId = userLikeGroup.getCollectionId();
                    QueryWrapper<Design> designQueryWrapper = new QueryWrapper<>();
                    designQueryWrapper.lambda().eq(Design::getCollectionId, collectionId);
                    Design design = designMapper.selectOne(designQueryWrapper);
//                    Collection collection = collectionMapper.selectById(collectionId);
                    Project project = new Project();
                    Workspace workspace = new Workspace();
                    workspace.setAgeGroup("Adult");
                    if (null != design.getTemplateId()) {
                        project.setProcess(DesignProcess.SERIES_DESIGN.name());
                        workspace.setPosition("Overall");
                        // workspace设置模特
                        if (design.getModelType().equals("System")) {
                            SysFile sysFile = sysFileMapper.selectById(design.getTemplateId());
                            if (sysFile.getLevel2Type().equals("Male")) {
                                workspace.setSex("Male");
                                workspace.setMannequinMaleId(design.getTemplateId());
                                workspace.setMannequinMaleType("System");
                            }else {
                                workspace.setSex("Female");
                                workspace.setMannequinFemaleId(design.getTemplateId());
                                workspace.setMannequinFemaleType("System");
                            }
                        }else {
                            Library library = libraryMapper.selectById(design.getTemplateId());
                            if (library.getLevel2Type().equals("Male")) {
                                workspace.setSex("Male");
                                workspace.setMannequinMaleId(design.getTemplateId());
                                workspace.setMannequinMaleType("Library");
                            }else {
                                workspace.setSex("Female");
                                workspace.setMannequinFemaleId(design.getTemplateId());
                                workspace.setMannequinFemaleType("Library");
                            }
                        }
                    }else {
                        project.setProcess(DesignProcess.SINGLE_DESIGN.name());
                        workspace.setPosition(design.getSwitchCategory());
                    }
                    workspace.setSystemDesignerPercentage(design.getSystemScale().multiply(new BigDecimal("100")).setScale(0, RoundingMode.HALF_UP).intValueExact());

                    project.setName(userLikeGroup.getName());
                    project.setOriginal(portfolio.getOriginal());
                    project.setOriginalPortfolioId(portfolio.getOriginalPortfolioId());
                    project.setOriginalAccountId(portfolio.getOriginalAccountId());

                    // 快照关联项目
                    projectSnapshot.setProject(project);
                    // 快照关联workspace
                    projectSnapshot.setWorkspace(workspace);


                    List<CollectionElement> collectionElementListOld = collectionElementService.getByCollectionId(collectionId);
                    projectSnapshot.setCollectionElementList(collectionElementListOld);

                    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);
                    portfolio.setSnapshot(snapshotJson);
                    portfolioMapper.updateById(portfolio);
                }
            }
        }
    }

    public void canvasData() {
        QueryWrapper<ExportFile> exportFileQueryWrapper = new QueryWrapper<>();
//        exportFileQueryWrapper.lambda().ge(ExportFile::getId, 10);
//        exportFileQueryWrapper.lambda().le(ExportFile::getId, 86);
        List<ExportFile> exportFiles = exportFileMapper.selectList(exportFileQueryWrapper);
        int size = exportFiles.size();
        int count = 0;
        for (ExportFile exportFile : exportFiles) {
            count ++;
            log.info("canvas 迁移进度 {} / {}", count, size);
            Long userLikeGroupId = exportFile.getProjectId();
            UserLikeGroup userLikeGroup = userLikeGroupMapper.selectById(userLikeGroupId);
            if (Objects.nonNull(userLikeGroup)) {
                exportFile.setProjectId(userLikeGroup.getProjectId());
                exportFileMapper.updateById(exportFile);
            }
        }
    }

    public void toProductRelightRelationProject() {
        QueryWrapper<Project> projectQueryWrapper = new QueryWrapper<>();
        List<Project> projects = projectMapper.selectList(projectQueryWrapper); // 所有project
        int size = projects.size();
        int count = 0;
        for (Project project : projects) {
            count ++;
            log.info("toProduct connect project 迁移进度 {} / {}", count, size);
            UserLikeGroup userLikeGroup = userLikeGroupService.getByProjectId(project.getId());
            if (Objects.nonNull(userLikeGroup)) {
                Long userLikeGroupId = userLikeGroup.getId();
                QueryWrapper<ToProductImageRecord> toProductImageRecordQueryWrapper = new QueryWrapper<>();
                toProductImageRecordQueryWrapper.lambda().eq(ToProductImageRecord::getUserLikeGroupId, userLikeGroupId);
                List<ToProductImageRecord> toProductImageRecords = toProductImageRecordMapper.selectList(toProductImageRecordQueryWrapper);
                for (ToProductImageRecord toProductImageRecord : toProductImageRecords) {
                    toProductImageRecord.setProjectId(project.getId());
                    toProductImageRecordMapper.updateById(toProductImageRecord);
                }

                QueryWrapper<ToProductImageResult> toProductImageResultQueryWrapper = new QueryWrapper<>();
                toProductImageResultQueryWrapper.lambda().eq(ToProductImageResult::getUserLikeGroupId, userLikeGroupId);
                List<ToProductImageResult> toProductImageResults = toProductImageResultMapper.selectList(toProductImageResultQueryWrapper);
                for (ToProductImageResult toProductImageResult : toProductImageResults) {
                    toProductImageResult.setProjectId(project.getId());
                    toProductImageResultMapper.updateById(toProductImageResult);
                }
            }
        }
    }

    public void userLikeGroupConvertProject() {
        QueryWrapper<UserLikeGroup> qw = new QueryWrapper<>();
        qw.lambda().ne(UserLikeGroup::getAccountId, -1);
        List<UserLikeGroup> userLikeGroups = userLikeGroupMapper.selectList(qw);
        int size = userLikeGroups.size();
        int count = 0;
        for (UserLikeGroup userLikeGroup : userLikeGroups) {
            count ++;
            log.info("userLikeGroupConvertProject 迁移进度 {} / {}", count, size);
            // 创建project
            Project project = new Project();
            project.setAccountId(userLikeGroup.getAccountId());
            project.setName(userLikeGroup.getName());
            project.setCreateTime(LocalDateTime.ofInstant(userLikeGroup.getCreateDate().toInstant(), ZoneId.systemDefault()));
            if (Objects.isNull(userLikeGroup.getUpdateDate())){
                project.setUpdateTime(LocalDateTime.ofInstant(userLikeGroup.getCreateDate().toInstant(), ZoneId.systemDefault()));
            } else {
                project.setUpdateTime(LocalDateTime.ofInstant(userLikeGroup.getUpdateDate().toInstant(), ZoneId.systemDefault()));
            }
//            project.setUpdateTime(LocalDateTime.ofInstant(userLikeGroup.getUpdateDate().toInstant(), ZoneId.systemDefault()));
            project.setOriginal(userLikeGroup.getOriginal());
            project.setOriginalAccountId(userLikeGroup.getOriginalAccountId());
            project.setOriginalPortfolioId(userLikeGroup.getOriginalPortfolioId());

            QueryWrapper<Design> designQueryWrapper = new QueryWrapper<>();
            designQueryWrapper.lambda().eq(Design::getCollectionId, userLikeGroup.getCollectionId())
                    .eq(Design::getAccountId, userLikeGroup.getAccountId())
                    .ne(Design::getCollectionId, 0);

            List<Design> designs = designMapper.selectList(designQueryWrapper);
            Design design;
            if (designs.isEmpty()) {
                log.info("collection_id {},对应design为空 ", userLikeGroup.getCollectionId());
                continue;
            } else if (designs.size() > 1){
                log.warn("collectionId 为：{}， accountId为：{}，查到{}条数据",
                        userLikeGroup.getCollectionId(), userLikeGroup.getAccountId(), designs.size() );
                design = designs.get(0);
            } else {
                design = designs.get(0);
            }
            // 设置项目类型 系列设计 || 单品设计
            if (design.getSingleOverall().equals("overall")) {
                project.setProcess(DesignProcess.SERIES_DESIGN.name());
            }else {
                project.setProcess(DesignProcess.SINGLE_DESIGN.name());
            }
            // 添加项目记录
            projectMapper.insert(project);

            userLikeGroup.setProjectId(project.getId());
            userLikeGroupMapper.updateById(userLikeGroup);

            Long accountId = userLikeGroup.getAccountId();
            QueryWrapper<Workspace> workspaceQueryWrapper = new QueryWrapper<>();
            workspaceQueryWrapper.lambda().eq(Workspace::getAccountId, accountId);
            workspaceQueryWrapper.lambda().eq(Workspace::getIsLastIndex, 1); // 最后一次使用的workspace的标识
            Workspace workspace = workspaceMapper.selectOne(workspaceQueryWrapper);
            if (Objects.isNull(workspace)) {
                log.info("用户id {}, 没有最后一次使用的workspace", accountId);
                continue;
            }
            workspace.setIsLastIndex(0); // 这个字段后续没有实际作用
            // 关联workspace与project
            workspace.setProjectId(project.getId());
            workspace.setSystemDesignerPercentage(design.getSystemScale().multiply(new BigDecimal("100")).setScale(0, RoundingMode.HALF_UP).intValueExact());
            if (!design.getSingleOverall().equals("overall")) {
                workspace.setPosition(design.getSwitchCategory());
            }

            workspace.setId(null);
            workspaceMapper.insert(workspace);  // 新增一条project则需要有对应的workspace记录

            QueryWrapper<CollectionElement> collectionElementQueryWrapper = new QueryWrapper<>();
            collectionElementQueryWrapper.lambda().eq(CollectionElement::getCollectionId, userLikeGroup.getCollectionId());
            List<CollectionElement> collectionElements = collectionElementMapper.selectList(collectionElementQueryWrapper);
            for (CollectionElement collectionElement : collectionElements) {
                // 关联collection_element和project
                collectionElement.setProjectId(project.getId());
                collectionElementMapper.updateById(collectionElement);
            }
            Collection collection = collectionMapper.selectById(userLikeGroup.getCollectionId());
            if (collection.getMoodTemplateId() != null) {
                CollectionElement collectionElement = collectionElementMapper.selectById(collection.getMoodTemplateId());
                if (Objects.isNull(collectionElement)){
                    log.warn("在collectionElement中找不到moodTemplateId为 {} 的记录", collection.getMoodTemplateId());
                    continue;
                }
                collectionElement.setProjectId(userLikeGroup.getProjectId());
                collectionElement.setIsCompositeImage(1);
                collectionElementMapper.updateById(collectionElement);
            }

            if (design.getModelType().equals("System")) {
                SysFile sysFile = sysFileMapper.selectById(design.getTemplateId());

                CollectionElement collectionElement = new CollectionElement();
                collectionElement.setAccountId(design.getAccountId());
                collectionElement.setProjectId(project.getId());
                collectionElement.setLevel1Type(CollectionLevel1TypeEnum.MODEL.getRealName());
//                    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);  // 为每个project创建一条模特记录

                CollectionElementRelModel collectionElementRelModel = new CollectionElementRelModel();
                collectionElementRelModel.setCollectionElementId(collectionElement.getId());
                collectionElementRelModel.setRelationId(sysFile.getId());
                collectionElementRelModel.setRelationType("System");
                collectionElementRelModelMapper.insert(collectionElementRelModel);
            }else {
                Library library = libraryMapper.selectById(design.getTemplateId());
                if (Objects.isNull(library)){
                    log.info("找不到模特{}，跳过", design.getTemplateId());
                    continue;
                }
                CollectionElement collectionElement = new CollectionElement();
                collectionElement.setAccountId(design.getAccountId());
                collectionElement.setProjectId(project.getId());
                collectionElement.setLevel1Type(CollectionLevel1TypeEnum.MODEL.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());
                collectionElement.setHasPin((byte) 0);
                collectionElementMapper.insert(collectionElement);  // 为每个project创建一条模特记录
                CollectionElementRelModel collectionElementRelModel = new CollectionElementRelModel();
                collectionElementRelModel.setCollectionElementId(collectionElement.getId());
                collectionElementRelModel.setRelationId(library.getId());
                collectionElementRelModel.setRelationType("Library");
                collectionElementRelModelMapper.insert(collectionElementRelModel);
            }
        }
    }

    public void userLikeAddToCollectionSort(){
        // 1、查询user_like_group表中projectId不为空的数据
        QueryWrapper<UserLikeGroup> qw = new QueryWrapper<>();
        qw.lambda().ne(UserLikeGroup::getAccountId, -1).isNotNull(UserLikeGroup::getProjectId);
        List<UserLikeGroup> userLikeGroups = userLikeGroupMapper.selectList(qw);
        int size = userLikeGroups.size();
        // 2、根据user_like_group_id去t_user_like表中获取id作为relation_id
        int userLikeGroupCount = 0;
        for (UserLikeGroup userLikeGroup : userLikeGroups){
            userLikeGroupCount ++;
            log.info("userLikeAddToCollectionSort 当前进度：{} / {}", userLikeGroupCount, size);
            QueryWrapper<UserLike> userLikeQW = new QueryWrapper<>();
            userLikeQW.lambda().eq(UserLike::getUserLikeGroupId, userLikeGroup.getId());
            List<UserLike> userLikes = userLikeMapper.selectList(userLikeQW);
            int count = userLikes.size();
            for (UserLike userLike: userLikes){
                // 3、将数据添加到collection_sort表中
                CollectionSort userLikeSort = new CollectionSort();
                userLikeSort.setProjectId(userLikeGroup.getProjectId());
                userLikeSort.setRelationId(userLike.getId());
                userLikeSort.setRelationType(CollectionType.DESIGN.getValue());
                userLikeSort.setSort(count);
                userLikeSort.setCreateTime(LocalDateTime.now());
                collectionSortMapper.insert(userLikeSort);
                count--;
            }
        }
    }

}
