package com.cf.imes.module.executor.service.plate;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.FieldValue;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.Hit;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO;
import com.cf.imes.framework.common.enums.*;
import com.cf.imes.framework.common.exception.ServiceException;
import com.cf.imes.framework.common.exception.util.ServiceExceptionUtil;
import com.cf.imes.framework.common.pojo.PageResult;
import com.cf.imes.framework.common.util.Assert.AssertUtils;
import com.cf.imes.framework.common.util.object.BeanUtils;
import com.cf.imes.framework.id.core.util.SnowflakeIdWorker3rd;
import com.cf.imes.framework.mybatis.core.query.MPJLambdaWrapperX;
import com.cf.imes.framework.mybatis.core.query.QueryWrapperX;
import com.cf.imes.module.executor.controller.admin.goods.vo.GoodsSaveReqVO;
import com.cf.imes.module.executor.controller.admin.order.vo.order.OrderPlanPlateNumAndAreaRespVO;
import com.cf.imes.module.executor.controller.admin.plan.vo.OrderGoodsResp;
import com.cf.imes.module.executor.controller.admin.plan.vo.PlateResList;
import com.cf.imes.module.executor.controller.admin.plate.vo.*;
import com.cf.imes.module.executor.dal.dataobject.goods.GoodsDO;
import com.cf.imes.module.executor.dal.dataobject.order.OrderDO;
import com.cf.imes.module.executor.dal.dataobject.orderBody.OrderBodyDO;
import com.cf.imes.module.executor.dal.dataobject.orderItem.OrderItemDO;
import com.cf.imes.module.executor.dal.dataobject.ordermodel.OrderModelDO;
import com.cf.imes.module.executor.dal.dataobject.plan.PlanDO;
import com.cf.imes.module.executor.dal.dataobject.plate.PlateDO;
import com.cf.imes.module.executor.dal.dataobject.plate.PlateGoodDO;
import com.cf.imes.module.executor.dal.mysql.goods.GoodsMapper;
import com.cf.imes.module.executor.dal.mysql.order.OrderMapper;
import com.cf.imes.module.executor.dal.mysql.orderBody.OrderBodyMapper;
import com.cf.imes.module.executor.dal.mysql.orderItem.OrderItemMapper;
import com.cf.imes.module.executor.dal.mysql.plan.PlanMapper;
import com.cf.imes.module.executor.dal.mysql.plate.PlateGoodMapper;
import com.cf.imes.module.executor.dal.mysql.plate.PlateMapper;
import com.cf.imes.module.executor.enums.OrderItemType;
import com.cf.imes.module.executor.enums.OrderStatusEnum;
import com.cf.imes.module.executor.service.order.OrderInputProcessor;
import com.cf.imes.module.system.enums.ErrorCodeConstants;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import jakarta.annotation.Resource;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

import static com.cf.imes.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR;
import static com.cf.imes.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.cf.imes.framework.security.core.util.SecurityFrameworkUtils.getUserOrganId;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.*;
import static com.cf.imes.module.executor.enums.EsIndexEnum.ORDER_PLATE_MODEL;
import static com.cf.imes.module.system.enums.ErrorCodeConstants.*;
/**
 * 生产单板件 Service 实现类
 *
 * @author 晨丰科技
 */
@Service
@Validated
@Slf4j
public class PlateServiceImpl implements PlateService {

    @Resource
    private PlateMapper plateMapper;

    @Resource
    private OrderItemMapper orderItemMapper;

    @Resource
    private GoodsMapper goodsMapper;

    @Resource
    private PlanMapper planMapper;

    @Resource
    private OrderBodyMapper orderBodyMapper;

    @Resource
    private PlateGoodMapper plateGoodMapper;

    @Resource
    private OrderMapper orderMapper;


    @Resource
    private SnowflakeIdWorker3rd idWorker;

    @Resource
    private ElasticsearchClient elasticsearchClient;

    @Resource
    private OrderInputProcessor orderInputProcessor;

    @Resource
    private IdentifierGenerator identifierGenerator;

    private static final String FIELD_PLATE_ID = "plateId";
    private static final String FIELD_OG_MATERIAL = "og.material";
    private static final String FIELD_OG_BRAND = "og.brand";
    private static final String FIELD_OG_COLOR = "og.color";
    private static final String FIELD_OP_THICKNESS = "op.thickness";
    private static final String FIELD_OG_TEXTURE = "og.texture";

    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Override
    public Long createPlate(PlateSaveReqVO createReqVO) {
        // 插入
        PlateDO plate = BeanUtils.toBean(createReqVO, PlateDO.class);
        plateMapper.insert(plate);
        // 返回
        return plate.getId();
    }

