<?php
/**
 * Extension compatibility tester for Folk embed SAPI.
 *
 * Called from Rust tests via eval(). Each test function returns a JSON
 * result: {"status": "ok"} or {"status": "fail", "error": "..."}.
 *
 * Usage from Rust:
 *   php.eval("require_once 'test_extensions.php';");
 *   let result = php.eval("echo folk_test_ext_json();");
 */

function folk_test_extension(string $name, callable $test): array {
    if (!extension_loaded($name)) {
        return ['name' => $name, 'load' => 'missing', 'basic' => 'skip'];
    }

    try {
        $result = $test();
        return [
            'name' => $name,
            'load' => 'ok',
            'basic' => $result === true ? 'ok' : 'fail',
            'error' => $result === true ? null : (string)$result,
        ];
    } catch (\Throwable $e) {
        return [
            'name' => $name,
            'load' => 'ok',
            'basic' => 'fail',
            'error' => $e->getMessage(),
        ];
    }
}

function folk_test_all_extensions(): array {
    $results = [];

    // ── Bundled extensions ──────────────────────────────────────

    $results[] = folk_test_extension('bcmath', function() {
        return bcadd('1.5', '2.5') === '4';
    });

    $results[] = folk_test_extension('calendar', function() {
        return is_int(cal_days_in_month(CAL_GREGORIAN, 1, 2024));
    });

    $results[] = folk_test_extension('ctype', function() {
        return ctype_alpha('hello') === true;
    });

    $results[] = folk_test_extension('curl', function() {
        $ch = curl_init();
        curl_close($ch);
        return true;
    });

    $results[] = folk_test_extension('date', function() {
        return strlen(date('Y-m-d')) === 10;
    });

    $results[] = folk_test_extension('dom', function() {
        $doc = new DOMDocument();
        $doc->loadHTML('<html><body>test</body></html>');
        return $doc->getElementsByTagName('body')->length === 1;
    });

    $results[] = folk_test_extension('exif', function() {
        return function_exists('exif_imagetype');
    });

    $results[] = folk_test_extension('ffi', function() {
        return class_exists('FFI');
    });

    $results[] = folk_test_extension('fileinfo', function() {
        $finfo = new finfo(FILEINFO_MIME_TYPE);
        return $finfo->buffer('<?php echo 1;') !== false;
    });

    $results[] = folk_test_extension('filter', function() {
        return filter_var('test@example.com', FILTER_VALIDATE_EMAIL) !== false;
    });

    $results[] = folk_test_extension('gd', function() {
        $img = imagecreatetruecolor(10, 10);
        imagedestroy($img);
        return true;
    });

    $results[] = folk_test_extension('gettext', function() {
        return function_exists('gettext');
    });

    $results[] = folk_test_extension('gmp', function() {
        return gmp_strval(gmp_add('123', '456')) === '579';
    });

    $results[] = folk_test_extension('hash', function() {
        return strlen(hash('sha256', 'test')) === 64;
    });

    $results[] = folk_test_extension('iconv', function() {
        return iconv('UTF-8', 'ASCII//TRANSLIT', 'café') !== false;
    });

    $results[] = folk_test_extension('intl', function() {
        $fmt = new NumberFormatter('en_US', NumberFormatter::DECIMAL);
        return $fmt->format(1234.5) === '1,234.5';
    });

    $results[] = folk_test_extension('json', function() {
        return json_encode(['a' => 1]) === '{"a":1}';
    });

    $results[] = folk_test_extension('mbstring', function() {
        return mb_strlen('тест') === 4;
    });

    $results[] = folk_test_extension('openssl', function() {
        return strlen(openssl_random_pseudo_bytes(16)) === 16;
    });

    $results[] = folk_test_extension('pcre', function() {
        return preg_match('/^\d+$/', '123') === 1;
    });

    $results[] = folk_test_extension('pdo', function() {
        return class_exists('PDO');
    });

    $results[] = folk_test_extension('pdo_sqlite', function() {
        $db = new PDO('sqlite::memory:');
        $db->exec('CREATE TABLE t(id INTEGER)');
        $db->exec('INSERT INTO t VALUES(1)');
        return $db->query('SELECT id FROM t')->fetchColumn() === '1';
    });

    $results[] = folk_test_extension('phar', function() {
        return class_exists('Phar');
    });

    $results[] = folk_test_extension('posix', function() {
        return is_int(posix_getpid());
    });

    $results[] = folk_test_extension('readline', function() {
        // readline is interactive — just check it loaded
        return function_exists('readline');
    });

    $results[] = folk_test_extension('reflection', function() {
        $ref = new ReflectionFunction('strlen');
        return $ref->getNumberOfParameters() === 1;
    });

    $results[] = folk_test_extension('session', function() {
        // Session in embed mode — just check functions exist
        return function_exists('session_start');
    });

    $results[] = folk_test_extension('simplexml', function() {
        $xml = simplexml_load_string('<root><item>test</item></root>');
        return (string)$xml->item === 'test';
    });

    $results[] = folk_test_extension('sodium', function() {
        $key = sodium_crypto_secretbox_keygen();
        return strlen($key) === SODIUM_CRYPTO_SECRETBOX_KEYBYTES;
    });

    $results[] = folk_test_extension('spl', function() {
        $stack = new SplStack();
        $stack->push('a');
        return $stack->pop() === 'a';
    });

    $results[] = folk_test_extension('sqlite3', function() {
        $db = new SQLite3(':memory:');
        $db->exec('CREATE TABLE t(id INTEGER)');
        $db->exec('INSERT INTO t VALUES(42)');
        return $db->querySingle('SELECT id FROM t') === 42;
    });

    $results[] = folk_test_extension('standard', function() {
        return strlen(str_repeat('a', 100)) === 100;
    });

    $results[] = folk_test_extension('tidy', function() {
        $tidy = new tidy();
        $tidy->parseString('<html><body>test</body></html>');
        return $tidy->getStatus() !== false;
    });

    $results[] = folk_test_extension('tokenizer', function() {
        $tokens = token_get_all('<?php echo 1;');
        return count($tokens) > 0;
    });

    $results[] = folk_test_extension('xml', function() {
        $parser = xml_parser_create();
        xml_parser_free($parser);
        return true;
    });

    $results[] = folk_test_extension('xmlreader', function() {
        return class_exists('XMLReader');
    });

    $results[] = folk_test_extension('xmlwriter', function() {
        $w = new XMLWriter();
        $w->openMemory();
        $w->startElement('test');
        $w->endElement();
        return strlen($w->outputMemory()) > 0;
    });

    $results[] = folk_test_extension('xsl', function() {
        return class_exists('XSLTProcessor');
    });

    $results[] = folk_test_extension('zip', function() {
        return class_exists('ZipArchive');
    });

    $results[] = folk_test_extension('zlib', function() {
        $c = gzcompress('test');
        return gzuncompress($c) === 'test';
    });

    $results[] = folk_test_extension('Zend OPcache', function() {
        return function_exists('opcache_get_status');
    });

    $results[] = folk_test_extension('sockets', function() {
        $s = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
        socket_close($s);
        return true;
    });

    $results[] = folk_test_extension('bz2', function() {
        $c = bzcompress('test');
        return bzdecompress($c) === 'test';
    });

    $results[] = folk_test_extension('ftp', function() {
        return function_exists('ftp_connect');
    });

    $results[] = folk_test_extension('ldap', function() {
        return function_exists('ldap_connect');
    });

    $results[] = folk_test_extension('soap', function() {
        return class_exists('SoapClient');
    });

    $results[] = folk_test_extension('pcntl', function() {
        // pcntl in embed mode — fork conflicts with threads
        return function_exists('pcntl_fork') ? 'loaded_but_unsafe' : false;
    });

    $results[] = folk_test_extension('shmop', function() {
        return function_exists('shmop_open');
    });

    // ── PECL extensions ────────────────────────────────────────

    $results[] = folk_test_extension('redis', function() {
        return class_exists('Redis');
    });

    $results[] = folk_test_extension('msgpack', function() {
        $packed = msgpack_pack(['a' => 1]);
        return msgpack_unpack($packed) === ['a' => 1];
    });

    $results[] = folk_test_extension('igbinary', function() {
        $s = igbinary_serialize(['a' => 1]);
        return igbinary_unserialize($s) === ['a' => 1];
    });

    $results[] = folk_test_extension('apcu', function() {
        // APCu may need cli enable
        return function_exists('apcu_store');
    });

    $results[] = folk_test_extension('mongodb', function() {
        return class_exists('MongoDB\Driver\Manager');
    });

    $results[] = folk_test_extension('yaml', function() {
        return yaml_emit(['key' => 'value']) !== false;
    });

    $results[] = folk_test_extension('uuid', function() {
        return strlen(uuid_create()) === 36;
    });

    $results[] = folk_test_extension('xhprof', function() {
        return function_exists('xhprof_enable');
    });

    return $results;
}

/**
 * Run all tests and return JSON.
 */
function folk_test_all_extensions_json(): string {
    return json_encode(folk_test_all_extensions(), JSON_PRETTY_PRINT);
}
