<?php
declare(strict_types=1);

// Parameterized SELECT-only gate for the next six ai_app reads.
// Business HTTP and fixture writes are intentionally not implemented.
$target = (string)getenv('CDX_READ6_TARGET');
$mode = $argv[1] ?? '';
if (!in_array($target, ['A', 'B', 'C'], true)
    || $mode !== '--preflight'
    || getenv('CDX_READ6_SELECT_ONLY') !== '1') {
    echo json_encode(['status' => 'default_deny', 'http' => 0, 'dml' => 0]), PHP_EOL;
    exit(78);
}

$stage = 'runtime';
set_exception_handler(static function (Throwable $e) use (&$stage): void {
    echo json_encode(['status' => 'redacted_error', 'target' => $GLOBALS['target'],
        'stage' => $stage, 'class' => get_class($e), 'code' => (string)$e->getCode(),
        'http' => 0, 'dml' => 0]), PHP_EOL;
    exit(2);
});
set_error_handler(static function (int $severity): bool {
    if (!(error_reporting() & $severity)) return false;
    throw new ErrorException('redacted warning', 0, $severity);
});

$config = [];
if ($target === 'C') {
    $pid = 53772;
    $cmd = (string)file_get_contents('/proc/' . $pid . '/cmdline');
    if (strpos($cmd, '127.0.0.1:18102') === false
        || strpos($cmd, '/tmp/zhct-ai-http-20260929.3XDj3w/public') === false) {
        throw new RuntimeException('isolated C runtime changed');
    }
    $raw = (string)file_get_contents('/proc/' . $pid . '/environ');
    foreach (explode("\0", $raw) as $entry) {
        if (strpos($entry, 'POC_') !== 0) continue;
        $separator = strpos($entry, '=');
        if ($separator !== false) {
            $config[substr($entry, 0, $separator)] = substr($entry, $separator + 1);
        }
    }
    foreach (['POC_DIALECT' => 'dm', 'POC_EXTERNAL_STUBS' => '1',
        'POC_AI_HOST' => '127.0.0.1', 'POC_AI_PORT' => '5238',
        'POC_AI_SCHEMA' => 'AIZHCT_APP', 'POC_HOST' => '127.0.0.1',
        'POC_PORT' => '5237', 'POC_SCHEMA' => 'ZHCT_APP'] as $key => $value) {
        if (($config[$key] ?? '') !== $value) throw new RuntimeException('C boundary changed');
    }
    foreach (['POC_AI_USER', 'POC_AI_PASSWORD', 'POC_USER', 'POC_PASSWORD'] as $key) {
        if (empty($config[$key])) throw new RuntimeException('C credential unavailable');
    }
} else {
    $port = $target === 'A' ? 18105 : 18101;
    $root = $target === 'A' ? '/private/tmp/zhct-http-ai-macos.zjaU8h'
        : '/private/tmp/zhct-http-ai-macos.x2CCZX';
    $pids = array_values(array_filter(explode("\n", trim((string)shell_exec(
        '/usr/sbin/lsof -t -nP -iTCP:' . $port . ' -sTCP:LISTEN 2>/dev/null')))));
    if (count($pids) !== 1 || !ctype_digit($pids[0])) {
        throw new RuntimeException('A/B listener changed');
    }
    $cmd = (string)shell_exec('/bin/ps eww -p ' . $pids[0] . ' -o command=');
    if (strpos($cmd, '-S 127.0.0.1:' . $port) === false
        || (strpos($cmd, $root . '/public') === false
            && strpos($cmd, str_replace('/private/tmp/', '/tmp/', $root) . '/public') === false)
        || strpos($cmd, 'PHP_CLI_SERVER_WORKERS=') !== false) {
        throw new RuntimeException('A/B runtime changed');
    }
    $local = '/Users/wiscourper/Documents/workspace/zhct/zhctproject/ai_api/.env.local';
    $ini = parse_ini_file($local, true, INI_SCANNER_RAW);
    if (!is_array($ini)) throw new RuntimeException('local config missing');
    foreach (['DATABASE' => 'POC_AI_', 'DATABASE_ZHCT' => 'POC_'] as $section => $prefix) {
        foreach (['HOSTNAME' => 'HOST', 'HOSTPORT' => 'PORT',
            'DATABASE' => 'SCHEMA', 'USERNAME' => 'USER', 'PASSWORD' => 'PASSWORD'] as $key => $suffix) {
            $value = (string)($ini[$section][$key] ?? '');
            $entry = preg_quote($prefix . $suffix . '=' . $value, '/');
            if ($value === '' || preg_match('/(?:^|\s)' . $entry . '(?=\s|$)/', $cmd) !== 1) {
                throw new RuntimeException('runtime/local DB mismatch');
            }
            $config[$prefix . $suffix] = $value;
        }
    }
}