    @Override
    public void updatePlate(PlateSaveReqVO updateReqVO) {
        // 校验存在
        validatePlateExists(updateReqVO.getId());
        // 更新
        PlateDO updateObj = BeanUtils.toBean(updateReqVO, PlateDO.class);
        plateMapper.updateById(updateObj);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deletePlate(List<Long> plateIds, Long planId) {

        if(CollUtil.isEmpty(plateIds)){
            return;
        }

        PlanDO planDO = planMapper.selectById(planId);

        AssertUtils.notEmpty(planDO,ORDER_PLAN_DATE_ERROR);

        List<PlateDO> plateDOS = plateMapper.selectBatchIds(plateIds);

        AssertUtils.notEmpty(plateDOS,REMAIN_PLATE_NOT_EXISTS);


        for (PlateDO plateDO : plateDOS) {

            if(!plateDO.getType().equals(OrderPlateTypeEnum.SELFINCREASINGBOARD.getType())){
                throw exception(PLATE_IS_SOURCE,plateDO.getPlateNo());
            }

            if(!plateDO.getIsCutted().equals(OrderPlateCutStatusEnum.NOCUTTING.getStatus())){

                throw exception(THIS_PLATE_IS_OPTIMIZE,plateDO.getPlateNo());
            }
        }


        List<Long> plateIdList = plateDOS.stream().map(PlateDO::getId).toList();

        List<Long> orderIds = plateDOS.stream().map(PlateDO::getOrderId).distinct().toList();

        List<Long> goodsIds = plateDOS.stream().map(PlateDO::getGoodsId).distinct().toList();


        List<OrderItemDO> orderItemDOS = orderItemMapper.selectPlateList(plateIdList, orderIds, getUserOrganId());

        List<Long> bodyIds = orderItemDOS.stream().map(OrderItemDO::getBodyId).distinct().toList();

        List<OrderBodyDO> orderBodyDOS = orderBodyMapper.selectBatchIds(bodyIds);

        orderBodyDOS.forEach(f->{
            int plateNum = orderItemDOS.stream().filter(o -> f.getId().equals(o.getBodyId())).toList().size();
            f.setPlateNum(f.getPlateNum() - plateNum);

        });

        orderBodyMapper.updateBatch(orderBodyDOS);

        // 删除小板ID
        plateMapper.deleteBatchIds(plateIdList);

        // 删除小板明细信息
        orderItemMapper.deleteByPlateId(plateIdList, orderIds, getUserOrganId());

        // 删除添加自增板时新增的大板ID
        List<Long> orderGoodsIdList = goodsMapper.selectInsertGoodsIds(orderIds, goodsIds, getUserOrganId());
        if(CollUtil.isNotEmpty(orderGoodsIdList)){
            goodsMapper.deleteBatchIds(orderGoodsIdList);
        }

        // 统计更新板件数量和面积
        computePlatePlanAndComputeOrderGoodsInfo(plateDOS.stream()
                .collect(Collectors.groupingBy(
                        PlateDO::getGoodsId,
                        Collectors.mapping(PlateDO::getId, Collectors.toList())
                )));
        computeOrderInfo(orderIds);

    }

    /**
     * 统计更新order_goods的小板数量和面积
     *
     * @param goodsPlateIdMap
     */
    public void computePlatePlanAndComputeOrderGoodsInfo(Map<Long, List<Long>> goodsPlateIdMap) {
        for (Map.Entry<Long, List<Long>> entry : goodsPlateIdMap.entrySet()) {
            Long orderGoodsId = entry.getKey();
            // 查询version
            GoodsDO goodsDO = goodsMapper.selectById(orderGoodsId);

            int version = goodsDO.getVersion();
            // 统计每个order_goods下的未排单面积，更新到order_goods中
            OrderPlanPlateNumAndAreaRespVO goodsPlateNumAndAreaPlanInfo = goodsMapper.selectPlannedPlateNumAndArea(orderGoodsId);
            int update = goodsMapper.update(new LambdaUpdateWrapper<GoodsDO>()
                    .eq(GoodsDO::getId, orderGoodsId)
                    .eq(GoodsDO::getVersion, version)
                    .set(GoodsDO::getPlannedPlateArea, goodsPlateNumAndAreaPlanInfo.getArea())
                    .set(GoodsDO::getPlannedPlateNum, goodsPlateNumAndAreaPlanInfo.getNum())
                    .set(GoodsDO::getVersion, version + 1));
            if (update == 0) {
                throw ServiceExceptionUtil.exception(com.cf.imes.module.executor.enums.ErrorCodeConstants.GOODS_PLATE_UPDATE_CONCURRENCY_ERROR, orderGoodsId);
            }
        }
    }

    /**
     * 统计更新orders的小板数量和面积
     *
     * @param orderIdList
     */
    public void computeOrderInfo(List<Long> orderIdList) {
        for (Long orderId : orderIdList) {
            // 统计每个orders下的未排单面积，更新到orders中
            OrderDO orderDO = orderMapper.selectById(orderId);
            OrderPlanPlateNumAndAreaRespVO orderPlateNumAndAreaPlanInfo = orderMapper.selectPlannedPlateNumAndArea(orderId);

            // 当前生产单下排单的板件数量
            Integer num = orderPlateNumAndAreaPlanInfo.getNum();

            int version = orderDO.getVersion();
            LambdaUpdateWrapper<OrderDO> updateWrapper = new LambdaUpdateWrapper<OrderDO>()
                    .eq(OrderDO::getId, orderId)
                    .eq(OrderDO::getVersion, version)
                    .set(OrderDO::getPlannedPlateArea, orderPlateNumAndAreaPlanInfo.getArea())
                    .set(OrderDO::getPlannedPlateNum, num)
                    .set(OrderDO::getVersion, version + 1);
            Integer orderDOStatus = orderDO.getStatus();
            // 更新生产单排单状态
            if (ObjectUtil.notEqual(orderDOStatus, OrderStatusEnum.IN_PRODUCTION.getStatus()) && ObjectUtil.notEqual(orderDOStatus, OrderStatusEnum.SORTED.getStatus())) {
                // 如果生产单下已经没有排单板件，更新生产单为新单
                if (num == 0) {
                    updateWrapper.set(OrderDO::getStatus, OrderStatusEnum.NEW_ORDER.getStatus());
                } else {
                    updateWrapper.set(OrderDO::getStatus, OrderStatusEnum.SORTED.getStatus());
                }
            }
            int update = orderMapper.update(updateWrapper);
            if (update == 0) {
                throw ServiceExceptionUtil.exception(com.cf.imes.module.executor.enums.ErrorCodeConstants.ORDER_PLATE_UPDATE_CONCURRENCY_ERROR, orderId);
            }
        }
    }

    /**
     * 拆分list，每个1000条
     *
     * @param dataList
     * @param <T>
     * @return
     */
    private <T> List<List<T>> batchProcess(List<T> dataList) {
        List<List<T>> resultList = new ArrayList<>();
        if (CollUtil.isEmpty(dataList)) {
            return resultList;
        }

        int total = dataList.size();
        for (int i = 0; i < total; i += 1000) {
            int end = Math.min(i + 1000, total);
            List<T> subList = dataList.subList(i, end);

            if (!subList.isEmpty()) {
                resultList.add(subList);
            }
        }
        return resultList;
    }

    private void validatePlateExists(Long id) {
        if (plateMapper.selectById(id) == null) {
            throw exception(REMAIN_PLATE_NOT_EXISTS);
        }
    }




    @Override
    public PageResult<PlateDO> getPlatePage(PlatePageReqVO pageReqVO) {
        return plateMapper.selectPage(pageReqVO);
    }


    @Override
    public PageResult<PlateGoodDO> getGoodsPlate(GoodsPlateFilterPageReqVO pageReqVO) {

        return plateGoodMapper.selectGoodsPage(pageReqVO, getUserOrganId());

    }




    @Override
    public PageResult<PlateResList> getOrderPlatePage(NoPlanPlatePageReqVO pageReqVO) {

        List<Integer> statusList = new ArrayList<>();
        statusList.add(OrderStatusEnum.NEW_ORDER.getStatus());
        statusList.add(OrderStatusEnum.IN_PRODUCTION.getStatus());
        statusList.add(OrderStatusEnum.SORTED.getStatus());

        Long organId = getUserOrganId();

        QueryWrapperX<OrderDO> queryWrapperX = new QueryWrapperX<>();
        queryWrapperX
                .eq("o.organ_id",organId)
                .eq("o.deleted",false)
                .in("o.status",statusList)
                .isNotNull("op.id")
                .eq("op.deleted",false);


        if(pageReqVO.getPlanId() != null){

            Long planId = pageReqVO.getPlanId();

            PlanDO planDO = planMapper.selectById(planId);

            AssertUtils.notEmpty(planDO, PLAN_NOT_EXISTS);

            List<OrderGoodsResp> goodsRespVOS = planMapper.selectPlanGoodsList(planId, organId);

            AssertUtils.notEmpty(goodsRespVOS,PLAN_NOT_EXISTS);

            List<String> material = goodsRespVOS.stream().map(OrderGoodsResp::getMaterial).distinct().toList();

            List<String> color = goodsRespVOS.stream().map(OrderGoodsResp::getColor).distinct().toList();

            List<String> brand = goodsRespVOS.stream().map(OrderGoodsResp::getBrand).distinct().toList();

            List<BigDecimal> thickness = goodsRespVOS.stream().map(OrderGoodsResp::getThickness).distinct().toList();

            List<Boolean> texture = goodsRespVOS.stream().map(OrderGoodsResp::getTexture).distinct().toList();


            // 混单
            if(planDO.getType().equals(PlanTypeEnum.MIXEDORDERPLAN.getType())){

                // 混单添加查询条件
                mixedInsertQuery(pageReqVO, planDO, material, thickness, queryWrapperX);

            }
            // 非混单
            else {

                // 非混单条件查询条件
                noMixedInsertQuery(pageReqVO, planDO, material, brand, color, thickness, texture, queryWrapperX);

            }
        }

        // 无排单ID时
        else {

            queryWrapperX
                    .likeIfPresent(FIELD_OG_MATERIAL,pageReqVO.getMaterial())
                    .likeIfPresent(FIELD_OG_BRAND,pageReqVO.getBrand())
                    .likeIfPresent(FIELD_OG_COLOR,pageReqVO.getColor())
                    .eqIfPresent(FIELD_OP_THICKNESS,pageReqVO.getThickness());
        }


        queryWrapperX
                .inIfPresent("op.goods_id",pageReqVO.getGoodsIdList())
                .likeIfPresent("o.id", pageReqVO.getOrderId() != null ? pageReqVO.getOrderId() : null)
                .likeIfPresent("op.id",pageReqVO.getPlateId())
                .likeIfPresent("op.name",pageReqVO.getPlateName())
                .likeIfPresent("op.plate_no",pageReqVO.getPlateNo())
                .likeIfPresent("op.custom_plate_no",pageReqVO.getCustomPlateNo())
                .betweenIfPresent("op.height", new BigDecimal[]{pageReqVO.getLongMinRang(), pageReqVO.getLongMaxRang()})
                .betweenIfPresent("op.width", new BigDecimal[]{pageReqVO.getWidthMinRang(), pageReqVO.getWidthMaxRang()})
                .betweenIfPresent(FIELD_OP_THICKNESS, new BigDecimal[]{pageReqVO.getThicknessMinRang(), pageReqVO.getThicknessMaxRang()})
                .eqIfPresent("op.texture",pageReqVO.getTexture())
                .eqIfPresent("op.is_special_shaped",pageReqVO.getIsSpecialShaped())
                .eqIfPresent("op.is_sculpt",pageReqVO.getIsSculpt())
                .eqIfPresent("op.is_row_hole",pageReqVO.getIsRowHole())
                .likeIfPresent("op.remark",pageReqVO.getRemark())
                .orderByDesc("o.id, op.id");


        Integer pageNo = (pageReqVO.getPageNo() - 1) * pageReqVO.getPageSize();


        List<PlateResList> plateResLists = orderMapper.selectNoPlanOrderPlateList(queryWrapperX,pageNo,pageReqVO.getPageSize(),organId);

        if(CollUtil.isEmpty(plateResLists)){

            return new PageResult<>();

        }

        queryWrapperX
                .groupBy("o.id");

        List<Long> plateCount = orderMapper.selectNoPlanOrderPlateCount(queryWrapperX,organId);

        long sum = plateCount.stream().mapToLong(Long::longValue).sum();

        return new PageResult<>(plateResLists, sum);

    }


    @Override
    @Transactional(rollbackFor = Exception.class) // 添加事务，异常则回滚所有导入
    public PlateImportRespVO importPlatesList(List<PlateSaveReqVO> importPlates, Long orderId) {
        if (CollUtil.isEmpty(importPlates)) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.RAW_GOODS_IMPORT_LIST_IS_EMPTY);
        }
        PlateImportRespVO respVO = PlateImportRespVO.builder().createPlates(new ArrayList<PlateSaveReqVO>())
                .updatePlates(new ArrayList<>()).failurePlates(new LinkedHashMap<>()).build();
        importPlates.forEach(plateSaveReqVO -> {
            try {
//                改成plateMapper.insertBatch()
                Long id = (long) plateMapper.insert(BeanUtils.toBean(plateSaveReqVO, PlateDO.class)
                        .setOrderId(orderId));
                respVO.getCreatePlates().add(plateSaveReqVO);
            } catch (ServiceException ex) {
                respVO.getFailurePlates().put(plateSaveReqVO.getName(), ex.getMessage());
            }
        });
        return respVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deletePlates(Set<Long> ids) {
        plateMapper.deleteBatchIds(ids);
    }

