package com.ai.da.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.ai.da.common.config.exception.BusinessException;
import com.ai.da.common.context.UserContext;
import com.ai.da.common.enums.SingleOverallEnum;
import com.ai.da.common.enums.SysFileLevel2TypeEnum;
import com.ai.da.common.utils.CopyUtil;
import com.ai.da.common.utils.DateUtil;
import com.ai.da.common.utils.MinioUtil;
import com.ai.da.mapper.primary.DesignItemMapper;
import com.ai.da.mapper.primary.entity.*;
import com.ai.da.model.dto.*;
import com.ai.da.model.enums.ModelType;
import com.ai.da.model.vo.*;
import com.ai.da.python.PythonService;
import com.ai.da.python.vo.*;
import com.ai.da.service.*;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import io.netty.util.internal.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 服务实现类
 *
 * @author yanglei
 * @since 2022-09-30
 */
@Slf4j
@Service
public class DesignItemServiceImpl extends ServiceImpl<DesignItemMapper, DesignItem> implements DesignItemService {
    @Resource
    private DesignItemMapper designItemMapper;
    @Resource
    private SysFileService sysFileService;
    @Resource
    private PythonService pythonService;
    @Resource
    private DesignService designService;
    @Resource
    private DesignItemDetailService designItemDetailService;
    @Resource
    private LibraryModelPointService libraryModelPointService;
    @Resource
    private LibraryService libraryService;
    @Resource
    private CollectionElementService collectionElementService;
    @Resource
    private ITDesignPythonOutfitService designPythonOutfitService;
    @Resource
    private ITDesignPythonOutfitDetailService designPythonOutfitDetailService;
    @Resource
    private PanToneService panToneService;
    @Resource
    private DesignItemDetailPrintService designItemDetailPrintService;
    @Resource
    private MinioUtil minioUtil;
    @Resource
    private UserLikeService userLikeService;
    @Resource
    private UserLikeGroupService userLikeGroupService;

    @Override
    public Long saveOne(DesignItem designItem) {
        if (designItemMapper.insertDesignItem(designItem) <= 0) {
            throw new BusinessException("save.designItem.failed");
        }
        return designItem.getId();
    }

    @Override
    public int deleteByCollectionId(Long collectionId) {
        QueryWrapper<DesignItem> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("collection_id", collectionId);

        DesignItem designItem = new DesignItem();
        designItem.setCollectionId(0L);
        return designItemMapper.update(designItem, queryWrapper);
    }

    @Override
    public List<DesignItem> getByDesignId(Long designId) {
        QueryWrapper<DesignItem> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("design_id", designId);
        queryWrapper.eq("is_like", (byte) 0);
        return designItemMapper.selectList(queryWrapper);
    }

    @Override
    public void updateLikeStatus(Long designItemId, Byte hasLike) {
        QueryWrapper<DesignItem> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id", designItemId);

        DesignItem designItem = new DesignItem();
        designItem.setHasLike(hasLike);
        designItemMapper.update(designItem, queryWrapper);
    }

    @Override
    public void updateDesignHighUrl(Long designItemId, String highUrl, String timeZone) {
        QueryWrapper<DesignItem> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id", designItemId);

        DesignItem designItem = new DesignItem();
        designItem.setHighDesignUrl(highUrl);
        designItem.setUpdateDate(DateUtil.getByTimeZone(timeZone));
        designItemMapper.update(designItem, queryWrapper);
    }

    @Override
    public GetNextSysElementVO getNextSysElement(Long id, String level2Type, String operateType) {
        //校验
        if (!DesignPythonItem.SYS_HAIRSTYLE_SHOES_BODY.contains(level2Type)) {
            throw new BusinessException("unknown.type");
        }
        List<String> operateTypes = Arrays.asList("PREV", "NEXT");
        if (!operateTypes.contains(operateType)) {
            throw new BusinessException("unknown.operateType");
        }
        if (null == id) {
            throw new BusinessException("id.cannot.be.empty");
        }
        Long maxId = sysFileService.getMaxIdByLevel2Type(level2Type, null);
        Long minId = sysFileService.getMinIdByLevel2Type(level2Type, null);

        if (id > maxId || id < minId) {
            throw new BusinessException("the.id.value.is.out.of.range");
        }
        Long idValue = null;
        if ("PREV".equals(operateType)) {
            if (minId.equals(id)) {
                idValue = minId;
            } else {
                idValue = id - 1;
            }
        }
        if ("NEXT".equals(operateType)) {
            if (maxId.equals(id)) {
                idValue = maxId;
            } else {
                idValue = id + 1;
            }
        }
        SysFileVO sysFileVO = sysFileService.getById(idValue);
        return new GetNextSysElementVO(sysFileVO.getId(), level2Type, sysFileVO.getUrl());
    }

