<?php

declare(strict_types=1);

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

namespace App\Support\EntityNavigation;

use App\Support\DberpFilamentListPageUrl;
use Filament\Resources\Resource;
use Throwable;

/**
 * 安全生成 Filament 只读 URL。拒绝 edit/create，失败时返回 null。
 */
final class SafeFilamentResourceUrl
{
    /**
     * @var list<string>
     */
    private const FORBIDDEN_PAGES = ['edit', 'create'];

    /**
     * @param  class-string<resource>  $resourceClass
     * @param  array<string, mixed>  $parameters
     */
    public static function page(string $resourceClass, string $page, array $parameters = []): ?string
    {
        if (in_array($page, self::FORBIDDEN_PAGES, true) || ! self::isResource($resourceClass)) {
            return null;
        }

        try {
            if (! $resourceClass::hasPage($page)) {
                return null;
            }

            $url = $resourceClass::getUrl($page, $parameters);
        } catch (Throwable) {
            return null;
        }

        return self::sanitize($url);
    }

    /**
     * @param  class-string<resource>  $resourceClass
     * @param  array<string, mixed>  $tableFilters
     */
    public static function filteredIndex(string $resourceClass, array $tableFilters = []): ?string
    {
        $url = self::page($resourceClass, 'index');

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

        return self::sanitize(DberpFilamentListPageUrl::append($url, $tableFilters));
    }

    /**
     * @param  class-string<resource>  $resourceClass
     */
    public static function searchedIndex(string $resourceClass, string $search): ?string
    {
        $url = self::page($resourceClass, 'index');

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

        $query = http_build_query(['search' => $search]);

        return self::sanitize($url.(str_contains($url, '?') ? '&' : '?').$query);
    }

    /**
     * @param  class-string<resource>  $resourceClass
     */
    public static function hasViewPage(string $resourceClass): bool
    {
        if (! self::isResource($resourceClass)) {
            return false;
        }

        try {
            return $resourceClass::hasPage('view');
        } catch (Throwable) {
            return false;
        }
    }

    /**
     * @param  class-string  $resourceClass
     */
    private static function isResource(string $resourceClass): bool
    {
        return class_exists($resourceClass) && is_subclass_of($resourceClass, Resource::class);
    }

    private static function sanitize(?string $url): ?string
    {
        if ($url === null) {
            return null;
        }

        $normalized = trim($url);

        if ($normalized === '' || str_contains(strtolower($normalized), '/edit')) {
            return null;
        }

        if (str_contains($normalized, '/create')) {
            return null;
        }

        if (str_starts_with($normalized, '/')) {
            return str_starts_with($normalized, '//') ? null : $normalized;
        }

        if (preg_match('#^https?://#i', $normalized) === 1) {
            return $normalized;
        }

        return null;
    }
}
