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

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Pair;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO;
import com.cf.imes.framework.common.enums.DeletedCodeEnum;
import com.cf.imes.framework.common.exception.ServiceException;
import com.cf.imes.framework.common.pojo.CommonResult;
import com.cf.imes.framework.common.pojo.PageParam;
import com.cf.imes.framework.common.pojo.PageResult;
import com.cf.imes.framework.common.util.Assert.AssertUtils;
import com.cf.imes.framework.common.util.json.JsonUtils;
import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.cf.imes.framework.mybatis.core.query.LambdaUpdateWrapperX;
import com.cf.imes.module.executor.controller.admin.assemblylist.vo.AssemblyListComponentPageReqVO;
import com.cf.imes.module.executor.controller.admin.assemblylist.vo.AssemblyListComponentFlatReqVO;
import com.cf.imes.module.executor.controller.admin.assemblylist.vo.AssemblyListComponentFlatRespVO;
import com.cf.imes.module.executor.controller.admin.order.vo.order.OrderPageReqVO;
import com.cf.imes.module.executor.controller.admin.order.vo.order.OrdersViewCadViewInfoRespVO;
import com.cf.imes.module.executor.controller.admin.ordercomponent.vo.AssemblyComponentChildPrintReqVO;
import com.cf.imes.module.executor.controller.admin.ordercomponent.vo.AssemblyComponentChildPrintRespVO;
import com.cf.imes.module.executor.controller.admin.ordercomponent.vo.OrderComponentRespVO;
import com.cf.imes.module.executor.controller.admin.ordercomponent.vo.OrderComponentTreeCompareVO;
import com.cf.imes.module.executor.controller.admin.ordercomponent.vo.OrdersTopComponentListReqVO;
import com.cf.imes.module.executor.controller.admin.plate.vo.OrderViewPartPageRespVO;
import com.cf.imes.module.executor.controller.admin.plate.vo.OrderViewPlatePageRespVO;
import com.cf.imes.module.executor.dal.dataobject.order.OrderDO;
import com.cf.imes.module.executor.dal.dataobject.orderItem.AssemblyComponentChildPrintItemDO;
import com.cf.imes.module.executor.dal.dataobject.orderItem.OrdersViewPartsPageDO;
import com.cf.imes.module.executor.dal.dataobject.orderItem.OrdersViewPlatesPageDO;
import com.cf.imes.module.executor.dal.dataobject.ordercomponent.OrderComponentDO;
import com.cf.imes.module.executor.dal.mysql.order.OrderMapper;
import com.cf.imes.module.executor.dal.mysql.orderItem.OrderItemMapper;
import com.cf.imes.module.executor.dal.mysql.ordercomponent.OrderComponentMapper;
import com.cf.imes.module.executor.enums.ordercomponent.OrderComponentProcessStatusEnum;
import com.cf.imes.module.system.api.assemblyconfig.AssemblyConfigApi;
import com.cf.imes.module.system.api.assemblyconfig.dto.AssemblyConfigRespDTO;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import static com.cf.imes.module.executor.enums.ErrorCodeConstants.ORDER_COMPONENT_ASSEMBLY_CONFIG_QUERY_ERROR;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.ORDER_COMPONENT_NOT_EXIST;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.ORDER_COMPONENT_NOT_PROCESS;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.ORDER_COMPONENT_PROCESSED_REPEAT;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.ORDER_COMPONENT_RESTORE_REPEAT;

/**
 * 装配清单 ServiceImpl 实现类
 *
 * @author Gqr
 * @since 2026/2/28 11:17
 */
@Service
public class AssemblyListServiceImpl implements AssemblyListService {
    @Resource
    private OrderComponentMapper orderComponentMapper;

    @Resource
    private OrderMapper orderMapper;

    @Resource
    private AssemblyConfigApi assemblyConfigApi;

    @Resource
    private OrderItemMapper orderItemMapper;

    @Override
    public PageResult<OrderDO> getMainOrderPage(OrderPageReqVO pageReqVO) {
        pageReqVO.setAssembly(true);
        IPage<OrderDO> page = new PageDTO<>(pageReqVO.getPageNo(), pageReqVO.getPageSize());
        // 1. 查询主单ID分页
        IPage<Long> pageResult = orderMapper.selectMainOrderIds(page, pageReqVO);
        Long pageResultTotal = pageResult.getTotal();

        if (pageResultTotal == 0) {
            return PageResult.empty();
        }

        List<Long> orderIds = pageResult.getRecords();
        // 2. 查询主单
        List<OrderDO> orderDOS = orderMapper.selectByIds(orderIds);
        if (CollUtil.isEmpty(orderDOS)) {
            return new PageResult<>(Collections.emptyList(), pageResultTotal);
        }

        // 保持分页顺序
        Map<Long, Integer> sortMap = IntStream.range(0, orderIds.size())
                .boxed()
                .collect(Collectors.toMap(orderIds::get, Function.identity()));

        orderDOS.sort(Comparator.comparing(o -> sortMap.get(o.getId())));

        // 3. 查询子单
        List<Long> childIdList = orderMapper.selectChildIdList(pageReqVO, orderIds);
        if (CollUtil.isEmpty(childIdList)) {
            return new PageResult<>(orderDOS, pageResultTotal);
        }

        List<OrderDO> childList = orderMapper.selectByIds(childIdList);
        if (CollUtil.isEmpty(childList)) {
            return new PageResult<>(orderDOS, pageResultTotal);
        }

        // 4. parentId分组
        Map<Long, List<OrderDO>> childMap = childList.stream()
                .collect(Collectors.groupingBy(OrderDO::getParentId));

        // 5. 挂载子单
        for (OrderDO order : orderDOS) {
            order.setChild(childMap.get(order.getId()));
        }

        return new PageResult<>(orderDOS, pageResultTotal);
    }