    @Override
    public DesignCollectionItemVO designSingle(DesignSingleDTO designSingleDTO) {
        AuthPrincipalVo userInfo = UserContext.getUserHolder();
        DesignItem designItem = selectById(designSingleDTO.getDesignItemId());
        if (Objects.isNull(designItem)) {
            throw new BusinessException("designItem.not.found");
        }
        Design design = designService.getById(designItem.getDesignId());
        if (Objects.isNull(design)) {
            throw new BusinessException("design.not.found");
        }
        DesignLibraryModelPointVO designLibraryModelPointVO = null;
        if (Objects.nonNull(design.getTemplateId())) {
            LibraryModelPoint modelPoint = libraryModelPointService.getById(design.getTemplateId());
            if (Objects.isNull(modelPoint)) {
                throw new BusinessException("modelPoint.not.found");
            }
            Library library = libraryService.getById(modelPoint.getRelationId());
            // ??和上面重复
            if (Objects.isNull(library)) {
                throw new BusinessException("library.not.found");
            }
            designLibraryModelPointVO = collectionElementService.calculateTemplatePoint(modelPoint, library.getHigh(), library.getWidth(), library.getUrl());
        }

        Set<String> newTypes = designSingleDTO.getClothes().stream().map(DesignSingleItemDTO::getType).collect(Collectors.toSet());
        //校验category
        validateCategory(newTypes, design.getSingleOverall(), design.getSwitchCategory());
        DesignPythonObjects objects = pythonService.covertDesignSingleParam(
                designSingleDTO, design.getSingleOverall(), design.getSwitchCategory(), designLibraryModelPointVO);
        pythonService.design(objects);
        //designSingle
        DesignCollectionItemVO response = saveSingleDesignItemAndDetail(objects, design.getId(), designSingleDTO.getDesignItemId(),
                design.getCollectionId(), userInfo, designSingleDTO.getTimeZone());
        // ??
        designItem.setDesignUrl(response.getDesignItemUrl());
        return response;
    }

    private LibraryModelPointVO resloveVoByModelPoint(LibraryModelPoint modelPoint, Library library) {
        LibraryModelPointVO libraryModelPointVO = CopyUtil.copyObject(modelPoint, LibraryModelPointVO.class);
        libraryModelPointVO.setTemplateId(modelPoint.getId());
        libraryModelPointVO.setHandLeft(JSON.parseObject(modelPoint.getHandLeft(), List.class));
        libraryModelPointVO.setHandRight(JSON.parseObject(modelPoint.getHandRight(), List.class));
        libraryModelPointVO.setShoulderRight(JSON.parseObject(modelPoint.getShoulderRight(), List.class));
        libraryModelPointVO.setShoulderLeft(JSON.parseObject(modelPoint.getShoulderLeft(), List.class));
        libraryModelPointVO.setWaistbandRight(JSON.parseObject(modelPoint.getWaistbandRight(), List.class));
        libraryModelPointVO.setWaistbandLeft(JSON.parseObject(modelPoint.getWaistbandLeft(), List.class));
        return libraryModelPointVO;
    }

