<?php
declare(strict_types=1);

// Read-only DDL, source and reference gate. No token, business HTTP or DML.
$lane = (string)($argv[1] ?? '');
$marker = (string)($argv[2] ?? '');
if (!in_array($lane, ['B', 'C'], true)
    || !preg_match('/^CDXSVC[0-9A-F]{12}$/', $marker)) {
    fwrite(STDERR, "DENIED: exact B|C and marker required\n");
    exit(78);
}
$root = $lane === 'B' ? '/private/tmp/zhct-http-ai-macos.x2CCZX'
    : '/tmp/zhct-ai-http-20260929.3XDj3w';
$pid = $lane === 'B' ? 13127 : 53772;
$port = $lane === 'B' ? 18101 : 18102;
if ($lane === 'B') {
    $cfg = parse_ini_file('/Users/wiscourper/Documents/workspace/zhct/zhctproject/ai_api/.env.local', true, INI_SCANNER_RAW)['DATABASE'] ?? null;
    $ps = (string)shell_exec('/bin/ps eww -p ' . $pid . ' -o command=');
    $owner = trim((string)shell_exec('/usr/sbin/lsof -nP -t -iTCP:' . $port . ' -sTCP:LISTEN 2>/dev/null'));
    if (!is_array($cfg) || strtolower((string)($cfg['TYPE'] ?? '')) !== 'mysql'
        || (string)($cfg['HOSTPORT'] ?? '') !== '3306' || $owner !== (string)$pid
        || strpos($ps, 'POC_DIALECT=mysql') === false
        || strpos($ps, 'POC_EXTERNAL_STUBS=1') === false) {
        throw new RuntimeException('B worker/config drift');
    }
    foreach (['HOSTNAME' => 'HOST', 'HOSTPORT' => 'PORT', 'DATABASE' => 'SCHEMA',
              'USERNAME' => 'USER', 'PASSWORD' => 'PASSWORD'] as $from => $to) {
        $v = (string)($cfg[$from] ?? '');
        if ($v === '' || strpos($ps, 'POC_AI_' . $to . '=' . $v) === false) {
            throw new RuntimeException('B worker differs from code local config');
        }
    }
    $db = new PDO('mysql:host=' . $cfg['HOSTNAME'] . ';port=' . $cfg['HOSTPORT']
        . ';dbname=' . $cfg['DATABASE'] . ';charset=utf8', $cfg['USERNAME'], $cfg['PASSWORD'],
        [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_CASE => PDO::CASE_LOWER]);
} else {
    $env = [];
    foreach (explode("\0", (string)file_get_contents('/proc/' . $pid . '/environ')) as $item) {
        $pair = explode('=', $item, 2);
        if (count($pair) === 2) $env[$pair[0]] = $pair[1];
    }
    if (($env['POC_TARGET_ROOT'] ?? '') !== $root
        || ($env['POC_BASE_URL'] ?? '') !== 'http://127.0.0.1:' . $port
        || ($env['POC_DIALECT'] ?? '') !== 'dm'
        || ($env['POC_EXTERNAL_STUBS'] ?? '') !== '1'
        || ($env['POC_AI_HOST'] ?? '') !== '127.0.0.1'
        || ($env['POC_AI_PORT'] ?? '') !== '5238'
        || ($env['POC_AI_SCHEMA'] ?? '') !== 'AIZHCT_APP'
        || ($env['POC_AI_USER'] ?? '') !== 'AIZHCT_APP'
        || !in_array('dm', PDO::getAvailableDrivers(), true)) {
        throw new RuntimeException('C worker/config drift');
    }
    $db = new PDO('dm:host=127.0.0.1;port=5238;schema=AIZHCT_APP',
        $env['POC_AI_USER'], $env['POC_AI_PASSWORD'],
        [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_CASE => PDO::CASE_LOWER]);
    if ($db->query("SELECT SYS_CONTEXT('USERENV','CURRENT_SCHEMA') FROM DUAL")->fetchColumn() !== 'AIZHCT_APP') {
        throw new RuntimeException('C schema drift');
    }
}
$loader = require $root . '/vendor/autoload.php';
if (!is_object($loader) || !method_exists($loader, 'findFile')) {
    throw new RuntimeException('Composer loader absent');
}
$classes = [
    'app\\store\\controller\\goods\\Service',
    'app\\store\\model\\goods\\Service',
    'app\\store\\model\\goods\\ServiceRel',
    'app\\common\\model\\goods\\Service',
];
$actualSources = [];
foreach ($classes as $class) {
    $file = $loader->findFile($class);
    $real = is_string($file) ? realpath($file) : false;
    if (!is_string($real) || !is_file($real)) {
        throw new RuntimeException('Actual source unresolved');
    }
    $actualSources[$class] = hash_file('sha256', $real);
}
$table = $lane === 'B' ? 'yoshop_goods_service' : 'YOSHOP_GOODS_SERVICE';
$rel = $lane === 'B' ? 'yoshop_goods_service_rel' : 'YOSHOP_GOODS_SERVICE_REL';
$count = static function (PDO $d, string $sql, array $args = []): int {
    $s = $d->prepare($sql);
    $s->execute($args);
    return (int)$s->fetchColumn();
};
$rows = static function (PDO $d, string $sql, array $args = []): array {
    $s = $d->prepare($sql);
    $s->execute($args);
    return $s->fetchAll(PDO::FETCH_ASSOC);
};
if ($lane === 'B') {
    $columns = $rows($db, 'SELECT COLUMN_NAME,DATA_TYPE,COLUMN_TYPE,IS_NULLABLE,COLUMN_DEFAULT,EXTRA FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME=? ORDER BY ORDINAL_POSITION', [$table]);
    $indexes = $rows($db, 'SELECT INDEX_NAME,NON_UNIQUE,SEQ_IN_INDEX,COLUMN_NAME FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME=? ORDER BY INDEX_NAME,SEQ_IN_INDEX', [$table]);
    $triggers = $rows($db, 'SELECT EVENT_OBJECT_TABLE,TRIGGER_NAME FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_SCHEMA=DATABASE() AND EVENT_OBJECT_TABLE IN (?,?)', [$table, $rel]);
    $fks = $rows($db, 'SELECT TABLE_NAME,COLUMN_NAME,REFERENCED_TABLE_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE TABLE_SCHEMA=DATABASE() AND REFERENCED_TABLE_NAME IS NOT NULL AND (TABLE_NAME IN (?,?) OR REFERENCED_TABLE_NAME IN (?,?))', [$table, $rel, $table, $rel]);
    $refs = $rows($db, "SELECT TABLE_NAME,COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME LIKE 'yoshop_%' AND UPPER(COLUMN_NAME)='SERVICE_ID' ORDER BY TABLE_NAME", []);
    $identity = array_values(array_map(static function (array $r): string {
        return strtoupper((string)$r['column_name']);
    }, array_filter($columns, static function (array $r): bool {
        return stripos((string)$r['extra'], 'auto_increment') !== false;
    })));
} else {
    $columns = $rows($db, 'SELECT COLUMN_NAME,DATA_TYPE,DATA_LENGTH,DATA_PRECISION,DATA_SCALE,NULLABLE,DATA_DEFAULT FROM USER_TAB_COLUMNS WHERE TABLE_NAME=? ORDER BY COLUMN_ID', [$table]);
    $indexes = $rows($db, 'SELECT INDEX_NAME,COLUMN_POSITION,COLUMN_NAME FROM USER_IND_COLUMNS WHERE TABLE_NAME=? ORDER BY INDEX_NAME,COLUMN_POSITION', [$table]);
    $triggers = $rows($db, "SELECT TABLE_NAME,TRIGGER_NAME FROM USER_TRIGGERS WHERE TABLE_NAME IN ('YOSHOP_GOODS_SERVICE','YOSHOP_GOODS_SERVICE_REL')", []);
    $fks = $rows($db, "SELECT TABLE_NAME,CONSTRAINT_NAME FROM USER_CONSTRAINTS WHERE CONSTRAINT_TYPE='R' AND (TABLE_NAME IN ('YOSHOP_GOODS_SERVICE','YOSHOP_GOODS_SERVICE_REL') OR R_CONSTRAINT_NAME IN (SELECT CONSTRAINT_NAME FROM USER_CONSTRAINTS WHERE TABLE_NAME IN ('YOSHOP_GOODS_SERVICE','YOSHOP_GOODS_SERVICE_REL')))", []);
    $refs = $rows($db, "SELECT TABLE_NAME,COLUMN_NAME FROM USER_TAB_COLUMNS WHERE TABLE_NAME LIKE 'YOSHOP_%' AND COLUMN_NAME='SERVICE_ID' ORDER BY TABLE_NAME", []);
    $s = $db->prepare('CALL SP_TABLEDEF(?, ?)');
    $s->execute(['AIZHCT_APP', $table]);
    $ddl = $s->fetchColumn();
    if (is_resource($ddl)) $ddl = stream_get_contents($ddl);
    if (!is_string($ddl) || $ddl === '') throw new RuntimeException('DM DDL absent');
    preg_match_all('/"([A-Za-z_][A-Za-z0-9_]*)"\s+[A-Za-z0-9_]+(?:\([^)]*\))?\s+(?:AUTO_INCREMENT|IDENTITY\b)/i', $ddl, $matches);
    $identity = array_map('strtoupper', $matches[1]);
}
if (count($columns) !== 10 || $identity !== ['SERVICE_ID']
    || count($triggers) !== 0 || count($fks) !== 0) {
    throw new RuntimeException('Service schema/side-effect gate drift');
}
if (count($refs) > 100) throw new RuntimeException('Service reference metadata cap');
$snap = [];
foreach (['service' => [$table, 'SERVICE_ID'], 'relation' => [$rel, 'ID']] as $logical => [$name, $pk]) {
    $s = $db->query('SELECT * FROM ' . $name
        . ' WHERE STORE_ID=10001 ORDER BY ' . $pk);
    $h = hash_init('sha256');
    $n = 0;
    while (($r = $s->fetch(PDO::FETCH_NUM)) !== false) {
        hash_update($h, serialize($r));
        if (++$n > 30000) throw new RuntimeException('Source cap exceeded');
    }
    $snap[$logical] = ['count' => $n, 'sha256' => hash_final($h)];
}
$markCount = $count($db, 'SELECT COUNT(*) FROM ' . $table
    . ' WHERE STORE_ID=10001 AND NAME=?', [$marker]);
echo json_encode(['lane' => $lane, 'worker_port' => $port,
    'marker' => $marker, 'actual_source_sha256' => $actualSources,
    'columns' => $columns, 'indexes' => $indexes,
    'identity_columns' => $identity, 'triggers' => $triggers,
    'foreign_keys' => $fks, 'service_id_reference_columns' => $refs,
    'natural_source' => $snap, 'marker_count' => $markCount,
    'business_http' => 0, 'business_dml' => 0], JSON_UNESCAPED_SLASHES), "\n";
