<?php
// Read-only DM5237 metadata probe. No DDL/DML/HTTP and no credential output.
if (($argv[1] ?? '') !== '--preflight') {
    fwrite(STDERR, "DENIED: --preflight required\n");
    exit(2);
}
$pid = 112175;
$raw = @file_get_contents('/proc/' . $pid . '/environ');
if ($raw === false) { throw new RuntimeException('fixed runtime env unavailable'); }
$env = [];
foreach (explode("\0", $raw) as $entry) {
    $pos = strpos($entry, '=');
    if ($pos !== false) { $env[substr($entry, 0, $pos)] = substr($entry, $pos + 1); }
}
if (($env['POC_HOST'] ?? '') !== '127.0.0.1' || ($env['POC_PORT'] ?? '') !== '5237'
    || strtoupper($env['POC_SCHEMA'] ?? '') !== 'ZHCT_APP'
    || strtoupper($env['POC_USER'] ?? '') !== 'ZHCT_APP') {
    throw new RuntimeException('fixed nonprod target mismatch');
}
$pdo = new PDO('dm:host=127.0.0.1;port=5237;schema=ZHCT_APP', $env['POC_USER'], $env['POC_PASSWORD'], [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
function rows(PDO $pdo, string $sql): array {
    try { return ['ok' => true, 'rows' => $pdo->query($sql)->fetchAll()]; }
    catch (Throwable $e) { return ['ok' => false, 'error_class' => get_class($e), 'error_hash' => hash('sha256', $e->getMessage())]; }
}
function scalar(PDO $pdo, string $sql) {
    $r = rows($pdo, $sql);
    return $r['ok'] ? ($r['rows'][0] ?? []) : $r;
}
$out = ['target' => ['pid' => $pid, 'host' => '127.0.0.1', 'port' => 5237, 'schema' => 'ZHCT_APP'],
    'identity' => scalar($pdo, 'SELECT USER AS LOGIN_USER, SYS_CONTEXT(\'USERENV\',\'CURRENT_SCHEMA\') AS CURRENT_SCHEMA FROM DUAL'),
    'instance_version' => scalar($pdo, 'SELECT SF_GET_DB_VERSION() AS DB_VERSION FROM DUAL'),
    'proposed_user_collision' => rows($pdo, "SELECT USERNAME FROM ALL_USERS WHERE USERNAME = 'CDX_BDAY_ISO_20261003'"),
    'sys_privileges' => rows($pdo, "SELECT PRIVILEGE FROM SESSION_PRIVS WHERE PRIVILEGE IN ('CREATE USER','CREATE TABLE','GRANT ANY PRIVILEGE','CREATE TABLESPACE') ORDER BY PRIVILEGE"),
    'tables' => []];
foreach (['YDY_CONFIG','YDY_USER','YDY_STAFF','YDY_BIRTHDAY_DISH','YDY_DISHES'] as $table) {
    $q = "'" . $table . "'";
    $item = [];
    $item['columns'] = rows($pdo, "SELECT COLUMN_ID,COLUMN_NAME,DATA_TYPE,DATA_LENGTH,DATA_PRECISION,DATA_SCALE,NULLABLE,IDENTITY_COLUMN,CASE WHEN DATA_DEFAULT IS NULL THEN 0 ELSE 1 END AS HAS_DEFAULT FROM USER_TAB_COLUMNS WHERE TABLE_NAME=$q ORDER BY COLUMN_ID");
    if (!$item['columns']['ok']) {
        $item['columns'] = rows($pdo, "SELECT COLUMN_ID,COLUMN_NAME,DATA_TYPE,DATA_LENGTH,DATA_PRECISION,DATA_SCALE,NULLABLE,CASE WHEN DATA_DEFAULT IS NULL THEN 0 ELSE 1 END AS HAS_DEFAULT FROM USER_TAB_COLUMNS WHERE TABLE_NAME=$q ORDER BY COLUMN_ID");
    }
    $item['constraints'] = rows($pdo, "SELECT CONSTRAINT_NAME,CONSTRAINT_TYPE,STATUS,R_CONSTRAINT_NAME FROM USER_CONSTRAINTS WHERE TABLE_NAME=$q ORDER BY CONSTRAINT_NAME");
    $item['indexes'] = rows($pdo, "SELECT I.INDEX_NAME,I.UNIQUENESS,C.COLUMN_POSITION,C.COLUMN_NAME FROM USER_INDEXES I JOIN USER_IND_COLUMNS C ON I.INDEX_NAME=C.INDEX_NAME WHERE I.TABLE_NAME=$q ORDER BY I.INDEX_NAME,C.COLUMN_POSITION");
    $item['triggers'] = rows($pdo, "SELECT TRIGGER_NAME,STATUS,TRIGGERING_EVENT FROM USER_TRIGGERS WHERE TABLE_NAME=$q ORDER BY TRIGGER_NAME");
    $item['segments'] = rows($pdo, "SELECT SEGMENT_NAME,SEGMENT_TYPE,BYTES FROM USER_SEGMENTS WHERE SEGMENT_NAME=$q OR SEGMENT_NAME IN (SELECT INDEX_NAME FROM USER_INDEXES WHERE TABLE_NAME=$q) ORDER BY SEGMENT_NAME");
    $item['table_stats'] = rows($pdo, "SELECT TABLE_NAME,NUM_ROWS,BLOCKS FROM USER_TABLES WHERE TABLE_NAME=$q");
    $item['ddl'] = rows($pdo, "SELECT DBMS_METADATA.GET_DDL('TABLE',$q) AS DDL FROM DUAL");
    if ($item['ddl']['ok']) {
        $rawDdl = (string)($item['ddl']['rows'][0]['DDL'] ?? '');
        preg_match('/"ID"\s+[^,\r\n)]+/i', $rawDdl, $idFragment);
        $item['ddl'] = ['ok' => true, 'bytes' => strlen($rawDdl), 'sha256' => hash('sha256', $rawDdl), 'id_definition' => $idFragment[0] ?? null];
    }
    $out['tables'][$table] = $item;
}
$compact = array_intersect_key($out, array_flip(['target','identity','instance_version','proposed_user_collision','sys_privileges']));
$compact['tables'] = [];
foreach ($out['tables'] as $table => $item) {
    $columns = $item['columns']['rows'] ?? [];
    $indexes = $item['indexes']['rows'] ?? [];
    $groups = [];
    foreach ($indexes as $index) {
        $name = $index['INDEX_NAME'];
        if (!isset($groups[$name])) { $groups[$name] = ['unique' => $index['UNIQUENESS'], 'columns' => []]; }
        $groups[$name]['columns'][] = $index['COLUMN_NAME'];
    }
    $compact['tables'][$table] = [
        'column_count' => count($columns),
        'required_without_default' => array_values(array_map(function ($c) { return $c['COLUMN_NAME'] . ':' . $c['DATA_TYPE']; }, array_filter($columns, function ($c) { return $c['NULLABLE'] === 'N' && (int)$c['HAS_DEFAULT'] === 0; }))),
        'constraints' => $item['constraints'], 'indexes' => $groups,
        'triggers' => $item['triggers'],
        'segment_bytes' => array_sum(array_column($item['segments']['rows'] ?? [], 'BYTES')),
        'segment_query_ok' => $item['segments']['ok'],
        'ddl' => $item['ddl'],
    ];
}
echo json_encode($compact, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_INVALID_UTF8_SUBSTITUTE), "\n";