    @Override
    public String printDot(DesignSingleDTO designSingleDTO) {
        DesignItem designItem = selectById(designSingleDTO.getDesignItemId());
        if (Objects.isNull(designItem)) {
            throw new BusinessException("designItem.not.found");
        }
        Design design = designService.getById(designItem.getDesignId());
        if (Objects.isNull(design)) {
            throw new BusinessException("design.not.found");
        }
        DesignLibraryModelPointVO designLibraryModelPointVO = null;
        if (Objects.nonNull(design.getTemplateId())) {
            LibraryModelPoint modelPoint = libraryModelPointService.getById(design.getTemplateId());
            if (Objects.isNull(modelPoint)) {
                throw new BusinessException("modelPoint.not.found");
            }
            Library library = libraryService.getById(modelPoint.getRelationId());
            if (Objects.isNull(library)) {
                throw new BusinessException("library.not.found");
            }
            designLibraryModelPointVO = collectionElementService.calculateTemplatePoint(modelPoint, library.getHigh(), library.getWidth(), library.getUrl());
        }
        Set<String> newTypes = designSingleDTO.getClothes().stream().map(DesignSingleItemDTO::getType).collect(Collectors.toSet());
        //校验category
        validateCategory(newTypes, design.getSingleOverall(), design.getSwitchCategory());
        DesignPythonObjects objects = pythonService.covertDesignSingleParam(
                designSingleDTO, design.getSingleOverall(), design.getSwitchCategory(), designLibraryModelPointVO);
        pythonService.design(objects);

        return objects.getObjects().get(0).getBasic().getSave_name();
    }

    private void validateCategory(Set<String> newTypes, String singleOverall, String switchCategory) {
        if (SingleOverallEnum.SINGLE.getRealName().equals(singleOverall)) {
            if (newTypes.size() > 1) {
                throw new BusinessException("wrong.clothes.type");
            }
            //一个的时候
            if (!switchCategory.equals(CollectionUtil.newArrayList(newTypes).get(0))) {
                throw new BusinessException("wrong.clothes.type");
            }
        }
    }

    private DesignCollectionItemVO saveSingleDesignItemAndDetail(DesignPythonObjects pythonObjects
            , Long designId, Long designItemId, Long collectionId, AuthPrincipalVo userInfo, String timeZone) {
        DesignCollectionItemVO response = new DesignCollectionItemVO();
        response.setDesignItemId(designItemId);

        DesignItem designItem = new DesignItem();
        String url = pythonObjects.getObjects().get(0).getBasic().getSave_name();
        designItem.setUpdateDate(DateUtil.getByTimeZone(timeZone));
        designItem.setDesignUrl(url);
        designItem.setId(designItemId);
        response.setDesignItemUrl(url);
        //更新item
        updateById(designItem);
        //删除itemDetail
        designItemDetailService.deleteByDesignItemId(designItemId);

        List<DesignItemDetail> designItemDetails = Lists.newArrayList();
        pythonObjects.getObjects().get(0).getItems().forEach(detail -> {
            if (null == detail) {
                return;
            }
            DesignItemDetail designItemDetail = CopyUtil.copyObject(detail, DesignItemDetail.class);
            designItemDetail.setAccountId(userInfo.getId());
            designItemDetail.setDesignId(designId);
            designItemDetail.setDesignItemId(designItemId);
            designItemDetail.setCollectionElementId(detail.getElementId());
            designItemDetail.setCreateDate(DateUtil.getByTimeZone(timeZone));
            if (SysFileLevel2TypeEnum.BODY.getRealName().equals(detail.getType())) {
                designItemDetail.setPath(detail.getBody_path());
                //BODY不关联businessId
                designItemDetail.setBusinessId(0L);
            }
            designItemDetail.setIconPath(detail.getIcon());
            DesignPythonItemPrint printObject = detail.getPrint();
            designItemDetail.setPrintPath(Objects.isNull(printObject) ? "" : printObject.getPath());
            designItemDetail.setPrintJson(JSON.toJSONString(printObject));
            designItemDetails.add(designItemDetail);
        });
        designItemDetailService.saveBatch(designItemDetails);
        //封装item信息
        List<DesignCollectionItemVO> designCollectionItems = CopyUtil.copyList(getByDesignId(designId)
                , DesignCollectionItemVO.class, (o, d) -> {
                    d.setDesignItemId(o.getId());
                    d.setDesignItemUrl(o.getDesignUrl());
                });
        return response;
    }

