<?php

declare(strict_types=1);

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

namespace App\Services\Plugin;

use App\Models\User;
use App\Services\DberpPermissionService;

/**
 * 官方插件 manifest 权限码解析与校验（plugin.{alias_snake}.{action}）。
 */
final class HostPluginPermissionResolver
{
    public function __construct(
        private readonly DberpPermissionService $permissionService,
        private readonly DberpPluginDiscoveryManager $discoveryManager,
        private readonly HostPluginManifestValidator $manifestValidator,
        private readonly HostPluginPermissionLabelResolver $permissionLabelResolver,
    ) {}

    public function aliasToPermissionSegment(string $alias): string
    {
        return $this->manifestValidator->aliasToPermissionSegment(trim($alias));
    }

    public function settingsPermissionCode(string $identifier): string
    {
        $manifest = $this->discoveryManager->find(trim($identifier));

        if (is_array($manifest)) {
            foreach ($this->permissionCodesFromManifest($manifest) as $code) {
                if (str_ends_with($code, '.configure')) {
                    return $code;
                }
            }
        }

        return 'plugin.'.$this->aliasToPermissionSegment($identifier).'.configure';
    }

    public function userCanAccessSettings(?User $user, string $identifier): bool
    {
        if ($user === null) {
            return false;
        }

        if (! $this->permissionService->allows($user, DberpPermissionService::CONFIGURE_HOST_PLUGIN)) {
            return false;
        }

        return $this->permissionService->allows($user, $this->settingsPermissionCode($identifier));
    }

    /**
     * @param  array<string, mixed>|null  $manifest
     * @return list<string>
     */
    public function permissionCodesFromManifest(?array $manifest): array
    {
        if (! is_array($manifest)) {
            return [];
        }

        $permissions = $manifest['permissions'] ?? null;

        if (! is_array($permissions)) {
            $configRoute = trim((string) ($manifest['config_route'] ?? ''));

            if ($configRoute === '') {
                return [];
            }

            $alias = trim((string) ($manifest['alias'] ?? $manifest['identifier'] ?? ''));

            if ($alias === '') {
                return [];
            }

            return ['plugin.'.$this->aliasToPermissionSegment($alias).'.configure'];
        }

        $codes = [];

        foreach ($permissions as $permission) {
            if (! is_string($permission) || trim($permission) === '') {
                continue;
            }

            $codes[] = trim($permission);
        }

        return array_values(array_unique($codes));
    }

    /**
     * @param  array<string, mixed>|null  $manifest
     * @return array<string, array{code: string, display_name: string, guard_name: string, module: string, navigation_group: string, plugin_identifier: string, plugin_label: string, action: string, action_label: string, description: string, sort_order: int, is_system: bool, default_allow_when_unconfigured: bool}>
     */
    public function permissionDefinitionsFromManifest(string $identifier, ?array $manifest): array
    {
        $normalized = trim($identifier);
        $codes = $this->permissionCodesFromManifest($manifest);

        if ($codes === [] && is_array($manifest) && trim((string) ($manifest['config_route'] ?? '')) !== '') {
            $codes = [$this->settingsPermissionCode($normalized)];
        }

        if ($codes === []) {
            return [];
        }

        $pluginLabel = $this->resolvePluginLabel($normalized, $manifest);
        $definitions = [];
        $baseSort = 860;

        foreach ($codes as $index => $code) {
            $action = explode('.', $code)[2] ?? 'access';
            $actionLabel = $this->permissionLabelResolver->actionLabel($action, $manifest);
            $displayName = $this->permissionLabelResolver->catalogDisplayName($actionLabel, $pluginLabel);

            $definitions[$code] = [
                'code' => $code,
                'display_name' => $displayName,
                'guard_name' => 'web',
                'module' => 'plugin',
                'navigation_group' => 'plugin',
                'plugin_identifier' => $normalized,
                'plugin_label' => $pluginLabel,
                'action' => $action,
                'action_label' => $actionLabel,
                'description' => $displayName,
                'sort_order' => $baseSort + ($index * 10),
                'is_system' => true,
                'default_allow_when_unconfigured' => false,
            ];
        }

        return $definitions;
    }

    /**
     * @param  array<string, mixed>|null  $manifest
     */
    private function resolvePluginLabel(string $identifier, ?array $manifest): string
    {
        if (is_array($manifest)) {
            $displayName = trim((string) ($manifest['display_name'] ?? ''));

            if ($displayName !== '') {
                return $displayName;
            }

            $name = trim((string) ($manifest['name'] ?? ''));

            if ($name !== '') {
                return $name;
            }
        }

        return $identifier;
    }
}