    @Override
    public List<OrderComponentRespVO> getComponentList(AssemblyListComponentPageReqVO reqVO) {
        Set<Long> componentIds = reqVO.getComponentIds();
        List<Long> orderIds = reqVO.getOrderIds();
        if (CollUtil.isEmpty(orderIds)
                || (CollUtil.isEmpty(componentIds) && reqVO.getComponentId() == null
                && CharSequenceUtil.isEmpty(reqVO.getName()))) {
            return Collections.emptyList();
        }

        // 按部件 ID 或名称查询时，仅展示命中的节点，不展开其所在的整棵树。
        if (reqVO.getComponentId() != null || CharSequenceUtil.isNotEmpty(reqVO.getName())) {
            List<OrderComponentDO> components = orderComponentMapper.getComponentsByIdOrNameAndProcessStatus(
                    orderIds, componentIds, reqVO.getComponentId(), reqVO.getName(), reqVO.getProcessStatus());
            return BeanUtil.copyToList(components, OrderComponentRespVO.class);
        }

        // 第一步：按部件 ID、名称及加工状态查询符合条件的 top_id。
        List<Long> topIds = orderComponentMapper.getTopIdsByComponentAndProcessStatus(
                orderIds, componentIds, reqVO.getComponentId(), reqVO.getName(),
                reqVO.getProcessStatus());
        if (CollUtil.isEmpty(topIds)) {
            return Collections.emptyList();
        }

        // 第二步：按 top_id 查询整棵树的所有节点。
        List<OrderComponentDO> allNodesOnTopIds = orderComponentMapper.selectList(new LambdaQueryWrapperX<OrderComponentDO>()
                .in(OrderComponentDO::getTopId, topIds)
                .in(OrderComponentDO::getOrderId, orderIds)
                .select(OrderComponentDO::getId, OrderComponentDO::getPid, OrderComponentDO::getName, OrderComponentDO::getProcessStatus,
                        OrderComponentDO::getExtraProcessStatus, OrderComponentDO::getWidth, OrderComponentDO::getHeight, OrderComponentDO::getDepth));

        // 遍历处理状态
        for (OrderComponentDO orderComponent : allNodesOnTopIds) {
            // extraProcessStatus不为空时替代processStatus
            if (ObjectUtil.isNotEmpty(orderComponent.getExtraProcessStatus())) {
                orderComponent.setProcessStatus(orderComponent.getExtraProcessStatus());
            }
        }
        return BeanUtil.copyToList(allNodesOnTopIds, OrderComponentRespVO.class);
    }

    @Override
    public List<AssemblyListComponentFlatRespVO> getComponentFlatList(
            AssemblyListComponentFlatReqVO reqVO) {
        List<OrderComponentDO> components =
                orderComponentMapper.selectAllForFlatList(reqVO.getOrderIds(), reqVO.getProcessStatus());
        if (CollUtil.isEmpty(components)) {
            return Collections.emptyList();
        }

        // 根据父子关系和雪花 ID 生成类似 1、1-1、1-2 的显示序号。
        // 底层优先；同一层按雪花 ID 倒序，明确保留 1-1、1-2 这类层级顺序信息。
        components.sort(Comparator.comparingInt(OrderComponentDO::getLevel)
                .reversed()
                .thenComparing(OrderComponentDO::getId, Comparator.reverseOrder()));

        Map<String, List<OrderComponentDO>> grouped = components.stream()
                .collect(Collectors.groupingBy(OrderComponentDO::getName,
                        LinkedHashMap::new, Collectors.toList()));

        return grouped.values().stream().map(list -> {
            // 同名合并时以更低层级（level 数值更大）的节点为准；同层取 ID 更大的节点。
            OrderComponentDO representative = list.stream()
                    .max(Comparator.comparingInt(OrderComponentDO::getLevel)
                            .thenComparing(OrderComponentDO::getId))
                    .orElseThrow();
            AssemblyListComponentFlatRespVO result = BeanUtil.copyProperties(
                    representative, AssemblyListComponentFlatRespVO.class);
            result.setCount(list.size());
            // 数据库 level 从 0 开始，接口返回层级从 1 开始。
            result.setLevel(list.stream()
                    .map(OrderComponentDO::getLevel)
                    .distinct()
                    .sorted(Comparator.reverseOrder())
                    .map(level -> String.valueOf(level + 1))
                    .collect(Collectors.joining(",")));
            result.setComponentIds(list.stream()
                    .map(OrderComponentDO::getId)
                    .toList());
            return result;
        }).toList();
    }