    private List<TDesignPythonOutfitDetail> saveDesignSingleItemDetailAndLayers(DesignPythonObjects pythonObjects
            , Long designId, Long designItemId, AuthPrincipalVo userInfo
            , JSONObject outfit, String timeZone, List<DesignSingleItemDTO> designSingleItemDTOList) {

        DesignItem designItem = new DesignItem();
//        String url = pythonObjects.getObjects().get(0).getBasic().getSave_name();
        designItem.setUpdateDate(DateUtil.getByTimeZone(timeZone));
        designItem.setDesignUrl(outfit.getString("synthesis_url"));
        designItem.setId(designItemId);
        // 1、更新designItem
        updateById(designItem);
        // 2、删除designItemDetail(逻辑删除)
        designItemDetailService.deleteByDesignItemId(designItemId);
        List<DesignItemDetail> designItemDetails = Lists.newArrayList();
        // 3、保存新的designItemDetail
        pythonObjects.getObjects().get(0).getItems().forEach(detail -> {
            if (null == detail) {
                return;
            }
            DesignItemDetail designItemDetail = CopyUtil.copyObject(detail, DesignItemDetail.class);
            designItemDetail.setAccountId(userInfo.getId());
            designItemDetail.setDesignId(designId);
            designItemDetail.setDesignItemId(designItemId);
            designItemDetail.setCollectionElementId(detail.getElementId());
            designItemDetail.setPriority(detail.getPriority());
            designItemDetail.setCreateDate(DateUtil.getByTimeZone(timeZone));
            if (SysFileLevel2TypeEnum.BODY.getRealName().equals(detail.getType())) {
                designItemDetail.setPath(detail.getBody_path());
                //BODY不关联businessId
                designItemDetail.setBusinessId(0L);
                designItemDetail.setPriority(0);
            }
            designItemDetail.setIconPath(detail.getIcon());
            DesignPythonItemPrint printObject = detail.getPrint();
            designItemDetail.setPrintPath(Objects.isNull(printObject) ? "" : printObject.getPath());
//            当有多个印花后，返回的printObject太长，导致存储到数据库时报错
//            designItemDetail.setPrintJson(JSON.toJSONString(printObject));
            designItemDetails.add(designItemDetail);
        });
        // businessId 来自t_sys_file或者t_library
        designItemDetailService.saveBatch(designItemDetails);

        // 4、保存印花信息到designItemDetailPrint
        List<DesignItemDetailPrint> designItemDetailPrints = setDesignItemDetailPrintList(designItemDetails, designSingleItemDTOList, timeZone);
        designItemDetailPrintService.saveBatch(designItemDetailPrints);

        // 5、覆盖designPythonOutfit表中的模特全身图
        TDesignPythonOutfit designPythonOutfit = new TDesignPythonOutfit();
        designPythonOutfit.setDesignUrl(outfit.getString("synthesis_url"));
        designPythonOutfit.setId(designPythonOutfitService.getByDesignItemId(designItemId).getId());
        designPythonOutfit.setUpdateDate(LocalDateTime.now(ZoneId.of(timeZone)));
        designPythonOutfitService.updateById(designPythonOutfit);

        // 6、删除designPythonOutfitDetail表中原始的图层信息（逻辑删除）
        designPythonOutfitDetailService.deleteByDesignPythonOutfitId(designPythonOutfit.getId());

        // 7、将新生成的图层信息存入designPythonOutfitDetail表
        JSONArray layers = outfit.getJSONArray("layers");

        // 需要将request中的offset也存入数据库，通过priority与image_category将sketch与layers关联
//        Map<String, List<Long>> typeOffset = designSingleItemDTOList.stream()
//                .collect(Collectors.toMap(d -> d.getType().toLowerCase(), DesignSingleItemDTO::getOffset));
        Map<Integer, List<Long>> priorityOffset = designSingleItemDTOList.stream()
                .collect(Collectors.toMap(DesignSingleItemDTO::getPriority, DesignSingleItemDTO::getOffset));
        List<TDesignPythonOutfitDetail> list = setTDesignPythonOutfitDetailList(layers, designId, designPythonOutfit.getId(), userInfo.getId(), priorityOffset);

        designPythonOutfitDetailService.saveBatch(list);

        return list;
    }