    @Override
    public List<PlateDO> getPlatesByOrderId(Long orderId) {
        List<PlateDO> plates = plateMapper.selectList(new LambdaQueryWrapper<PlateDO>().eq(PlateDO::getOrderId, orderId));
        return plates;
    }

    @Override
    public PageResult<PlateRespVO> getPlatePageByTerms(PlateTermsPageReqVO pageReqVO) {
        PageDTO<PlateRespVO> page = new PageDTO<>(pageReqVO.getPageNo(), pageReqVO.getPageSize());
        IPage<PlateRespVO> pageRes = plateMapper.selectProductList(page, pageReqVO.getOrderId(), pageReqVO.getRoomId(), pageReqVO.getBodyId(),getUserOrganId());
        return new PageResult<PlateRespVO>(pageRes.getRecords(), pageRes.getTotal());
    }

    @Override
    public void updatePlateByRawGoodsId(List<GoodsSaveReqVO> createReqVOS) {
        // 根据生产单id和goods_id查到数据，再更新goods_id
        createReqVOS.forEach(createReqVO -> {
//            plateMapper.update(null,
//                    new LambdaQueryWrapper<PlateDO>()
//                            .eq(PlateDO::getGoodsId, createReqVO.getRawGoodsId())
//                            .eq(PlateDO::getOrderId, createReqVO.getOrderId())
//                            .set(PlateDO::getGoodsId, createReqVO.getGoodsId()
//            );

        });

    }