    @Override
    public List<AssemblyComponentChildPrintRespVO> getDirectChildComponentList(AssemblyComponentChildPrintReqVO reqVO) {
        List<Long> componentIds = new ArrayList<>(new LinkedHashSet<>(
                Optional.ofNullable(reqVO.getComponentIds()).orElseGet(Collections::emptyList)));
        if (CollUtil.isEmpty(componentIds)) {
            return Collections.emptyList();
        }
        // 查询入参部件的信息
        Set<Long> queryIds = new LinkedHashSet<>(componentIds);
        List<OrderComponentDO> parentComponents = orderComponentMapper.selectList(
                new LambdaQueryWrapperX<OrderComponentDO>()
                        .in(OrderComponentDO::getId, queryIds)
                        .eq(OrderComponentDO::getDeleted, DeletedCodeEnum.NOT_DELETED.getStatus())
                        .select(
                                OrderComponentDO::getId,
                                OrderComponentDO::getPid,
                                OrderComponentDO::getOrderId,
                                OrderComponentDO::getName,
                                OrderComponentDO::getWidth,
                                OrderComponentDO::getHeight,
                                OrderComponentDO::getDepth,
                                OrderComponentDO::getProcessStatus,
                                OrderComponentDO::getExtraProcessStatus
                        )
        );

        /*
         * 若数量不一致，说明存在以下任一情况：
         * 1. 部件不存在；
         * 2. 部件已删除；
         * 3. 部件不属于前端传入的订单范围。
         */
        if (parentComponents.size() != queryIds.size()) {
            throw new ServiceException(ORDER_COMPONENT_NOT_EXIST);
        }

        if (CollUtil.isNotEmpty(reqVO.getProcessStatus())) {
            LambdaQueryWrapperX<OrderComponentDO> filteredParentQuery =
                    new LambdaQueryWrapperX<OrderComponentDO>()
                            .in(OrderComponentDO::getId, queryIds)
                            .eq(OrderComponentDO::getDeleted, DeletedCodeEnum.NOT_DELETED.getStatus())
                            .selectX(
                                    OrderComponentDO::getId,
                                    OrderComponentDO::getPid,
                                    OrderComponentDO::getOrderId,
                                    OrderComponentDO::getName,
                                    OrderComponentDO::getWidth,
                                    OrderComponentDO::getHeight,
                                    OrderComponentDO::getDepth,
                                    OrderComponentDO::getProcessStatus,
                                    OrderComponentDO::getExtraProcessStatus
                            );
            appendProcessStatusCondition(filteredParentQuery, reqVO.getProcessStatus());
            parentComponents = orderComponentMapper.selectList(filteredParentQuery);
            if (CollUtil.isEmpty(parentComponents)) {
                return Collections.emptyList();
            }

            Set<Long> matchedParentIds = parentComponents.stream()
                    .map(OrderComponentDO::getId)
                    .collect(Collectors.toSet());
            componentIds = componentIds.stream()
                    .filter(matchedParentIds::contains)
                    .toList();
        }

        // 只有顶级节点才允许使用 extraProcessStatus；非顶级节点始终返回自身 processStatus。
        for (OrderComponentDO parentComponent : parentComponents) {
            if (Objects.equals(parentComponent.getPid(), OrderComponentDO.PARENT_ID_ROOT)
                    && ObjectUtil.isNotEmpty(parentComponent.getExtraProcessStatus())) {
                parentComponent.setProcessStatus(parentComponent.getExtraProcessStatus());
            }
        }

        Map<Long, OrderComponentDO> componentDOMap = parentComponents.stream()
                .collect(Collectors.toMap(OrderComponentDO::getId, Function.identity()));
        List<Long> orderIds = parentComponents.stream()
                .map(OrderComponentDO::getOrderId)
                .distinct()
                .toList();

        Map<Long, AssemblyComponentChildPrintRespVO> parentMap =
                createPrintParentMap(componentIds, componentDOMap);
        if (CollUtil.isNotEmpty(componentIds)) {
            LambdaQueryWrapperX<OrderComponentDO> childQuery =
                    new LambdaQueryWrapperX<OrderComponentDO>()
                            .in(OrderComponentDO::getPid, componentIds)
                            .in(OrderComponentDO::getOrderId, orderIds)
                            .eq(OrderComponentDO::getDeleted, DeletedCodeEnum.NOT_DELETED.getStatus())
                            .orderByAsc(OrderComponentDO::getId)
                            .selectX(
                                    OrderComponentDO::getId,
                                    OrderComponentDO::getPid,
                                    OrderComponentDO::getName,
                                    OrderComponentDO::getWidth,
                                    OrderComponentDO::getHeight,
                                    OrderComponentDO::getDepth,
                                    OrderComponentDO::getRoomName,
                                    OrderComponentDO::getBodyName,
                                    OrderComponentDO::getProcessStatus,
                                    OrderComponentDO::getExtraProcessStatus
                            );
            appendProcessStatusCondition(childQuery, reqVO.getProcessStatus());
            List<OrderComponentDO> childComponents = orderComponentMapper.selectList(childQuery);

            for (OrderComponentDO child : childComponents) {
                AssemblyComponentChildPrintRespVO parent =
                        parentMap.get(child.getPid());

                if (parent != null) {
                    // false：子部件不创建 children
                    parent.getChildren().add(convertPrintComponent(child, false));
                }
            }
        }

        {
            /*
             * 板件数量在业务上固定为 1。
             * SQL 已根据 order_item.comp_id 取得板件归属部件，
             * 并根据 order_item.body_id 取得实际房间、柜体。
             */
            List<AssemblyComponentChildPrintItemDO> plates =
                    orderItemMapper.selectAssemblyComponentPrintPlates(
                    orderIds, new LinkedHashSet<>(componentIds));

            /*
             * 配件可能对应多条 order_item 明细。
             * 先查明细，再在内存中按“部件 + 柜体 + 配件”聚合数量。
             */
            List<AssemblyComponentChildPrintItemDO> partRows =
                    orderItemMapper.selectAssemblyComponentPrintParts(
                    orderIds, new LinkedHashSet<>(componentIds));

            List<AssemblyComponentChildPrintItemDO> parts =
                    mergeAssemblyComponentPrintParts(partRows);

            for (AssemblyComponentChildPrintItemDO plate : plates) {
                AssemblyComponentChildPrintRespVO parent =
                        parentMap.get(plate.getCompId());

                if (parent != null) {
                    parent.getChildren().add(convertPrintItem(plate));
                }
            }

            for (AssemblyComponentChildPrintItemDO part : parts) {
                AssemblyComponentChildPrintRespVO parent =
                        parentMap.get(part.getCompId());

                if (parent != null) {
                    parent.getChildren().add(convertPrintItem(part));
                }
            }
        }

        return new ArrayList<>(parentMap.values());
    }

    /**
     * 将加工状态转换为部件查询条件。
     * 0、3 仅匹配顶级节点的 extraProcessStatus；1、2 匹配节点的 processStatus。
     */
    private void appendProcessStatusCondition(LambdaQueryWrapperX<OrderComponentDO> query,
                                              List<Integer> processStatus) {
        if (CollUtil.isEmpty(processStatus)) {
            return;
        }

        List<Integer> topStatuses = processStatus.stream()
                .filter(status -> Objects.equals(status, OrderComponentProcessStatusEnum.NOT_PROCESS.getStatus())
                        || Objects.equals(status, OrderComponentProcessStatusEnum.PART_PROCESSED.getStatus()))
                .toList();
        List<Integer> commonStatuses = processStatus.stream()
                .filter(status -> Objects.equals(status, OrderComponentProcessStatusEnum.UNPROCESSED.getStatus())
                        || Objects.equals(status, OrderComponentProcessStatusEnum.PROCESSED.getStatus()))
                .toList();

        query.and(wrapper -> {
            if (CollUtil.isNotEmpty(topStatuses)) {
                wrapper.eq(OrderComponentDO::getPid, OrderComponentDO.PARENT_ID_ROOT)
                        .in(OrderComponentDO::getExtraProcessStatus, topStatuses);
            }
            if (CollUtil.isNotEmpty(topStatuses) && CollUtil.isNotEmpty(commonStatuses)) {
                wrapper.or();
            }
            if (CollUtil.isNotEmpty(commonStatuses)) {
                wrapper.in(OrderComponentDO::getProcessStatus, commonStatuses)
                        .and(statusWrapper -> statusWrapper
                                .ne(OrderComponentDO::getPid, OrderComponentDO.PARENT_ID_ROOT)
                                .or()
                                .isNull(OrderComponentDO::getExtraProcessStatus));
            }
        });
    }

