<?php

declare(strict_types=1);

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

namespace App\Services\Plugin;

use DBCore\Plugin\PluginManager as DbcorPluginFilesystemManager;
use DBCore\Plugin\PluginManifestReader;
use DBCore\Plugin\PluginRegistry;

/**
 * DBErp 插件发现管理器：封装 DBCore 文件系统扫描版 PluginManager，避免与生命周期 PluginManager 混淆。
 */
final class DberpPluginDiscoveryManager
{
    public function __construct(
        private readonly DbcorPluginFilesystemManager $filesystemManager,
        private readonly PluginManifestReader $manifestReader,
        private readonly PluginRegistry $registry,
        private readonly DberpOfficialPluginGuard $officialPluginGuard,
    ) {}

    /**
     * @return list<array<string, mixed>>
     */
    public function scan(): array
    {
        $discovered = $this->filesystemManager->scan();

        foreach ($this->nestedOfficialPluginDirectories() as $pluginDirectory) {
            $errors = [];
            $data = $this->manifestReader->read($pluginDirectory, $errors);

            if ($data === null) {
                continue;
            }

            $this->registry->add($data);
            $discovered[] = $data;
        }

        return $discovered;
    }

    /**
     * @param  list<string>  $aliases
     */
    public function bootEnabled(array $aliases): void
    {
        $this->filesystemManager->bootEnabled($aliases);
    }

    public function registry(): PluginRegistry
    {
        return $this->filesystemManager->registry();
    }

    /**
     * @return array<string, mixed>|null
     */
    public function find(string $alias): ?array
    {
        return $this->filesystemManager->find($alias);
    }

    /**
     * @return list<string>
     */
    public function enabledAliases(): array
    {
        return $this->filesystemManager->enabledAliases();
    }

    public function isEnabled(string $alias): bool
    {
        return $this->filesystemManager->isEnabled($alias);
    }

    /**
     * @return array<string, list<string>>
     */
    public function scanErrors(): array
    {
        $errors = $this->filesystemManager->scanErrors();

        return array_filter(
            $errors,
            fn (array $messages, string $directory): bool => ! $this->isVendorContainerDirectory($directory),
            ARRAY_FILTER_USE_BOTH,
        );
    }

    /**
     * @return list<string>
     */
    private function nestedOfficialPluginDirectories(): array
    {
        $root = $this->officialPluginGuard->officialRootPath();

        if (! is_dir($root)) {
            return [];
        }

        $directories = [];

        foreach (glob($root.DIRECTORY_SEPARATOR.'*', GLOB_ONLYDIR) ?: [] as $vendorDirectory) {
            if (! is_string($vendorDirectory)) {
                continue;
            }

            if (is_file($vendorDirectory.DIRECTORY_SEPARATOR.PluginManifestReader::MANIFEST_FILE)) {
                continue;
            }

            foreach (glob($vendorDirectory.DIRECTORY_SEPARATOR.'*', GLOB_ONLYDIR) ?: [] as $pluginDirectory) {
                if (! is_string($pluginDirectory)) {
                    continue;
                }

                if (is_file($pluginDirectory.DIRECTORY_SEPARATOR.PluginManifestReader::MANIFEST_FILE)) {
                    $directories[] = $pluginDirectory;
                }
            }
        }

        return $directories;
    }

    private function isVendorContainerDirectory(string $directory): bool
    {
        if (is_file($directory.DIRECTORY_SEPARATOR.PluginManifestReader::MANIFEST_FILE)) {
            return false;
        }

        foreach (glob($directory.DIRECTORY_SEPARATOR.'*', GLOB_ONLYDIR) ?: [] as $nestedDirectory) {
            if (! is_string($nestedDirectory)) {
                continue;
            }

            if (is_file($nestedDirectory.DIRECTORY_SEPARATOR.PluginManifestReader::MANIFEST_FILE)) {
                return true;
            }
        }

        return false;
    }
}