    @SneakyThrows
    @Override
    public List<BodyPlateDetailVO> getPlateModelByPlateId(List<Long> bodyIds)  {
        List<BodyPlateIdDTO> list = plateMapper.selectJoinList(BodyPlateIdDTO.class, new MPJLambdaWrapperX<PlateDO>()
                .selectAs(PlateDO::getId, FIELD_PLATE_ID)
                .leftJoin(OrderItemDO.class, OrderItemDO::getPlateId, PlateDO::getId)
                .eq(OrderItemDO::getOrganId,getUserOrganId())
                .in(OrderItemDO::getBodyId, bodyIds)
                .select(OrderItemDO::getBodyId)
        );
        List<Long> plateIds = list.stream().map(BodyPlateIdDTO::getPlateId).collect(Collectors.toList());
        List<OrderModelDO> orderModelDOS = buildRespByPlateIds(plateIds, ORDER_PLATE_MODEL.getIndex());
        Map<Long, List<OrderModelDO>> map = orderModelDOS.stream().collect(Collectors.groupingBy(e -> {
            return list.stream().filter(f -> Objects.equals(f.getPlateId(), e.getPlateId())).map(BodyPlateIdDTO::getBodyId).findAny().orElse(null);
        }));

        List<BodyPlateDetailVO> bodyPlateDetailVOS = new ArrayList<>();
        List<List<List<Object>>> data = new ArrayList<>();
        map.entrySet().forEach(e->{
                bodyPlateDetailVOS.add(BodyPlateDetailVO.builder()
                        .orderModelList(e.getValue())
                        .bodyId(e.getKey())
                        .build()
                );
        });
        return bodyPlateDetailVOS;
    }



    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<InsertPlateRespVO> createNewPlate(List<OptimizationSavePlateReqVO> reqVO) {

        List<PlateDO> plateDOS = new ArrayList<>();

        List<OrderItemDO> orderItemDOS = new ArrayList<>();

        List<InsertPlateRespVO> insertPlateRespVOS = new ArrayList<>();

        List<OrderBodyNumVO> orderBodyNumVOS = new ArrayList<>();

        List<OrderModelDO> orderPlateModelDOS = new ArrayList<>();

        Long planId = Optional.ofNullable(reqVO.get(0).getPlanId()).orElseThrow(()-> exception(ORDER_PLAN_PLATE_ERROR));

        PlanDO planDO = planMapper.selectById(planId);
        AssertUtils.notEmpty(planDO,ORDER_PLAN_DATE_ERROR);

        List<Long> orderIds = reqVO.stream().map(OptimizationSavePlateReqVO::getOrderId).distinct().toList();

        // 查询排单下的orderGoodsId列表
        List<Long> goodsId = planMapper.selectPlanOrderGoodsId(planId,orderIds, getUserOrganId());

        List<GoodsDO> goodsDOS = goodsMapper.selectBatchIds(goodsId);

        Map<Long, OrderPlanPlateNumAndAreaRespVO> orderPlanPlateNumAndAreaRespVOMap = new HashMap<>();

        Map<Long, OrderPlanPlateNumAndAreaRespVO> orderGoodsPlanPlateNumAndAreaRespVOMap = new HashMap<>();

        // 组装新增数据
        reqVO.forEach(f->{

            Map<String,String> plateIdAndNo = new HashMap<>();

            Long orderId = f.getOrderId();

            GoodsDO goodsDO = goodsDOS.stream().filter(g -> g.getOrderId().equals(f.getOrderId())).toList().get(0);

            orderBodyNumVOS.add(OrderBodyNumVO.builder()
                    .bodyId(f.getBodyId())
                    .plateNum(f.getMultiple())
                    .build());

            // 生成板编号
            long obtainingTime = SnowflakeIdWorker3rd.obtainingTime();

            String plateNo = (obtainingTime) + Long.toString(idWorker.nextId()).substring(2);

            String remake1 = f.getRemake1() == null ? "" : f.getRemake1() + ";";

            String remake2 = f.getRemake2() == null ? "" : f.getRemake2();

            // 小板ID
            Long plateId = (Long) identifierGenerator.nextId(null);

            plateIdAndNo.put(plateId.toString(),plateNo);

            // 计算面积
            BigDecimal area = f.getWidth().multiply(f.getHeight()).movePointLeft(6).stripTrailingZeros();

            plateDOS.add(PlateDO.builder()
                    .id(plateId)
                    .orderId(orderId)
                    .name(f.getName())
                    .plateNo(plateNo)
                    .type(OrderPlateTypeEnum.SELFINCREASINGBOARD.getType())
                    .isOptimized(true)
                    .thickness(goodsDO.getThickness())
                    .goodsId(goodsDO.getId())
                    .holeFace(f.getPlaceHole())
                    .remark(remake1 + remake2)
                    .area(area)
                    .width(f.getWidth())
                    .height(f.getHeight())
                    .texture(f.getTexture())
                    .sealLeft(f.getSealLeft())
                    .sealRight(f.getSealRight())
                    .sealUp(f.getSealUp())
                    .sealDown(f.getSealDown())
                    .planId(f.getPlanId())
                    .build());


            // 生产单造型数据
            orderPlateModelDOS.add(OrderModelDO.builder()
                    .plateId(plateId)
                    .orderId(orderId)
                    .goodsId(goodsDO.getGoodsId())
                    .plateGoodsId(goodsDO.getId())
                    .texture(f.getTexture())
                    .boardType(OrderPlateTypeEnum.SELFINCREASINGBOARD.getDescription())
                    .build());


            // 生产单明细表新增数据
            orderItemDOS.add(OrderItemDO.builder()
                    .orderId(f.getOrderId())
                    .type(OrderItemType.BOARD.getCode())
                    .roomId(f.getRoomId())
                    .bodyId(f.getBodyId())
                    .plateId(plateId)
                    .build());

            insertPlateRespVOS.add(InsertPlateRespVO.builder()
                    .blockKey(f.getBlockKey())
                    .plateNo(plateIdAndNo)
                    .build());

            // 累加生产单板数和面积
            orderPlanPlateNumAndAreaRespVOMap.putIfAbsent(orderId, new OrderPlanPlateNumAndAreaRespVO(0, BigDecimal.ZERO));
            OrderPlanPlateNumAndAreaRespVO orderPlanPlateNumAndAreaRespVO = orderPlanPlateNumAndAreaRespVOMap.get(orderId);
            orderPlanPlateNumAndAreaRespVO.setArea(orderPlanPlateNumAndAreaRespVO.getArea().add(area)).setNum(orderPlanPlateNumAndAreaRespVO.getNum() + 1);

            // 累加订单材质板数和面积
            orderGoodsPlanPlateNumAndAreaRespVOMap.putIfAbsent(orderId, new OrderPlanPlateNumAndAreaRespVO(0, BigDecimal.ZERO));
            OrderPlanPlateNumAndAreaRespVO orderGoodsPlanPlateNumAndAreaRespVO = orderGoodsPlanPlateNumAndAreaRespVOMap.get(orderId);
            orderGoodsPlanPlateNumAndAreaRespVO.setArea(orderGoodsPlanPlateNumAndAreaRespVO.getArea().add(area)).setNum(orderGoodsPlanPlateNumAndAreaRespVO.getNum() + 1);
        });

        plateMapper.insertBatch(plateDOS);

        List<OrderBodyNumVO> numVOS = mergeOrderBody(orderBodyNumVOS);

        List<Long> bodyIds = numVOS.stream().map(OrderBodyNumVO::getBodyId).toList();


        List<OrderBodyDO> orderBodyDOS = orderBodyMapper.selectBatchIds(bodyIds);

        orderBodyDOS.forEach(f->{

            Integer plateNum = numVOS.stream()
                    .filter(n -> n.getBodyId().equals(f.getId()))
                    .map(OrderBodyNumVO::getPlateNum)
                    .findFirst().orElse(0);

            f.setPlateNum(f.getPlateNum() + plateNum);

        });

        orderBodyMapper.updateBatch(orderBodyDOS);

        orderItemMapper.insertBatch(orderItemDOS);

        // 更新生产单和材质板数量和面积
        updateOrdersPlanPlateNumAndArea(orderPlanPlateNumAndAreaRespVOMap);
        updateOrderGoodsPlanPlateNumAndArea(orderGoodsPlanPlateNumAndAreaRespVOMap);

        orderInputProcessor.batchSaveModel(orderPlateModelDOS);

        return insertPlateRespVOS;
    }