    /**
     * 按请求 ID 顺序创建父节点。
     *
     * 父节点是树的唯一可展开层级，因此统一初始化 children。
     * 同一部件在不同查询类型中调用本方法时，会创建不同的 RespVO 实例。
     */
    private Map<Long, AssemblyComponentChildPrintRespVO> createPrintParentMap(
            List<Long> componentIds,
            Map<Long, OrderComponentDO> componentDOMap) {

        Map<Long, AssemblyComponentChildPrintRespVO> result = new LinkedHashMap<>();

        for (Long componentId : componentIds) {
            OrderComponentDO component = componentDOMap.get(componentId);
            if (component != null) {
                // true：父节点才初始化 children
                result.put(componentId, convertPrintComponent(component, true));
            }
        }

        return result;
    }

    /**
     * 部件节点转换。
     *
     * 部件原始字段是：width、height、depth；
     * 打印展示统一为：length、width、thickness。
     *
     * @param hasChildren true 表示父节点，初始化 children；
     *                    false 表示子部件，children 必须为 null。
     */
    private AssemblyComponentChildPrintRespVO convertPrintComponent(
            OrderComponentDO source, boolean hasChildren) {

        AssemblyComponentChildPrintRespVO target = new AssemblyComponentChildPrintRespVO();
        target.setId(source.getId());
        target.setName(source.getName());
        target.setLength(toBigDecimal(source.getHeight()));
        target.setWidth(toBigDecimal(source.getWidth()));
        target.setThickness(toBigDecimal(source.getDepth()));
        target.setRoomName(source.getRoomName());
        target.setBodyName(source.getBodyName());
        target.setProcessStatus(source.getProcessStatus());

        // 仅父节点存在 children；叶子子部件明确设置为 null。
        target.setChildren(hasChildren ? new ArrayList<>() : null);
        return target;
    }

    /**
     * 板件、配件节点转换。
     *
     * 板件和配件均为叶子节点，不设置 children。
     * JsonInclude(NON_NULL) 会使响应 JSON 中不输出 children 字段。
     */
    private AssemblyComponentChildPrintRespVO convertPrintItem(
            AssemblyComponentChildPrintItemDO source) {

        AssemblyComponentChildPrintRespVO target = new AssemblyComponentChildPrintRespVO();
        target.setId(source.getId());
        target.setName(source.getName());
        target.setLength(source.getLength());
        target.setWidth(source.getWidth());
        target.setThickness(source.getThickness());
        target.setQuantity(source.getQuantity());
        target.setRoomName(source.getRoomName());
        target.setBodyName(source.getBodyName());
        return target;
    }

    private BigDecimal toBigDecimal(Double value) {
        return value == null ? null : BigDecimal.valueOf(value);
    }

    /**
     * 配件明细内存聚合。
     *
     * 分组维度：
     * - compId：所属部件；
     * - bodyId：实际所属柜体；
     * - id：配件 ID。
     *
     * 同一配件在不同柜体、房间中出现时，不应合并；
     * 同一部件、同一柜体下存在多条相同配件明细时，数量需要累加。
     */
    private List<AssemblyComponentChildPrintItemDO> mergeAssemblyComponentPrintParts(
            List<AssemblyComponentChildPrintItemDO> rows) {

        if (CollUtil.isEmpty(rows)) {
            return Collections.emptyList();
        }

        Map<String, AssemblyComponentChildPrintItemDO> mergedMap = new LinkedHashMap<>();

        for (AssemblyComponentChildPrintItemDO row : rows) {
            // 同一部件、同一柜体、同一配件才合并数量
            String key = row.getCompId() + "_" + row.getBodyId() + "_" + row.getId();

            AssemblyComponentChildPrintItemDO merged = mergedMap.computeIfAbsent(key, ignored -> {
                AssemblyComponentChildPrintItemDO target = new AssemblyComponentChildPrintItemDO();
                target.setCompId(row.getCompId());
                target.setBodyId(row.getBodyId());
                target.setId(row.getId());
                target.setName(row.getName());
                target.setLength(row.getLength());
                target.setWidth(row.getWidth());
                target.setThickness(row.getThickness());
                target.setRoomName(row.getRoomName());
                target.setBodyName(row.getBodyName());
                target.setQuantity(BigDecimal.ZERO);
                return target;
            });

            BigDecimal quantity = row.getQuantity() == null
                    ? BigDecimal.ZERO
                    : row.getQuantity();

            merged.setQuantity(merged.getQuantity().add(quantity));
        }

        return new ArrayList<>(mergedMap.values());
    }

    /**
     * 根据装配设置计算部件节点的加工状态
     *
     * @param topComponentList
     */
    private List<OrderComponentTreeCompareVO> calculateProcessingStatusAccordingToAssemblyConfig(List<OrderComponentDO> topComponentList) {
        // 构建树
        List<OrderComponentTreeCompareVO> orderComponentTreeRespVOS = buildTree(topComponentList);

        // 查询对应的装配设置
        List<String> topComponentNames = orderComponentTreeRespVOS.stream().map(OrderComponentTreeCompareVO::getName).distinct().toList();

        // 根据名称查询组织装配设置
        if (CollUtil.isEmpty(topComponentNames)) {
            return orderComponentTreeRespVOS;
        }
        CommonResult<List<AssemblyConfigRespDTO>> assemblyConfigByComponentNameListResult = assemblyConfigApi.getAssemblyConfigByPartNameList(topComponentNames);
        if (assemblyConfigByComponentNameListResult.isError()) {
            throw new ServiceException(ORDER_COMPONENT_ASSEMBLY_CONFIG_QUERY_ERROR);
        }
        List<AssemblyConfigRespDTO> assemblyConfigByComponentNameList = assemblyConfigByComponentNameListResult.getData();

        // 构造name+结构hash的索引Map
        Map<Pair<String, String>, String> configMap = assemblyConfigByComponentNameList.stream()
                .collect(Collectors.toMap(
                        dto -> new Pair<>(dto.getComponentName(), dto.getStructureHash()),
                        AssemblyConfigRespDTO::getStructureJson,
                        (v1, v2) -> v1   // 如果重复保留第一个
                ));

        // 从当前树的顶级中匹配name+hash，匹配上的存id：json用于解析加工状态
        Map<Long, String> result = orderComponentTreeRespVOS.stream()
                .map(vo -> {
                    String structureJson = configMap.get(
                            new Pair<>(vo.getName(), vo.getStructureHash())
                    );
                    return structureJson == null
                            ? null
                            : Map.entry(vo.getId(), structureJson);
                })
                .filter(Objects::nonNull)
                .collect(Collectors.toMap(
                        Map.Entry::getKey,
                        Map.Entry::getValue
                ));

        // 解压json，逐级解析加工信息
        for (OrderComponentTreeCompareVO compareVO : orderComponentTreeRespVOS) {
            String structureZipJson = result.get(compareVO.getId());
            if (CharSequenceUtil.isNotEmpty(structureZipJson)) {
                // json解析出配置结构
                String structureJson = JsonUtils.unzipString(structureZipJson);
                OrderComponentTreeCompareVO structure = JSON.parseObject(structureJson, OrderComponentTreeCompareVO.class);
                // 把结构上的加工状态赋值到结果上
                processRecursive(structure, compareVO);
            }
        }

        return orderComponentTreeRespVOS;
    }

