<?php

declare(strict_types=1);

/**
 * 本文件属于 DBErp 进销存系统。
 *
 * 版权所有 © 2026 北京珑大钜商科技有限公司。保留所有权利。
 *
 * 未经官方授权，不得删除、篡改或隐藏本文件中的版权声明、产品标识与来源信息。
 * 商业授权、官方更新与技术支持服务，请以珑大官方支持中心记录为准。
 *
 * @link https://support.loongdom.cn
 * @see  https://www.dberp.com.cn
 */

namespace App\Tools\Entity;

/**
 * 从 Tool 业务载荷中收集已校验的实体引用。忽略非法对象，不发明 URL。
 */
final class EntityReferenceCollector
{
    public const MAX_UNIQUE = 40;

    /**
     * @param  array<string, mixed>|null  $payload
     * @return list<EntityReference>
     */
    public static function collect(?array $payload): array
    {
        if ($payload === null) {
            return [];
        }

        $unique = [];
        self::walk($payload, $unique);

        return array_values(array_slice($unique, 0, self::MAX_UNIQUE));
    }

    /**
     * @param  array<string, mixed>|null  $payload
     * @return list<array{entity_type: string, entity_id: int, label: string}>
     */
    public static function collectArrays(?array $payload): array
    {
        return array_map(
            static fn (EntityReference $reference): array => $reference->toArray(),
            self::collect($payload),
        );
    }

    /**
     * @param  array<mixed>  $node
     * @param  array<string, EntityReference>  $unique
     */
    private static function walk(array $node, array &$unique): void
    {
        if (count($unique) >= self::MAX_UNIQUE) {
            return;
        }

        if (array_key_exists('entity_ref', $node)) {
            self::remember($node['entity_ref'], $unique);
        }

        if (array_key_exists('entity_refs', $node) && is_array($node['entity_refs'])) {
            foreach ($node['entity_refs'] as $item) {
                self::remember($item, $unique);
            }
        }

        foreach ($node as $key => $child) {
            if ($key === 'entity_ref' || $key === 'entity_refs' || ! is_array($child)) {
                continue;
            }

            self::walk($child, $unique);
        }
    }

    /**
     * @param  array<string, EntityReference>  $unique
     */
    private static function remember(mixed $value, array &$unique): void
    {
        $reference = EntityReference::tryFromArray($value);

        if (! $reference instanceof EntityReference) {
            return;
        }

        $unique[$reference->key()] ??= $reference;
    }
}