    public List<TDesignPythonOutfitDetail> setTDesignPythonOutfitDetailList(JSONArray layers, Long designId,
                                                                            Long designPythonOutfitId, Long userId,
                                                                            Map<Integer, List<Long>> priorityOffset) {
        // 设置图层信息;
        List<TDesignPythonOutfitDetail> list = new ArrayList<>();
        for (int i = 0; i < layers.size(); i++) {
            JSONObject jsonObject = layers.getJSONObject(i);
            TDesignPythonOutfitDetail designPythonOutfitDetail = new TDesignPythonOutfitDetail();
            designPythonOutfitDetail.setDesignId(designId);
            designPythonOutfitDetail.setDesignPythonOutfitId(designPythonOutfitId);
            designPythonOutfitDetail.setPosition(jsonObject.getString("position"));
            designPythonOutfitDetail.setImageUrl(jsonObject.getString("image_url"));
            designPythonOutfitDetail.setImageSize(jsonObject.getString("image_size"));
            designPythonOutfitDetail.setImageCategory(jsonObject.getString("image_category"));
            designPythonOutfitDetail.setMaskUrl(jsonObject.getString("mask_url"));
            designPythonOutfitDetail.setScale(Objects.isNull(jsonObject.getString("resize_scale")) ? "1.0" : jsonObject.getString("resize_scale"));
            designPythonOutfitDetail.setUserId(userId);
            designPythonOutfitDetail.setOffset(String.valueOf(priorityOffset.get(Math.abs(Integer.parseInt(jsonObject.getString("priority"))))));
            designPythonOutfitDetail.setPriority((Integer) jsonObject.get("priority"));
            list.add(designPythonOutfitDetail);
        }
        return list;
    }

    private DesignItem selectById(Long id) {
        QueryWrapper<DesignItem> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id", id);
        return designItemMapper.selectOne(queryWrapper);
    }