    /**
     * 构建树
     *
     * @param list
     * @return
     */
    private List<OrderComponentTreeCompareVO> buildTree(List<OrderComponentDO> list) {
        if (list == null || list.isEmpty()) return Collections.emptyList();

        Map<Long, OrderComponentTreeCompareVO> map = new HashMap<>(list.size());
        List<OrderComponentTreeCompareVO> roots = new ArrayList<>();

        // 1、初始化节点
        for (OrderComponentDO node : list) {
            OrderComponentTreeCompareVO vo = new OrderComponentTreeCompareVO();
            vo.setName(node.getName());
            vo.setChildren(new ArrayList<>());
            vo.setProcess(true);
            vo.setProcessStatus(node.getProcessStatus());
            vo.setId(node.getId());
            vo.setPid(node.getPid());
            vo.setLevel(node.getLevel());
            map.put(node.getId(), vo);
        }

        // 2、组装树 + 设置 sourceComponentId
        for (OrderComponentDO node : list) {
            OrderComponentTreeCompareVO vo = map.get(node.getId());
            if (node.getPid() == 0) {
                roots.add(vo);
            } else {
                OrderComponentTreeCompareVO parent = map.get(node.getPid());
                if (parent != null) parent.getChildren().add(vo);
            }
        }

        // 3、递归排序 + 生成 hash
        for (OrderComponentTreeCompareVO root : roots) {
            computeHashRecursively(root);
        }

        return roots;
    }

    /**
     * 递归排序 children + 生成结构 hash
     *
     * @param node
     */
    private void computeHashRecursively(OrderComponentTreeCompareVO node) {
        List<OrderComponentTreeCompareVO> children = node.getChildren();
        if (children != null && !children.isEmpty()) {
            // 按 name 排序保证 hash 稳定
            children.sort(Comparator.comparing(OrderComponentTreeCompareVO::getName));

            // 2. 递归子节点排序
            for (OrderComponentTreeCompareVO child : children) {
                computeHashRecursively(child);
            }
        }
        // 生成结构字符串并 hash
        String structureStr = buildStructureString(node);
        node.setStructureHash(DigestUtil.sha256Hex(structureStr));
        // 默认是加工的
        node.setProcess(true);
    }

    /**
     * 构建结构字符串（name + children）
     *
     * @param node
     * @return
     */
    private String buildStructureString(OrderComponentTreeCompareVO node) {
        StringBuilder sb = new StringBuilder();
        sb.append(node.getName());

        List<OrderComponentTreeCompareVO> children = node.getChildren();
        if (children != null && !children.isEmpty()) {
            sb.append("(");
            for (OrderComponentTreeCompareVO child : children) {
                sb.append(buildStructureString(child));
            }
            sb.append(")");
        }
        return sb.toString();
    }

    /**
     * 逐级对比：当b状态不是已加工时，a的process是false，b的状态才是不加工
     *
     * @param a 配置
     * @param b 部件数据
     */
    private void processRecursive(
            OrderComponentTreeCompareVO a,
            OrderComponentTreeCompareVO b) {

        // 1️⃣ 赋值当前层
        if (ObjectUtil.notEqual(OrderComponentProcessStatusEnum.PROCESSED.getStatus(), b.getProcessStatus())) {
            b.setProcessStatus(a.isProcess() ? OrderComponentProcessStatusEnum.UNPROCESSED.getStatus() : OrderComponentProcessStatusEnum.NOT_PROCESS.getStatus());
        }

        // 2️⃣ 处理子节点
        List<OrderComponentTreeCompareVO> aChildren = a.getChildren();
        List<OrderComponentTreeCompareVO> bChildren = b.getChildren();

        if (aChildren == null || bChildren == null) {
            return;
        }

        // 把A子节点转成Map，加速匹配
        Map<String, OrderComponentTreeCompareVO> aChildMap =
                new HashMap<>(aChildren.size());

        for (OrderComponentTreeCompareVO aChild : aChildren) {
            if (aChild != null) {
                aChildMap.put(aChild.getName(), aChild);
            }
        }

        for (OrderComponentTreeCompareVO bChild : bChildren) {
            if (bChild == null) {
                continue;
            }
            OrderComponentTreeCompareVO aChild =
                    aChildMap.get(bChild.getName());

            if (aChild != null) {
                processRecursive(aChild, bChild);
            }
        }
    }

    /**
     * 树形扁平化
     *
     * @param node
     * @param result
     */
    private void flatTree(OrderComponentTreeCompareVO node,
                          List<OrderComponentRespVO> result) {

        if (node == null) {
            return;
        }

        // 1️⃣ 先加入自己
        OrderComponentRespVO orderComponentTreeRespVO = new OrderComponentRespVO();
        orderComponentTreeRespVO.setId(node.getId());
        orderComponentTreeRespVO.setName(node.getName());
        orderComponentTreeRespVO.setPid(node.getPid());
        orderComponentTreeRespVO.setProcessStatus(node.getProcessStatus());
        result.add(orderComponentTreeRespVO);

        // 2️⃣ 再处理子节点
        List<OrderComponentTreeCompareVO> children = node.getChildren();
        if (children == null || children.isEmpty()) {
            return;
        }

        for (OrderComponentTreeCompareVO child : children) {
            flatTree(child, result);
        }
    }

