<?php

declare(strict_types=1);

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

namespace App\Support\SystemUpdate;

/**
 * 宿主安装包 / 系统更新包：排除 plugins/ 下插件源码，仅保留目录骨架文件。
 */
class HostPluginPackagePathExclusion
{
    /**
     * @var list<string>
     */
    public const SKELETON_RELATIVE_PATHS = [
        'plugins/.gitkeep',
    ];

    public function isSkeletonRelativePath(string $relativePath): bool
    {
        $normalized = $this->normalizeRelativePath($relativePath);

        return $normalized !== null
            && in_array($normalized, self::SKELETON_RELATIVE_PATHS, true);
    }

    public function isExcludedPluginRelativePath(string $relativePath): bool
    {
        $normalized = $this->normalizeRelativePath($relativePath);

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

        if ($this->isSkeletonRelativePath($normalized)) {
            return false;
        }

        return str_starts_with($normalized, 'plugins/');
    }

    public function shouldPrunePluginDirectory(string $relativeDirectory): bool
    {
        $normalized = $this->normalizeRelativePath($relativeDirectory);

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

        if ($normalized === 'plugins') {
            return false;
        }

        if ($this->isSkeletonRelativePath($normalized)) {
            return false;
        }

        return str_starts_with($normalized, 'plugins/');
    }

    private function normalizeRelativePath(string $path): ?string
    {
        $trimmed = trim(str_replace('\\', '/', $path));

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

        if (str_starts_with($trimmed, '/')) {
            return null;
        }

        if (preg_match('/^[A-Za-z]:[\/\\\\]/', $path) === 1) {
            return null;
        }

        if (str_contains($trimmed, '../') || str_contains($trimmed, '/..')
            || str_starts_with($trimmed, '..') || str_contains($trimmed, '..\\')) {
            return null;
        }

        $segments = explode('/', $trimmed);
        $safe = [];

        foreach ($segments as $segment) {
            if ($segment === '' || $segment === '.') {
                continue;
            }

            if ($segment === '..') {
                return null;
            }

            $safe[] = $segment;
        }

        return $safe === [] ? null : implode('/', $safe);
    }
}