    private Boolean exists(Long id) {
        QueryWrapper<DesignItem> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id", id);
        return designItemMapper.exists(queryWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public DesignSingleVO designSingleIncludeLayers(DesignSingleIncludeLayersDTO designSingleIncludeLayersDTO) {
        log.info("designSingle request入参  ==>  " + designSingleIncludeLayersDTO.toString());

        AuthPrincipalVo userInfo = UserContext.getUserHolder();
        DesignItem designItem = selectById(designSingleIncludeLayersDTO.getDesignItemId());
        if (Objects.isNull(designItem)) {
            throw new BusinessException("designItem.not.found");
        }
        Design design = designService.getById(designItem.getDesignId());
        if (Objects.isNull(design)) {
            throw new BusinessException("design.not.found");
        }

        DesignLibraryModelPointVO designLibraryModelPointVO = null;
        // 设置模特
        if (Objects.nonNull(design.getTemplateId())) {
            String modelUrl;
            Integer high;
            Integer width;
            if (design.getModelType().equals(ModelType.SYSTEM.getValue())) {
                SysFileVO sysFile = sysFileService.getById(design.getTemplateId());
                if (Objects.isNull(sysFile)) {
                    throw new BusinessException("model.not.found");
                }
                modelUrl = sysFile.getUrl();
                high = 700;
                width = 320;
            } else if (design.getModelType().equals(ModelType.LIBRARY.getValue())){
                Library libFile = libraryService.getById(design.getTemplateId());
                if (Objects.isNull(libFile)) {
                    throw new BusinessException("model.not.found");
                }
                modelUrl = libFile.getUrl();
                high = libFile.getHigh();
                width = libFile.getWidth();
            }else {
                throw new BusinessException("unknown.modelType");
            }
            LibraryModelPoint modelPoint = libraryModelPointService.getByRelationId(design.getTemplateId(), design.getModelType());
            if (Objects.isNull(modelPoint)) {
                throw new BusinessException("modelPoint.not.found");
            }
//            Assert.notNull(modelPoint, "The model has not been tagged");

            designLibraryModelPointVO = collectionElementService.calculateTemplatePoint(modelPoint, high, width, modelUrl);
        }

        // 组装入参
        DesignPythonObjects objects = pythonService.covertDesignSingleParam(
                designSingleIncludeLayersDTO, design.getSingleOverall(), design.getSwitchCategory(), designLibraryModelPointVO);
        // design
        JSONObject jsonObject = pythonService.designNew(objects);
        // preview -> 不存数据库    submit -> 存数据库
        List<TDesignPythonOutfitDetail> tDesignPythonOutfitDetails;
        JSONObject data = jsonObject.getJSONObject("data");
        if (data == null) {
            throw new BusinessException("python response data is null");
        }
        JSONObject outfit = data.getJSONObject("0");
        // 通过priority将offset关联到layers
//        Map<String, List<Long>> typeOffset = designSingleIncludeLayersDTO.getDesignSingleItemDTOList().stream()
//                .collect(Collectors.toMap(d -> d.getType().toLowerCase(), DesignSingleItemDTO::getOffset));
        Map<Integer, List<Long>> priorityOffset = new HashMap<>();
        try{
            priorityOffset = designSingleIncludeLayersDTO.getDesignSingleItemDTOList().stream()
                    .collect(Collectors.toMap(DesignSingleItemDTO::getPriority, DesignSingleItemDTO::getOffset));
        }catch (IllegalStateException e){
            // priority重复
            log.info("服装的priority重复");
            throw new BusinessException("priority.cannot.be.repeated");
        }

        if (!designSingleIncludeLayersDTO.getIsPreview()) {
            // 更新及保存图层信息
            tDesignPythonOutfitDetails = saveDesignSingleItemDetailAndLayers(objects, design.getId(), designSingleIncludeLayersDTO.getDesignItemId(),
                    userInfo, outfit, designSingleIncludeLayersDTO.getTimeZone(), designSingleIncludeLayersDTO.getDesignSingleItemDTOList());
        } else {
            JSONArray layers = outfit.getJSONArray("layers");
            tDesignPythonOutfitDetails = setTDesignPythonOutfitDetailList(layers, designItem.getDesignId(), null, userInfo.getId(), priorityOffset);
        }

        List<DesignPythonOutfitVO> detailsVO = new ArrayList<>();

        tDesignPythonOutfitDetails.forEach(detail -> {
            String type = detail.getImageCategory().split("_")[0];
            detailsVO.add(designPythonOutfitDetailService.convertToDesignPythonOutfitVO(detail, null));
        });

        TDesignPythonOutfit designPythonOutfit = designPythonOutfitService.getByDesignItemId(designSingleIncludeLayersDTO.getDesignItemId());
//        Assert.notNull(designItem, "design item detail layers does not exists!");

       // 如果当前item被like过，需要更新t_user_like表和t_user_like_group表
        if (!designSingleIncludeLayersDTO.getIsPreview()){
            updateUserLikeDate(designSingleIncludeLayersDTO.getDesignItemId(),designSingleIncludeLayersDTO.getTimeZone());
        }

        return assembleDesignSingleResponse(designItem.getId(),
                minioUtil.getPresignedUrl(designPythonOutfit.getDesignUrl(), 24 * 60),
                outfit.getString("synthesis_url"),
                designSingleIncludeLayersDTO.getDesignSingleItemDTOList(),
                detailsVO,
                design.getSingleOverall());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ComposeLayersVO editLayersPositionAndScale(EditLayersPositionAndScaleVO positionAndScaleVO) throws IOException {
        ComposeLayersVO designItemLayer = positionAndScaleVO.getLayers();
        // 1、校验designItem是是否存在
        DesignItem designItem = selectById(designItemLayer.getDesignItemId());
        if (Objects.isNull(designItem)){
            throw new BusinessException("design.item.does.not.exist");
        }
        TDesignPythonOutfit designPythonOutfit = designPythonOutfitService.getByDesignItemId(designItemLayer.getDesignItemId());
        if (Objects.isNull(designPythonOutfit)){
            throw new BusinessException("layers.does.not.exists");
        }

        // 2、校验layers是否存在
        designItemLayer.getLayers().forEach(layer -> {
            TDesignPythonOutfitDetail detail = designPythonOutfitDetailService.getById(layer.getId());
            if (Objects.isNull(detail)){
                log.error(layer.getImageCategory() + " layer does not exists!");
                throw new BusinessException("layers.does.not.exists");
            }
//            Assert.notNull(detail, layer.getImageCategory() + " layer does not exists!");

            /*layer.setImageUrl(detail.getImageUrl());
            layer.setMaskUrl(detail.getMaskUrl());*/
        });

        // 3、组装python入参
        List<OutfitDetailPythonItem> outfitDetailPythonItems = convertToOutfitDetailPythonItemList(designItemLayer.getLayers());

        // 4、合成图层
        String synthesisUrl = pythonService.composeLayers(outfitDetailPythonItems);
        designItemLayer.setDesignItemUrl(minioUtil.getPresignedUrl(synthesisUrl, 24 * 60));

        // 5、更新数据库，根据designItemId更新designItemUrl
        designItem.setUpdateDate(DateUtil.getByTimeZone(positionAndScaleVO.getTimeZone()));
        designItem.setDesignUrl(synthesisUrl);
        designItem.setId(designItemLayer.getDesignItemId());
        designItem.setUpdateDate(DateUtil.getByTimeZone(positionAndScaleVO.getTimeZone()));
        updateById(designItem);

        // 6、更新数据库，根据designItemId更新t_design_python_outfit的designUrl
        TDesignPythonOutfit tDesignPythonOutfit = new TDesignPythonOutfit();
        tDesignPythonOutfit.setDesignUrl(synthesisUrl);
        tDesignPythonOutfit.setId(designPythonOutfit.getId());
        tDesignPythonOutfit.setUpdateDate(LocalDateTime.now(ZoneId.of(positionAndScaleVO.getTimeZone())));
        designPythonOutfitService.updateById(tDesignPythonOutfit);

        // 7、将图层信息position和scale更新到t_design_python_outfit_detail表
        ArrayList<TDesignPythonOutfitDetail> details = new ArrayList<>();
        designItemLayer.getLayers().forEach(layer -> {
            TDesignPythonOutfitDetail layerDetail = new TDesignPythonOutfitDetail();
            layerDetail.setPosition(layer.getPosition().toString());
            layerDetail.setScale(layer.getScale().toString());
            layerDetail.setId(layer.getId());
            details.add(layerDetail);
        });
        designPythonOutfitDetailService.updateBatchById(details);

        // 8、返回图层及合成图信息
        designItemLayer.getLayers().forEach(layer -> {
            ArrayList<Long> imageSize = new ArrayList<>();
            for (int i = 0; i < layer.getImageSize().size(); i++) {
                imageSize.add((long) (layer.getImageSize().get(i) * layer.getScale()));
            }
            layer.setImageSize(imageSize);
            if (!StringUtil.isNullOrEmpty(layer.getImageUrl())) {
                layer.setImageUrl(minioUtil.getPresignedUrl(layer.getImageUrl(), 24 * 60));
            }
            if (!StringUtil.isNullOrEmpty(layer.getMaskUrl())) {
                layer.setMaskUrl(minioUtil.getPresignedUrl(layer.getMaskUrl(), 24 * 60));
            }
        });

        // 9、如果当前item被like过，需要更新t_user_like表和t_user_like_group表
        updateUserLikeDate(designItemLayer.getDesignItemId(),positionAndScaleVO.getTimeZone());
        return designItemLayer;
    }

    private void updateUserLikeDate(Long designItemId,String timeZone){
        UserLike userLike = userLikeService.getByDesignItemId(designItemId);
        if (!ObjectUtil.isEmpty(userLike)){
            Long userLikeGroupId = userLike.getUserLikeGroupId();
            // 更新t_user_like和t_user_like_group表的update_date
            userLikeService.updateDate(designItemId,timeZone);
            userLikeGroupService.updateDate(userLikeGroupId,timeZone);
        }
    }

    private DesignSingleVO assembleDesignSingleResponse(Long designItemId, String designItemUrl,
                                                        String currentFullBodyView,
                                                        List<DesignSingleItemDTO> designSingleItemDTOList,
                                                        List<DesignPythonOutfitVO> layersObject,
                                                        String singleOrOverall) {

        DesignSingleVO designSingleVO = new DesignSingleVO();
        ArrayList<DesignItemClothesDetailVO> clothes = new ArrayList<>();
        DesignItemClothesDetailVO body = new DesignItemClothesDetailVO("body");
        designSingleVO.setDesignItemId(designItemId);
        // 图片用于修改前后的一键对比
        designSingleVO.setDesignItemUrl(designItemUrl);
        // 当前全身图
        designSingleVO.setCurrentFullBodyView(minioUtil.getPresignedUrl(currentFullBodyView, 24 * 60));
        designSingleVO.setClothes(clothes);

        boolean flag = singleOrOverall.equals("single");
        designSingleItemDTOList.forEach(singleItem -> {
            DesignItemClothesDetailVO designItemClothesDetailVO = new DesignItemClothesDetailVO();
            designItemClothesDetailVO.setId(singleItem.getId());
            designItemClothesDetailVO.setType(singleItem.getType());
            designItemClothesDetailVO.setPath(minioUtil.getPresignedUrl(singleItem.getPath(), 24 * 60));
            designItemClothesDetailVO.setMinIOPath(singleItem.getPath());
            designItemClothesDetailVO.setColor(panToneService.getPantoneByRgb(singleItem.getColor()));
//            designItemClothesDetailVO.setPrintObject(new DesignPythonItemPrint(singleItem.getPrintObject().getPath()));
            designItemClothesDetailVO.setPrintObject(singleItem.getPrintObject());
            designItemClothesDetailVO.setLayersObject(layersObject.stream().filter(
                    layers -> (singleItem.getType().toLowerCase().equals(layers.getImageCategory().split("_")[0])
                            && (flag ? Boolean.TRUE : singleItem.getPriority().equals(layers.getPriority())))
            ).collect(Collectors.toList()));
            body.setLayersObject(layersObject.stream().filter(layers -> layers.getImageCategory().equals("body")).collect(Collectors.toList()));

            clothes.add(designItemClothesDetailVO);
        });
        clothes.add(body);

        return designSingleVO;
    }

    private List<DesignItemDetailPrint> setDesignItemDetailPrintList(List<DesignItemDetail> designItemDetails,
                                                                     List<DesignSingleItemDTO> designSingleItemDTOList,
                                                                     String timeZone) {

        Map<Integer, Long> designItemDetailTypeIdMap = designItemDetails.stream().collect(Collectors.toMap(DesignItemDetail::getPriority, DesignItemDetail::getId));
        ArrayList<DesignItemDetailPrint> designItemDetailPrints = new ArrayList<>();

        designSingleItemDTOList.forEach(designSingleItem -> {
            // 1、判断有无印花，无印花则跳过
            DesignSinglePrintDTO printObject = designSingleItem.getPrintObject();
            if (printObject.getIfSingle().equals(Boolean.FALSE)
                    && CollectionUtil.isEmpty(printObject.getPrints())) {
                return;
            } else {
                // 2、有印花，添加到list
                printObject.getPrints().forEach(print -> {
                    // 2.1 判断是否第一次添加印花，是：直接添加
                    List<DesignItemDetailPrint> designItemDetailPrintList = designItemDetailPrintService.getByDesignItemDetailId(designItemDetailTypeIdMap.get(designSingleItem.getPriority()));
                    if (!designItemDetailPrintList.isEmpty()) {
                        // 2.2 否：先删除原始印花，再添加新印花信息
                        designItemDetailPrintService.deleteByDesignItemDetailId(designItemDetailTypeIdMap.get(designSingleItem.getPriority()));
                    }
                    DesignItemDetailPrint designItemDetailPrint = new DesignItemDetailPrint();
                    designItemDetailPrint.setDesignItemDetailId(designItemDetailTypeIdMap.get(designSingleItem.getPriority()));
                    designItemDetailPrint.setPath(print.getMinIOPath());
                    designItemDetailPrint.setScale(print.getScale());
                    designItemDetailPrint.setSingleOrOverall(printObject.getIfSingle() ? "single" : "overall");
                    designItemDetailPrint.setCreateDate(LocalDateTime.now(ZoneId.of(timeZone)));
                    // single、overall模式下都有position、angle和priority
                    designItemDetailPrint.setPosition(print.getLocation().toString());
                    designItemDetailPrint.setAngle(print.getAngle());
                    designItemDetailPrint.setPriority(print.getPriority());
                    designItemDetailPrints.add(designItemDetailPrint);
                });
            }
        });
        return designItemDetailPrints;
    }

    private List<OutfitDetailPythonItem> convertToOutfitDetailPythonItemList(List<DesignPythonOutfitVO> layers) {
        List<OutfitDetailPythonItem> composeLayerPythonItem = Arrays.asList(new OutfitDetailPythonItem[layers.size()]);
        layers.forEach(layer -> {
            composeLayerPythonItem.set(layer.getPriority() - 1, new OutfitDetailPythonItem(layer.getImageCategory(),
                    layer.getPosition(),
                    layer.getImageSize(),
                    layer.getScale(),
                    layer.getImageUrl(),
                    layer.getMaskUrl()));
        });
        return composeLayerPythonItem;
    }

    @Override
    public List<DesignItem> selectDesignIdById(List<Long> designItemIdList){
        QueryWrapper<DesignItem> queryWrapper = new QueryWrapper<>();

        queryWrapper.in("id",designItemIdList);
        return designItemMapper.selectList(queryWrapper);
    }
}