    @Override
    public void processComponent(Long id) {
        // 未加工 -> 加工
        handleComponentProcessStatus(id, OrderComponentProcessStatusEnum.UNPROCESSED.getStatus(), OrderComponentProcessStatusEnum.PROCESSED.getStatus());
    }

    @Override
    public void restoreComponent(Long id) {
        // 加工 -> 未加工
        handleComponentProcessStatus(id, OrderComponentProcessStatusEnum.PROCESSED.getStatus(), OrderComponentProcessStatusEnum.UNPROCESSED.getStatus());
    }

    /**
     * 处理部件加工状态
     *
     * 规则：
     * 1、顶级部件：
     *    - 自身加工       => extraProcessStatus = null
     *    - 自身未加工：
     *          存在已加工子级 => PART_PROCESSED
     *          否则         => null
     *
     * 2、子级部件：
     *    - 任意子级已加工 => 顶级 PART_PROCESSED
     *    - 所有子级未加工 => 顶级 null
     *
     * 3、子级自身 processStatus 正常更新
     */
    private void handleComponentProcessStatus(Long id,
                                              Integer sourceProcessStatus,
                                              Integer targetProcessStatus) {

        // =========================
        // 1、查询和校验当前部件
        // =========================
        OrderComponentDO componentDO =
                orderComponentMapper.selectById(id);

        AssertUtils.notEmpty(
                componentDO,
                ORDER_COMPONENT_NOT_EXIST
        );

        // 不加工不可操作
        AssertUtils.equals(
                componentDO.getExtraProcessStatus(),
                OrderComponentProcessStatusEnum.NOT_PROCESS.getStatus(),
                ORDER_COMPONENT_NOT_PROCESS
        );

        // =========================
        // 2、状态校验
        // =========================

        // 当前准备变成“已加工”
        boolean toBeProcessed =
                Objects.equals(
                        targetProcessStatus,
                        OrderComponentProcessStatusEnum.PROCESSED.getStatus()
                );

        // 当前准备变成“未加工”
        boolean toBeUnProcessed =
                Objects.equals(
                        targetProcessStatus,
                        OrderComponentProcessStatusEnum.UNPROCESSED.getStatus()
                );

        // 防重复加工
        if (toBeProcessed) {

            AssertUtils.equals(
                    componentDO.getProcessStatus(),
                    OrderComponentProcessStatusEnum.PROCESSED.getStatus(),
                    ORDER_COMPONENT_PROCESSED_REPEAT
            );
        }

        // 防重复恢复
        if (toBeUnProcessed) {

            AssertUtils.equals(
                    componentDO.getProcessStatus(),
                    OrderComponentProcessStatusEnum.UNPROCESSED.getStatus(),
                    ORDER_COMPONENT_RESTORE_REPEAT
            );
        }

        Long organId = componentDO.getOrganId();
        Long orderId = componentDO.getOrderId();
        Long topId = componentDO.getTopId();

        // =========================
        // 3、查询顶级部件
        // =========================
        OrderComponentDO topComponentDO =
                orderComponentMapper.selectById(topId);

        AssertUtils.notEmpty(
                topComponentDO,
                ORDER_COMPONENT_NOT_EXIST
        );

        // =========================
        // 4、更新当前节点状态
        // =========================
        int updateCount = orderComponentMapper.update(
                null,
                new LambdaUpdateWrapperX<OrderComponentDO>()
                        .eq(OrderComponentDO::getId, id)
                        .eq(OrderComponentDO::getOrderId, orderId)
                        .eq(OrderComponentDO::getOrganId, organId)
                        .eq(OrderComponentDO::getProcessStatus,
                                sourceProcessStatus)
                        .eq(OrderComponentDO::getDeleted,
                                DeletedCodeEnum.NOT_DELETED.getStatus())
                        .set(OrderComponentDO::getProcessStatus,
                                targetProcessStatus)
        );

        if (updateCount <= 0) {
            return;
        }

        // =========================
        // 5、重新查询整棵树（拿最新状态）
        // =========================
        List<OrderComponentDO> topComponentList =
                orderComponentMapper.selectList(
                        new LambdaQueryWrapperX<OrderComponentDO>()
                                .eq(OrderComponentDO::getTopId, topId)
                                .eq(OrderComponentDO::getDeleted,
                                        DeletedCodeEnum.NOT_DELETED.getStatus())
                                .select(
                                        OrderComponentDO::getId,
                                        OrderComponentDO::getTopId,
                                        OrderComponentDO::getLevel,
                                        OrderComponentDO::getProcessStatus
                                )
                );

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

        // =========================
        // 6、统计：
        // 是否存在已加工子级
        // =========================
        boolean hasProcessedChild =
                topComponentList.stream()
                        // 排除顶级自己
                        .filter(item ->
                                !Objects.equals(
                                        item.getId(),
                                        topId
                                ))
                        .anyMatch(item ->
                                Objects.equals(
                                        item.getProcessStatus(),
                                        OrderComponentProcessStatusEnum.PROCESSED.getStatus()
                                ));

        // =========================
        // 7、计算顶级 extra 状态
        // =========================
        Integer extraProcessStatus = null;

        // 顶级自身未加工
        boolean topUnProcessed =
                Objects.equals(
                        topComponentDO.getProcessStatus(),
                        OrderComponentProcessStatusEnum.UNPROCESSED.getStatus()
                );

        // 只要：
        // 顶级未加工
        // 且存在已加工子级
        // => 部分加工
        if (topUnProcessed && hasProcessedChild) {

            extraProcessStatus =
                    OrderComponentProcessStatusEnum.PART_PROCESSED.getStatus();
        }

        // =========================
        // 8、更新顶级 extra 状态
        // =========================
        orderComponentMapper.update(
                null,
                new LambdaUpdateWrapperX<OrderComponentDO>()
                        .eq(OrderComponentDO::getId, topId)
                        .eq(OrderComponentDO::getOrderId, orderId)
                        .eq(OrderComponentDO::getOrganId, organId)
                        .eq(OrderComponentDO::getDeleted,
                                DeletedCodeEnum.NOT_DELETED.getStatus())
                        .set(OrderComponentDO::getExtraProcessStatus,
                                extraProcessStatus)
        );
    }