    /**
     * 更新生产单板件数量和面积
     *
     * @param orderPlanPlateNumAndAreaRespVOS
     */
    private void updateOrdersPlanPlateNumAndArea(Map<Long, OrderPlanPlateNumAndAreaRespVO> orderPlanPlateNumAndAreaRespVOS) {
        for (Map.Entry<Long, OrderPlanPlateNumAndAreaRespVO> entry : orderPlanPlateNumAndAreaRespVOS.entrySet()) {
            Long orderId = entry.getKey();
            OrderDO orderDO = orderMapper.selectById(orderId);

            OrderPlanPlateNumAndAreaRespVO orderPlateNumAndAreaPlanInfo = entry.getValue();

            int version = orderDO.getVersion();
            LambdaUpdateWrapper<OrderDO> updateWrapper = new LambdaUpdateWrapper<OrderDO>()
                    .eq(OrderDO::getId, orderId)
                    .eq(OrderDO::getVersion, version)
                    .set(OrderDO::getArea, orderPlateNumAndAreaPlanInfo.getArea().add(BigDecimal.valueOf(orderDO.getArea())))
                    .set(OrderDO::getPlannedPlateArea, orderPlateNumAndAreaPlanInfo.getArea())
                    .set(OrderDO::getPlannedPlateNum, orderPlateNumAndAreaPlanInfo.getNum())
                    .set(OrderDO::getPlateNum, orderPlateNumAndAreaPlanInfo.getNum() + orderDO.getPlateNum())
                    .set(OrderDO::getVersion, version + 1);
            int update = orderMapper.update(updateWrapper);
            if (update == 0) {
                throw ServiceExceptionUtil.exception(com.cf.imes.module.executor.enums.ErrorCodeConstants.ORDER_PLATE_UPDATE_CONCURRENCY_ERROR, orderId);
            }
        }
    }