$stage = 'database_identity';
$dialect = $target === 'C' ? 'dm' : 'mysql';
$connect = static function (string $prefix) use ($config, $dialect): PDO {
    $dsn = $dialect === 'dm'
        ? 'dm:host=' . $config[$prefix . 'HOST'] . ';port=' . $config[$prefix . 'PORT']
            . ';schema=' . $config[$prefix . 'SCHEMA']
        : 'mysql:host=' . $config[$prefix . 'HOST'] . ';port=' . $config[$prefix . 'PORT']
            . ';dbname=' . $config[$prefix . 'SCHEMA'] . ';charset=utf8';
    return new PDO($dsn, $config[$prefix . 'USER'], $config[$prefix . 'PASSWORD'],
        [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_TIMEOUT => 5]);
};
$ai = $connect('POC_AI_');
$store = $connect('POC_');
if ($dialect === 'dm') {
    foreach ([[$ai, 'AIZHCT_APP'], [$store, 'ZHCT_APP']] as $pair) {
        if (strtoupper((string)$pair[0]->query('SELECT USER FROM DUAL')->fetchColumn()) !== $pair[1]
            || strtoupper((string)$pair[0]->query(
                "SELECT SYS_CONTEXT('USERENV','CURRENT_SCHEMA') FROM DUAL")->fetchColumn()) !== $pair[1]) {
            throw new RuntimeException('DM schema identity changed');
        }
    }
} else {
    foreach ([[$ai, '210f925e093f71e26a8c8923f0f626e3be0a15ccff3d386bba21feef695c8a5b'],
        [$store, '003eb5aecf1cd4595b609c1f7f20b9ee325b578309fb9fe14fedaf77584fa401']] as $pair) {
        $identity = (string)$pair[0]->query(
            "SELECT CONCAT(@@server_uuid,'|',@@hostname,'|',@@port,'|',DATABASE())")->fetchColumn();
        if (hash('sha256', $identity) !== $pair[1]) {
            throw new RuntimeException('MySQL physical identity changed');
        }
    }
}

$stage = 'bounded_source_presence';
$tables = ['user', 'staff', 'cashout_order', 'recharge_order',
    'wxapp_setting', 'user_weight_status', 'user_course', 'drill_course'];
$present = [];
foreach ($tables as $table) {
    $name = $dialect === 'dm' ? 'YOSHOP_' . strtoupper($table) : 'yoshop_' . $table;
    $query = $dialect === 'dm'
        ? 'SELECT 1 FROM ' . $name . ' WHERE STORE_ID=10001 AND ROWNUM<=1'
        : 'SELECT 1 FROM ' . $name . ' WHERE store_id=10001 LIMIT 1';
    $present[$table] = $ai->query($query)->fetchColumn() !== false;
}
$storeUser = $dialect === 'dm' ? 'YDY_USER' : 'ydy_user';
$query = $dialect === 'dm' ? 'SELECT 1 FROM ' . $storeUser . ' WHERE ROWNUM<=1'
    : 'SELECT 1 FROM ' . $storeUser . ' LIMIT 1';
$present['store_user'] = $store->query($query)->fetchColumn() !== false;
echo json_encode(['status' => 'select_preflight_only', 'target' => $target,
    'identity' => 'matched', 'source_present' => $present,
    'http' => 0, 'dml' => 0], JSON_UNESCAPED_SLASHES), PHP_EOL;