    /**
     * 点击加工入口方法
     */
    public static Long getNeedProcessIdsByAssemblyConfig(OrderComponentTreeCompareVO aRoot, OrderComponentTreeCompareVO bRoot, Long currentComponentId) {

        if (aRoot == null || bRoot == null || currentComponentId == null) {
            return null;
        }

        // 1. 构建 B 的 processMap
        Map<String, Boolean> processMap = buildProcessMap(bRoot);

        // 2. 找到 A 中点击的节点
        OrderComponentTreeCompareVO startNode = findNodeById(aRoot, currentComponentId);
        if (startNode == null) {
            return null;
        }

        // 判断当前节点是否允许加工
        String selfKey = buildKey(startNode.getName(), startNode.getLevel());
        Boolean selfProcess = processMap.get(selfKey);
        // 如果明确配置为 false，直接终止
        if (Boolean.FALSE.equals(selfProcess)) {
            throw new ServiceException(ORDER_COMPONENT_NOT_PROCESS);
        }

        // 3. 本身没有不加工，返回id
        return currentComponentId;
    }

    /**
     * 在 A 树中查找节点
     */
    private static OrderComponentTreeCompareVO findNodeById(OrderComponentTreeCompareVO root, Long targetId) {

        Deque<OrderComponentTreeCompareVO> stack = new ArrayDeque<>();
        stack.push(root);

        while (!stack.isEmpty()) {
            OrderComponentTreeCompareVO node = stack.pop();

            if (targetId.equals(node.getId())) {
                return node;
            }

            if (node.getChildren() != null) {
                for (OrderComponentTreeCompareVO child : node.getChildren()) {
                    stack.push(child);
                }
            }
        }

        return null;
    }

    /**
     * 把 B 树扁平化成 Map<name_level, process>
     */
    private static Map<String, Boolean> buildProcessMap(OrderComponentTreeCompareVO root) {

        Map<String, Boolean> map = new HashMap<>();

        Deque<NodeLevel<OrderComponentTreeCompareVO>> stack = new ArrayDeque<>();
        stack.push(new NodeLevel<>(root, 0));

        while (!stack.isEmpty()) {
            NodeLevel<OrderComponentTreeCompareVO> current = stack.pop();
            OrderComponentTreeCompareVO node = current.node;
            int level = current.level;

            String key = buildKey(node.getName(), level);
            map.put(key, node.isProcess());

            if (node.getChildren() != null) {
                for (OrderComponentTreeCompareVO child : node.getChildren()) {
                    stack.push(new NodeLevel<>(child, level + 1));
                }
            }
        }

        return map;
    }

    /**
     * 构建匹配 key
     */
    private static String buildKey(String name, Integer level) {
        return name + "_" + level;
    }

    /**
     * 用于保存节点和层级
     */
    private static class NodeLevel<T> {
        T node;
        int level;

        NodeLevel(T node, int level) {
            this.node = node;
            this.level = level;
        }
    }

    @Override
    public OrdersViewCadViewInfoRespVO getViewComponentPlatesCadInfo(AssemblyListComponentPageReqVO pageReqVO) {
        OrdersViewCadViewInfoRespVO assemblyListComponentCadViewInfoRespVO = new OrdersViewCadViewInfoRespVO();
        Set<Long> componentIds = pageReqVO.getComponentIds();
        if (CollUtil.isEmpty(componentIds)) {
            return assemblyListComponentCadViewInfoRespVO;
        }

        // 1、查询顶级
        List<OrderComponentDO> componentDOS = orderComponentMapper.selectByIds(componentIds);
        if (CollUtil.isEmpty(componentDOS) || componentDOS.size() != componentIds.size()) {
            throw new ServiceException(ORDER_COMPONENT_NOT_EXIST);
        }
        // 整理所在订单id列表
        List<Long> orderIds = componentDOS.stream()
                .map(OrderComponentDO::getOrderId)
                .distinct()
                .toList();
        // 整理所在顶级配件id列表
        List<Long> topIds = componentDOS.stream()
                .map(OrderComponentDO::getTopId)
                .toList();

        // 2、把下级部件id作为查询条件
        List<OrderComponentDO> orderComponentDOS = orderComponentMapper.selectList(new LambdaQueryWrapperX<OrderComponentDO>()
                .in(OrderComponentDO::getTopId, topIds)
                .in(OrderComponentDO::getOrderId, orderIds)
                .eq(OrderComponentDO::getDeleted, DeletedCodeEnum.NOT_DELETED.getStatus())
                .select(OrderComponentDO::getId, OrderComponentDO::getCadViewFileId, OrderComponentDO::getPid));
        Set<Long> queryComponentIds = new HashSet<>();
        if (CollUtil.isNotEmpty(orderComponentDOS)) {
            for (OrderComponentDO co : componentDOS) {
                queryComponentIds.addAll(getChildrenIds(co, orderComponentDOS));
            }
        } else {
            return assemblyListComponentCadViewInfoRespVO;
        }

        // 整理出id和cadViewFileId的对应关系
        Map<Long, Long> cadViewFileIdMap = orderComponentDOS.stream()
                .filter(item -> item.getCadViewFileId() != null)
                .collect(Collectors.toMap(OrderComponentDO::getId, OrderComponentDO::getCadViewFileId));

        // 查询所有板件的视图所需信息
        PageDTO<OrdersViewPlatesPageDO> page1 = new PageDTO<>(1, PageParam.PAGE_SIZE_NONE);
        IPage<OrdersViewPlatesPageDO> viewPlatesPage = orderItemMapper.selectOrdersViewPlatesPage(page1, orderIds, null, null, queryComponentIds, true, false);
        List<OrdersViewPlatesPageDO> plateRecords = viewPlatesPage.getRecords();

        List<OrderViewPlatePageRespVO> plateResultList = new ArrayList<>();
        if (CollUtil.isNotEmpty(plateRecords)) {
            plateResultList = plateRecords.stream().map(item -> {
                OrderViewPlatePageRespVO vo = new OrderViewPlatePageRespVO();
                BeanUtil.copyProperties(item, vo);

                vo.setCadViewFileId(cadViewFileIdMap.get(item.getCompId()));
                return vo;
            }).toList();
        }

        // 查询所有配件的视图所需信息
        PageDTO<OrdersViewPartsPageDO> page2 = new PageDTO<>(1, PageParam.PAGE_SIZE_NONE);
        IPage<OrdersViewPartsPageDO> viewPartsPage = orderItemMapper.selectOrdersViewPartsPage(page2, orderIds, null, null, queryComponentIds, null, true, false);
        List<OrdersViewPartsPageDO> partRecords = viewPartsPage.getRecords();

        List<OrderViewPartPageRespVO> partResultList = new ArrayList<>();
        if (CollUtil.isNotEmpty(partRecords)) {
            partResultList = partRecords.stream().map(item -> {
                OrderViewPartPageRespVO vo = new OrderViewPartPageRespVO();
                BeanUtil.copyProperties(item, vo);

                vo.setCadViewFileId(cadViewFileIdMap.get(item.getCompId()));
                return vo;
            }).toList();
        }

        assemblyListComponentCadViewInfoRespVO.setPlates(plateResultList);
        assemblyListComponentCadViewInfoRespVO.setParts(partResultList);
        return assemblyListComponentCadViewInfoRespVO;
    }