    /**
     * 更新订单材质板件数量和面积
     *
     * @param orderGoodsPlanPlateNumAndAreaRespVOS
     */
    private void updateOrderGoodsPlanPlateNumAndArea(Map<Long, OrderPlanPlateNumAndAreaRespVO> orderGoodsPlanPlateNumAndAreaRespVOS) {
        for (Map.Entry<Long, OrderPlanPlateNumAndAreaRespVO> entry : orderGoodsPlanPlateNumAndAreaRespVOS.entrySet()) {
            Long orderGoodsId = entry.getKey();
            // 查询version
            GoodsDO goodsDO = goodsMapper.selectById(orderGoodsId);

            int version = goodsDO.getVersion();
            OrderPlanPlateNumAndAreaRespVO goodsPlateNumAndAreaPlanInfo = entry.getValue();
            int update = goodsMapper.update(new LambdaUpdateWrapper<GoodsDO>()
                    .eq(GoodsDO::getId, orderGoodsId)
                    .eq(GoodsDO::getVersion, version)
                    .set(GoodsDO::getArea, goodsPlateNumAndAreaPlanInfo.getArea().add(BigDecimal.valueOf(goodsDO.getArea())))
                    .set(GoodsDO::getPlannedPlateArea, goodsPlateNumAndAreaPlanInfo.getArea().add(BigDecimal.valueOf(goodsDO.getPlannedPlateArea())))
                    .set(GoodsDO::getPlannedPlateNum, goodsPlateNumAndAreaPlanInfo.getNum() + goodsDO.getPlannedPlateNum())
                    .set(GoodsDO::getPlateNum, goodsPlateNumAndAreaPlanInfo.getNum() + goodsDO.getPlateNum())
                    .set(GoodsDO::getVersion, version + 1));
            if (update == 0) {
                throw ServiceExceptionUtil.exception(com.cf.imes.module.executor.enums.ErrorCodeConstants.GOODS_PLATE_UPDATE_CONCURRENCY_ERROR, orderGoodsId);
            }
        }
    }



