<?php
/**
 * PHP 8 运行环境检测（版本、扩展、可选语法扫描）
 */
class CloakPhpCompat
{
    /** @var string 项目要求的最低 PHP 版本 */
    public const MIN_PHP_VERSION = '8.0.0';

    /** @var string[] 必需扩展 */
    public const REQUIRED_EXTENSIONS = [
        'curl',
        'json',
        'mbstring',
        'mysqli',
        'session',
        'dom',
    ];

    /** @var string[] 推荐扩展（缺失时警告，不阻断） */
    public const RECOMMENDED_EXTENSIONS = [
        'redis',
        'openssl',
    ];

    /**
     * 入口引导时调用：不满足最低版本则终止并输出说明
     *
     * @return void
     */
    public static function ensureRuntime()
    {
        $report = self::buildReport();
        if ($report['ok']) {
            return;
        }

        $lines = ['Cloaka 需要 PHP ' . self::MIN_PHP_VERSION . ' 或更高版本。', ''];
        foreach ($report['errors'] as $err) {
            $lines[] = ' - ' . $err;
        }
        $lines[] = '';
        $lines[] = '当前 PHP：' . PHP_VERSION;
        $lines[] = '请升级 PHP 或运行：php tools/regression_test.php';

        $message = implode("\n", $lines);

        if (PHP_SAPI === 'cli') {
            fwrite(STDERR, $message . "\n");
            exit(1);
        }

        if (!headers_sent()) {
            header('Content-Type: text/plain; charset=utf-8', true, 503);
        }
        echo $message;
        exit(1);
    }

    /**
     * @return array{ok:bool,php_version:string,errors:array,warnings:array,extensions:array}
     */
    public static function buildReport()
    {
        $errors   = [];
        $warnings = [];

        if (version_compare(PHP_VERSION, self::MIN_PHP_VERSION, '<')) {
            $errors[] = 'PHP 版本过低（需要 >= ' . self::MIN_PHP_VERSION . '，当前 ' . PHP_VERSION . '）';
        }

        foreach (self::REQUIRED_EXTENSIONS as $ext) {
            if (!extension_loaded($ext)) {
                $errors[] = '缺少必需扩展：' . $ext;
            }
        }

        foreach (self::RECOMMENDED_EXTENSIONS as $ext) {
            if (!extension_loaded($ext)) {
                $warnings[] = '缺少推荐扩展：' . $ext . '（部分功能将降级）';
            }
        }

        return [
            'ok'          => empty($errors),
            'php_version' => PHP_VERSION,
            'errors'      => $errors,
            'warnings'    => $warnings,
            'extensions'  => array_values(array_filter(
                array_merge(self::REQUIRED_EXTENSIONS, self::RECOMMENDED_EXTENSIONS),
                'extension_loaded'
            )),
        ];
    }

    /**
     * 对项目 PHP 文件执行 php -l（仅 CLI）
     *
     * @param string|null $root 项目根目录
     * @return array{ok:bool,failures:array<int,string>}
     */
    public static function lintProject($root = null)
    {
        $root = $root ?: dirname(__DIR__);
        $failures = [];

        if (PHP_SAPI !== 'cli') {
            return ['ok' => true, 'failures' => [], 'skipped' => 'not_cli'];
        }

        $iterator = new RecursiveIteratorIterator(
            new RecursiveDirectoryIterator($root, FilesystemIterator::SKIP_DOTS)
        );

        $skipDirs = ['vendor', 'node_modules', '.git'];

        foreach ($iterator as $file) {
            /** @var SplFileInfo $file */
            if (!$file->isFile() || $file->getExtension() !== 'php') {
                continue;
            }
            $path = $file->getPathname();
            foreach ($skipDirs as $skip) {
                if (strpos($path, DIRECTORY_SEPARATOR . $skip . DIRECTORY_SEPARATOR) !== false) {
                    continue 2;
                }
            }

            $cmd = escapeshellarg(PHP_BINARY) . ' -l ' . escapeshellarg($path) . ' 2>&1';
            $out = [];
            exec($cmd, $out, $code);
            if ($code !== 0) {
                $failures[] = $path . ': ' . implode(' ', $out);
            }
        }

        return ['ok' => empty($failures), 'failures' => $failures];
    }
}