    /**
     * 整理出需要删除的部件id列表
     *
     * @param componentDO
     * @param componentOnTop
     * @return
     */
    private Set<Long> getChildrenIds(OrderComponentDO componentDO, List<OrderComponentDO> componentOnTop) {
        // 3、整理出真正的下级（通过 pid 逐级确认）
        Set<Long> needDeleteIds = new HashSet<>();
        needDeleteIds.add(componentDO.getId());

        if (CollUtil.isNotEmpty(componentOnTop)) {

            // 先构建 pid -> children 映射
            Map<Long, List<OrderComponentDO>> childrenMap = componentOnTop.stream()
                    .collect(Collectors.groupingBy(OrderComponentDO::getPid));

            // 用队列逐级往下找
            Deque<Long> queue = new ArrayDeque<>();
            queue.add(componentDO.getId());

            while (!queue.isEmpty()) {
                Long parentId = queue.poll();

                List<OrderComponentDO> children = childrenMap.get(parentId);
                if (CollUtil.isEmpty(children)) {
                    continue;
                }

                for (OrderComponentDO child : children) {
                    Long childId = child.getId();
                    if (needDeleteIds.add(childId)) { // 防重复
                        queue.add(childId);           // 继续往下找
                    }
                }
            }
        }
        return needDeleteIds;
    }

    @Override
    public List<OrderComponentRespVO> getOrderTopComponentList(OrdersTopComponentListReqVO reqVO) {
        /**
         * 规则：
         * 部件装配的状态：
         * 1、已加工：部件根节点已加工
         * 2、未加工：部件根节点未加工，且子节点均为未加工状态
         * 3、部份加工：部件根节点未加工，且子节点至少有一个已加工
         * 4、不加工： 部件装配设置中至少有一个节点标记为不加工
         */
        if (CollUtil.isEmpty(reqVO.getOrderIds())) {
            return Collections.emptyList();
        }

        if (reqVO.getComponentId() != null || StringUtils.isNotEmpty(reqVO.getName())) {
            return Collections.emptyList();
        }

        // 查询顶级部件
        List<OrderComponentDO> result = orderComponentMapper.getOrderTopComponentListByAssemblyStatus(reqVO.getOrderIds(), reqVO.getProcessStatus());
        return BeanUtil.copyToList(result, OrderComponentRespVO.class);
    }

    /**
     * 解析树数据
     *
     * @param node
     * @return
     */
    private ProcessStats analyzeTree(OrderComponentTreeCompareVO node) {

        ProcessStats stats = new ProcessStats();

        // 默认认为全未加工
        stats.allUnprocessed =
                ObjectUtil.equals(OrderComponentProcessStatusEnum.UNPROCESSED.getStatus(),
                        node.getProcessStatus());

        stats.anyChildProcessed = false;

        List<OrderComponentTreeCompareVO> children = node.getChildren();

        if (CollUtil.isNotEmpty(children)) {

            for (OrderComponentTreeCompareVO child : children) {

                ProcessStats childStats = analyzeTree(child);

                // 只要有一个不是未加工
                if (!childStats.allUnprocessed) {
                    stats.allUnprocessed = false;
                }

                // 子树存在已加工
                if (childStats.anyChildProcessed ||
                        ObjectUtil.equals(OrderComponentProcessStatusEnum.PROCESSED.getStatus(),
                                child.getProcessStatus())) {

                    stats.anyChildProcessed = true;
                }
            }
        }

        return stats;
    }

    /**
     * 过滤规则，是否匹配状态
     *
     * @param state
     * @param statusSet
     * @return
     */
    private boolean matchAnyStatus(TopComponentState state,
                                   Set<OrderComponentProcessStatusEnum> statusSet) {

        if (CollUtil.isEmpty(statusSet)) {
            return true;
        }

        for (OrderComponentProcessStatusEnum status : statusSet) {

            switch (status) {

                case PROCESSED:
                    // 已加工：部件根节点已加工
                    if (state.rootProcessed) {
                        return true;
                    }
                    break;

                case UNPROCESSED:
                    // 未加工：部件根节点未加工，且子节点均为未加工状态
                    if (!state.rootProcessed
                            && state.allUnprocessed
                            && !state.notProcessConfig) {
                        return true;
                    }
                    break;

                case PART_PROCESSED:
                    // 部份加工：部件根节点未加工，且子节点至少有一个已加工
                    if (!state.rootProcessed
                            && state.anyChildProcessed) {
                        return true;
                    }
                    break;

                case NOT_PROCESS:
                    // 不加工： 部件装配设置中至少有一个节点标记为不加工
                    if (state.notProcessConfig) {
                        return true;
                    }
                    break;
            }
        }

        return false;
    }

    class ProcessStats {

        boolean allUnprocessed = true;

        boolean anyChildProcessed = false;
    }

    class TopComponentState {

        OrderComponentTreeCompareVO node;

        /**
         * 根节点加工了
         */
        boolean rootProcessed;

        /**
         * 全都未加工
         */
        boolean allUnprocessed;

        /**
         * 任一子节点加工
         */
        boolean anyChildProcessed;

        /**
         * 不加工
         */
        boolean notProcessConfig;
    }
}
