<?php
declare(strict_types=1);

// Read-only model/json type-key probe under the fixed C HTTP worker's complete startup env.
$mode = (string)($argv[1] ?? '');
if (!in_array($mode, ['--parent', '--child'], true)) {
    echo json_encode(['status' => 'default_deny', 'http' => 0, 'dml' => 0]), PHP_EOL;
    exit(78);
}
$dir = '/tmp/zhct-next5-readonly-20261004';
$baselinePath = $dir . '/A_NEXT5_CONTRACT_C.json';
$baselineRaw = trim((string)file_get_contents($baselinePath));
if (hash('sha256', $baselineRaw)
    !== '01663a5f3ef0c1a0b8784d06571fb58a1847bf1bcf168a3f96064f104e159250') {
    throw new RuntimeException('A baseline drift');
}
if ($mode === '--parent') {
    $pid = 112175;
    $cmdline = (string)file_get_contents('/proc/' . $pid . '/cmdline');
    if (strpos($cmdline, '/tmp/zhct-dm-poc-20260928.fcpiiN/store/public') === false
        || strpos($cmdline, '127.0.0.1:18080') === false) {
        throw new RuntimeException('C worker drift');
    }
    $environment = [];
    foreach (explode("\0", (string)file_get_contents('/proc/' . $pid . '/environ')) as $item) {
        $at = strpos($item, '=');
        if ($at !== false) $environment[substr($item, 0, $at)] = substr($item, $at + 1);
    }
    $svc = (string)($environment['DM_SVC_PATH'] ?? '');
    if (substr(hash('sha256', $svc), 0, 12) !== '5a92d26aec07'
        || !is_file($svc . '/dm_svc.conf')
        || strpos((string)file_get_contents($svc . '/dm_svc.conf'), 'CHAR_CODE=(PG_UTF8)') === false) {
        throw new RuntimeException('C UTF8 client profile drift');
    }
    $cmd = escapeshellarg('/www/server/php/73/bin/php')
        . ' -d display_errors=0 -d log_errors=0'
        . ' -d extension=/home/dmdba/dmdbms/drivers/php_pdo/php73_pdo_dm.so '
        . escapeshellarg(__FILE__) . ' --child';
    $process = proc_open($cmd, [1 => ['pipe', 'w'], 2 => ['pipe', 'w']],
        $pipes, null, $environment);
    if (!is_resource($process)) throw new RuntimeException('Child unavailable');
    $stdout = stream_get_contents($pipes[1]);
    $stderr = stream_get_contents($pipes[2]);
    fclose($pipes[1]);
    fclose($pipes[2]);
    $exit = proc_close($process);
    $result = json_decode((string)$stdout, true);
    if ($exit !== 0 || !is_array($result)) {
        echo json_encode(['status' => 'redacted_child_error', 'exit' => $exit,
            'stderr' => $stderr === '' ? 'empty' : 'nonempty']), PHP_EOL;
        exit(2);
    }
    echo json_encode($result, JSON_UNESCAPED_SLASHES), PHP_EOL;
    exit(0);
}

if ((string)getenv('POC_PORT') !== '5237' || (string)getenv('POC_SCHEMA') !== 'ZHCT_APP') {
    throw new RuntimeException('C target mismatch');
}
define('APP_PATH', '/tmp/zhct-dm-poc-20260928.fcpiiN/store/application/');
require '/tmp/zhct-dm-poc-20260928.fcpiiN/store/env.php';
require '/tmp/zhct-dm-poc-20260928.fcpiiN/store/thinkphp/base.php';
require APP_PATH . 'common.php';
if (!function_exists('config')) {
    function config($name = '', $value = null, $range = '')
    {
        return $value === null ? \think\Config::get($name)
            : \think\Config::set($name, $value, $range);
    }
}
$runtime = require APP_PATH . 'database.php';
\think\Config::set($runtime, 'database');
$departments = (new \app\model\Department())
    ->where(['status' => 1, 'is_show' => 1])->select()->toArray();
if (count($departments) !== 26) throw new RuntimeException('Department source drift');
$payload = ['code' => 0, 'message' => '获取成功',
    'data' => ['department' => tree($departments), 'project' => []]];
$encoded = json_encode($payload, JSON_UNESCAPED_UNICODE);
if (!is_string($encoded)) throw new RuntimeException('C JSON encoding failed');
$response = json_decode($encoded, true);
$nodes = [];
$walk = static function (array $items) use (&$walk, &$nodes): void {
    foreach ($items as $node) {
        $nodes[] = $node;
        if (isset($node['children'])) $walk($node['children']);
    }
};
$walk($response['data']['department']);
$profile = [];
foreach ($nodes as $node) {
    foreach ($node as $field => $value) {
        if ($field === 'children' || $field === 'staff_info') continue;
        $profile[$field][gettype($value)] = true;
    }
}
foreach ($profile as $field => $types) {
    $profile[$field] = array_keys($types);
    sort($profile[$field], SORT_STRING);
}
$profile['__envelope_code'] = [gettype($response['code'])];
$profile['__envelope_data'] = [gettype($response['data'])];
$profile['__envelope_message'] = [gettype($response['message'])];
ksort($profile, SORT_STRING);
$baseline = json_decode($baselineRaw, true)['routes']['staff_tree']['type_profile'];
$added = array_values(array_diff(array_keys($profile), array_keys($baseline)));
$missing = array_values(array_diff(array_keys($baseline), array_keys($profile)));
$types = [];
foreach ($profile as $field => $actual) {
    if (!isset($baseline[$field])) continue;
    if ($actual !== $baseline[$field]) $types[$field] = ['A' => $baseline[$field], 'C' => $actual];
}
echo json_encode(['status' => 'read_only', 'model_rows' => count($departments),
    'json_tree_nodes' => count($nodes), 'added_keys' => $added,
    'missing_keys' => $missing, 'type_differences' => $types,
    'dml' => 0, 'http' => 0], JSON_UNESCAPED_SLASHES), PHP_EOL;
