<?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\CorePlugin;
use App\Models\User;
use App\Services\DberpPermissionService;
use DBCore\Plugin\Enums\PluginStatus;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Support\Facades\Auth;
use Throwable;

/**
 * 解析插件 manifest 中的设置入口（config_route），并校验路由可用性。
 */
final class HostPluginSettingsRouteResolver
{
    public function __construct(
        private readonly DberpPluginDiscoveryManager $discoveryManager,
        private readonly DberpOfficialPluginGuard $officialPluginGuard,
        private readonly HostPluginPermissionResolver $permissionResolver,
    ) {}

    public function hasSettingsRoute(string $identifier): bool
    {
        return $this->resolveAccess($identifier)->isAvailable();
    }

    public function resolveAccess(string $identifier, ?Authenticatable $user = null): HostPluginSettingsAccessResult
    {
        $normalized = trim($identifier);

        if ($normalized === '') {
            return new HostPluginSettingsAccessResult(
                state: HostPluginSettingsAccessResult::STATE_PLUGIN_NOT_INSTALLED,
                userMessage: (string) __('dberp.plugin_center.settings.unavailable'),
            );
        }

        $record = CorePlugin::query()->where('identifier', $normalized)->first();

        if ($record === null || $record->status === PluginStatus::Uninstalled->value) {
            return new HostPluginSettingsAccessResult(
                state: HostPluginSettingsAccessResult::STATE_PLUGIN_NOT_INSTALLED,
                userMessage: (string) __('dberp.plugin_center.settings.unavailable'),
            );
        }

        if ($record->status !== PluginStatus::Enabled->value) {
            return new HostPluginSettingsAccessResult(
                state: HostPluginSettingsAccessResult::STATE_PLUGIN_DISABLED,
                userMessage: (string) __('dberp.plugin_center.settings.plugin_disabled'),
            );
        }

        $resolvedUser = $user ?? Auth::user();
        $actor = $resolvedUser instanceof User ? $resolvedUser : null;

        $configRoute = $this->resolveRouteReference($normalized);

        if ($configRoute === null) {
            if ($actor === null || ! app(DberpPermissionService::class)->allows($actor, DberpPermissionService::CONFIGURE_HOST_PLUGIN)) {
                return new HostPluginSettingsAccessResult(
                    state: HostPluginSettingsAccessResult::STATE_PERMISSION_DENIED,
                    userMessage: (string) __('dberp.plugin_center.lifecycle.permission_denied'),
                );
            }

            return new HostPluginSettingsAccessResult(
                state: HostPluginSettingsAccessResult::STATE_NO_CONFIG_ROUTE,
                userMessage: (string) __('dberp.plugin_center.settings.no_settings'),
            );
        }

        if (! $this->permissionResolver->userCanAccessSettings($actor, $normalized)) {
            return new HostPluginSettingsAccessResult(
                state: HostPluginSettingsAccessResult::STATE_PERMISSION_DENIED,
                userMessage: (string) __('dberp.plugin_center.lifecycle.permission_denied'),
            );
        }

        $url = $this->buildUrlFromRouteReference($configRoute);

        if ($url === null) {
            return new HostPluginSettingsAccessResult(
                state: HostPluginSettingsAccessResult::STATE_ROUTE_MISSING,
                configRoute: $configRoute,
                userMessage: (string) __('dberp.plugin_center.settings.route_missing'),
            );
        }

        return new HostPluginSettingsAccessResult(
            state: HostPluginSettingsAccessResult::STATE_AVAILABLE,
            url: $url,
            configRoute: $configRoute,
        );
    }

    public function resolveUrl(string $identifier): ?string
    {
        $access = $this->resolveAccess($identifier);

        return $access->isAvailable() ? $access->url : null;
    }

    public function resolveRouteReference(string $identifier): ?string
    {
        $configRoute = $this->configRouteFromManifest($this->discoveryManager->find($identifier));

        if ($configRoute !== null) {
            return $configRoute;
        }

        return $this->configRouteFromManifest($this->readManifestFromInstalledPlugin($identifier));
    }

    /**
     * @param  array<string, mixed>|null  $manifest
     */
    private function configRouteFromManifest(?array $manifest): ?string
    {
        if (! is_array($manifest)) {
            return null;
        }

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

        return $configRoute !== '' ? $configRoute : null;
    }

    /**
     * @return array<string, mixed>|null
     */
    private function readManifestFromInstalledPlugin(string $identifier): ?array
    {
        $normalized = trim($identifier);

        if ($normalized === '') {
            return null;
        }

        $record = CorePlugin::query()->where('identifier', $normalized)->first();

        if ($record === null) {
            return null;
        }

        /** @var array<string, mixed> $meta */
        $meta = is_array($record->meta) ? $record->meta : [];
        /** @var array<string, mixed> $extra */
        $extra = is_array($meta['extra'] ?? null) ? $meta['extra'] : [];
        $pluginPath = trim((string) ($extra['path'] ?? ''));

        if ($pluginPath === '') {
            $pluginPath = $this->resolveOfficialPluginDirectory($normalized);
        }

        $manifestPath = $pluginPath.DIRECTORY_SEPARATOR.'plugin.json';

        if (! is_file($manifestPath)) {
            return null;
        }

        try {
            $decoded = json_decode((string) file_get_contents($manifestPath), true, 512, JSON_THROW_ON_ERROR);

            return is_array($decoded) ? $decoded : null;
        } catch (Throwable) {
            return null;
        }
    }

    private function resolveOfficialPluginDirectory(string $identifier): string
    {
        $root = $this->officialPluginGuard->officialRootPath();
        $flat = $root.DIRECTORY_SEPARATOR.$identifier;

        if (is_dir($flat)) {
            return $flat;
        }

        $vendorDirectories = glob($root.DIRECTORY_SEPARATOR.'*', GLOB_ONLYDIR) ?: [];

        foreach ($vendorDirectories as $vendorDirectory) {
            if (! is_string($vendorDirectory)) {
                continue;
            }

            $candidate = $vendorDirectory.DIRECTORY_SEPARATOR.$identifier;

            if (is_dir($candidate)) {
                return $candidate;
            }
        }

        return $flat;
    }

    private function buildUrlFromRouteReference(string $routeReference): ?string
    {
        if (str_starts_with($routeReference, '/')) {
            return $routeReference;
        }

        try {
            // 官方插件路由常在 app()->booted() 后注册，刷新命名查找避免误判为缺失。
            app('router')->getRoutes()->refreshNameLookups();

            $url = route($routeReference);

            return is_string($url) && $url !== '' ? $url : null;
        } catch (Throwable) {
            return null;
        }
    }
}