    public static List<OrderBodyNumVO> mergeOrderBody(List<OrderBodyNumVO> dataList) {
        if (dataList == null || dataList.isEmpty()) {
            return Collections.emptyList();
        }

        // 使用 HashMap 来聚合数据，key 为 filed1，value 为 TestData 对象
        Map<Long, Integer> mergedMap = new HashMap<>();
        for (OrderBodyNumVO data : dataList) {
            // 合并逻辑：将 filed2 的值累加
            mergedMap.merge(data.getBodyId(), data.getPlateNum(), Integer::sum);
        }

        // 将结果转换回 List<TestData>
        return mergedMap.entrySet().stream()
                .map(entry -> new OrderBodyNumVO(entry.getKey(), entry.getValue()))
                .toList();
    }






    private List<OrderModelDO> buildRespByPlateIds(Collection<Long> plateIds, String index) {

        List<FieldValue> fieldValues = plateIds.stream().map(FieldValue::of).toList();
        SearchRequest.Builder builder = new SearchRequest.Builder();
        builder.index(index);
        builder.query(q -> q.terms(b -> b.field(FIELD_PLATE_ID).terms(e->e.value(fieldValues))));
        builder.size(plateIds.size());
        try {
            SearchResponse<OrderModelDO> search = elasticsearchClient.search(builder.build(), OrderModelDO.class);
            List<Hit<OrderModelDO>> hits = search.hits().hits();
            if (CollUtil.isNotEmpty(hits)) {
                return hits.stream().map(Hit::source).collect(Collectors.toList());
            }
            return new ArrayList<>();
        } catch (IOException e) {
            log.error(e.getMessage());
            throw new ServiceException(INTERNAL_SERVER_ERROR);
        }
    }


