<?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\Contracts\PluginManagerInterface;
use DBCore\Support\Results\OperationResult;
use Throwable;

/**
 * 将官方插件安装与 DBCore PluginManagerInterface::install() 对齐，并触发 PluginInterface::install()。
 */
final class HostPluginLifecycleInstallService
{
    public function __construct(
        private readonly PluginManagerInterface $pluginManager,
        private readonly DberpPluginDiscoveryManager $discoveryManager,
        private readonly HostPluginEntryInstallInvoker $entryInstallInvoker,
        private readonly HostPluginInstallRollback $installRollback,
    ) {}

    /**
     * @param  array<string, mixed>  $hostExtra  写入 core_plugins.meta.extra 的宿主字段（path、source 等）
     */
    public function registerInstalledPlugin(
        string $identifier,
        array $hostExtra = [],
        ?string $pluginDirectoryForRollback = null,
    ): OperationResult {
        $normalized = trim($identifier);

        if ($normalized === '') {
            return OperationResult::failure('插件标识符不能为空。');
        }

        $this->discoveryManager->scan();

        $lifecycleResult = $this->pluginManager->install($normalized, [
            'extra' => $hostExtra,
            'installed_at' => now()->utc()->toIso8601String(),
        ]);

        if ($lifecycleResult->getStatus() !== 'success') {
            return $lifecycleResult;
        }

        try {
            $this->entryInstallInvoker->invokeInstall($normalized);
        } catch (Throwable $exception) {
            $this->installRollback->rollbackPersistence($normalized);

            if ($pluginDirectoryForRollback !== null && trim($pluginDirectoryForRollback) !== '') {
                $this->installRollback->rollbackFilesystem($pluginDirectoryForRollback);
            }

            return OperationResult::failure(
                $exception->getMessage(),
                [
                    'exception_class' => $exception::class,
                    'entry_install_failed' => true,
                ],
            );
        }

        return $lifecycleResult;
    }
}