    private void mixedInsertQuery(NoPlanPlatePageReqVO pageReqVO,
                                  PlanDO planDO,
                                  List<String> material,
                                  List<BigDecimal> thickness,
                                  QueryWrapperX<OrderDO> queryWrapperX) {



        if(Boolean.TRUE.equals(pageReqVO.getIsMixed())){
            throw exception(PLAN_IS_MIXED_ERROR);
        }

        // 相同材质和厚度
        if(planDO.getFilter().equals(MixConfigTypeEnum.SAMEMATERIALANDTHICKNESS.getType())){

            queryWrapperX
                    .inIfPresent(FIELD_OG_MATERIAL,material)
                    .likeIfPresent(FIELD_OG_BRAND,pageReqVO.getBrand())
                    .likeIfPresent(FIELD_OG_COLOR,pageReqVO.getColor())
                    .inIfPresent(FIELD_OP_THICKNESS,thickness);

        }
        // 相同厚度
        else {

            queryWrapperX
                    .likeIfPresent(FIELD_OG_MATERIAL,pageReqVO.getMaterial())
                    .likeIfPresent(FIELD_OG_BRAND,pageReqVO.getBrand())
                    .likeIfPresent(FIELD_OG_COLOR,pageReqVO.getColor())
                    .inIfPresent(FIELD_OP_THICKNESS,thickness);

        }


    }


    private void noMixedInsertQuery(NoPlanPlatePageReqVO pageReqVO,
                                    PlanDO planDO,
                                    List<String> material,
                                    List<String> brand,
                                    List<String> color,
                                    List<BigDecimal> thickness,
                                    List<Boolean> texture,
                                    QueryWrapperX<OrderDO> queryWrapperX) {

        // 是否开启混单
        if(Boolean.TRUE.equals(pageReqVO.getIsMixed())){

            if(!planDO.getStatus().equals(PlanStatusEnum.NOCUTTING.getStatus())){
                throw exception(PLAN_PLATE_IS_CUTTING);
            }

            // 相同材质和厚度 混单
            if(pageReqVO.getMixedType().equals(MixConfigTypeEnum.SAMEMATERIALANDTHICKNESS.getType())){
                queryWrapperX
                        .inIfPresent(FIELD_OG_MATERIAL, material)
                        .likeIfPresent(FIELD_OG_BRAND, pageReqVO.getBrand())
                        .likeIfPresent(FIELD_OG_COLOR, pageReqVO.getColor())
                        .inIfPresent(FIELD_OP_THICKNESS, thickness);

            }
            // 相同厚度 混单
            else{
                queryWrapperX
                        .likeIfPresent(FIELD_OG_MATERIAL, pageReqVO.getMaterial())
                        .likeIfPresent(FIELD_OG_BRAND, pageReqVO.getBrand())
                        .likeIfPresent(FIELD_OG_COLOR, pageReqVO.getColor())
                        .inIfPresent(FIELD_OP_THICKNESS, thickness);

            }
        }else {
            queryWrapperX
                    .inIfPresent(FIELD_OG_MATERIAL, material)
                    .inIfPresent(FIELD_OG_BRAND, brand)
                    .inIfPresent(FIELD_OG_COLOR, color)
                    .inIfPresent(FIELD_OP_THICKNESS, thickness)
                    .inIfPresent(FIELD_OG_TEXTURE, texture);

        }

    }


}