<?php

declare(strict_types=1);

// Store five-read candidate preflight. There is deliberately NO business HTTP or DML path.
// A formal runner must be separately reviewed before an --execute mode is introduced.
set_exception_handler(static function (Throwable $e): void {
    fwrite(STDERR, 'NEXT5_PREFLIGHT_FAIL ' . get_class($e) . ':'
        . hash('sha256', $e->getMessage()) . PHP_EOL);
    exit(1);
});
if (($argv[1] ?? '') !== '--preflight') {
    fwrite(STDERR, "NEXT5 formal HTTP and DML disabled\n");
    exit(78);
}
$lane = (string)getenv('CDX_NEXT5_LANE');
$targets = [
    'A' => ['/tmp/zhct-http-store-a.l5omH8', 'http://127.0.0.1:18097', 21023, 'mysql'],
    'B' => ['/tmp/zhct-http-store-mysql.dQTTBP', 'http://127.0.0.1:18081', 10001, 'mysql'],
    'C' => ['/tmp/zhct-dm-poc-20260928.fcpiiN/store', 'http://127.0.0.1:18080', 112175, 'dm'],
];
if (!isset($targets[$lane])) throw new RuntimeException('Unapproved lane');
[$root, $base, $pid, $dialect] = $targets[$lane];
if ((string)getenv('POC_APP_ROOT') !== $root
    || (string)getenv('POC_BASE_URL') !== $base
    || (string)getenv('POC_DIALECT') !== $dialect
    || is_link($root)) throw new RuntimeException('Isolated target drift');
$fixed = [
    'application/config.php' => 'f80bb19246c84a13b2000c445aa3174aed03a9e5d6666d559eabde773c6ca7a3',
    'application/database.php' => $dialect === 'dm'
        ? '86c29ff71adfe33e02f345e4f0892d3be0772c5b97912f6602c4ad54f97d780d'
        : 'e152fe35b9c792fd7edf20dc4131cf9633d8fc0bc03075b65c2836251bae2108',
    'public/router.php' => '2d444eeca77269f60826653e5d0d4a51071f7d7f1826b623dda2391dd2f35380',
    'public/index.php' => $dialect === 'dm'
        ? 'f5e26a7b4bc9bd5ced50dfba5f43972e07a692abece1d8fdde52a0713c5c8448'
        : 'c333605da346af58b46bdea84038e183f87850c1c2d162eb60ab2aa5292d776b',
    'application/p/controller/Staff.php' => '58b27afaaea3562ba4ed32a696133a1b42171cd18ce647b6e7588f911c3aa71d',
    'application/p/logic/Staff.php' => '7c2892e3848926e03fe9e56ac32c6f9c122aa46c27b5de36e30cce597ff5585f',
    'application/model/Staff.php' => $lane === 'A'
        ? '18139997f481d40cf01c489cb8bf8ddd5e625170243b923042e40215e9419f80'
        : 'e709b91af8e78758b0adbb29697dba4d16d62402d8c365712afe9c47e72277d3',
    'application/model/Sport.php' => $lane === 'A'
        ? '1f4570973a9d92aa7bd0f5908b66916fcc06f5948c2520e964b0de09ef1e903d'
        : '0926a7240a54afbe8c0435c26810c2f3745fe3645d2e11c1dcb607f76a4eee01',
    'application/p/controller/DateMenu.php' => '792b56de2dc42d36e19fc1d0f852cd853dab8f7768c06276070d02a9bfc76013',
    'application/p/logic/DateMenu.php' => '6005b9ee832735c1fc81073dabc1cbd27cbee30635757916d546131849c2c62b',
    'application/model/User.php' => $lane === 'A'
        ? '95ce9bcee0f908ace8c86c1978ed9e41791e56a3ab53d53de17972d12e908341'
        : '8953e4be37bb3a1f6adf40c9da9b19de5e3eb2f61d595812b080a66bec10b7c2',
];
foreach ($fixed as $relative => $sha) {
    $file = $root . '/' . $relative;
    if (!is_file($file) || is_link($file) || hash_file('sha256', $file) !== $sha) {
        throw new RuntimeException('Isolated source drift: ' . $relative);
    }
}
$configRoot = $root . '/application/config';
$cacheRoot = $root . '/runtime/cache';
if (!is_dir($configRoot) || is_link($configRoot)
    || !is_dir($cacheRoot) || is_link($cacheRoot)
    || strpos((string)realpath($cacheRoot), $root . '/runtime/cache') !== 0) {
    throw new RuntimeException('Config/cache boundary drift');
}
$manifest = [];
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator(
    $configRoot, FilesystemIterator::SKIP_DOTS));
foreach ($iterator as $file) {
    if ($file->isLink() || !$file->isFile()) throw new RuntimeException('Config tree drift');
    $manifest[] = substr($file->getPathname(), strlen($configRoot) + 1)
        . ':' . hash_file('sha256', $file->getPathname());
}
sort($manifest, SORT_STRING);
$expectedManifest = $lane === 'A'
    ? [62, '631ed07380400b9bf3f69f11f67699d287fe784677dadc3a721ded34eab43d9c']
    : ($lane === 'B'
        ? [64, '8e7f8932cdccefff532273b886488070e5b5f97c4810408d488cd7064cc3f303']
        : [2, '460c5f4141aafb21679669ab037c77217ac28c964732bf858632a7bae967f15b']);
if (count($manifest) !== $expectedManifest[0]
    || hash('sha256', implode('|', $manifest)) !== $expectedManifest[1]) {
    throw new RuntimeException('Config tree manifest drift');
}
$port = (int)parse_url($base, PHP_URL_PORT);
$cmdline = (string)@file_get_contents('/proc/' . $pid . '/cmdline');
$environment = (string)@file_get_contents('/proc/' . $pid . '/environ');
$children = (string)@file_get_contents('/proc/' . $pid . '/task/' . $pid . '/children');
$boundary = json_decode((string)@file_get_contents($base . '/__poc_boundary'), true);
$listenHex = strtoupper(str_pad(dechex($port), 4, '0', STR_PAD_LEFT));
$inode = '';
foreach (@file('/proc/net/tcp', FILE_IGNORE_NEW_LINES) ?: [] as $line) {
    $part = preg_split('/\s+/', trim($line));
    if (($part[1] ?? '') === '0100007F:' . $listenHex && ($part[3] ?? '') === '0A') {
        $inode = (string)($part[9] ?? '');
        break;
    }
}
$ownsSocket = false;
if ($inode !== '') foreach (@scandir('/proc/' . $pid . '/fd') ?: [] as $fd) {
    if ($fd !== '.' && $fd !== '..'
        && @readlink('/proc/' . $pid . '/fd/' . $fd) === 'socket:[' . $inode . ']') {
        $ownsSocket = true;
        break;
    }
}
if (!$ownsSocket || strpos($cmdline, '127.0.0.1:' . $port) === false
    || strpos($cmdline, $root . '/public') === false || $environment === ''
    || trim($children) !== ''
    || preg_match('/(?:^|\x00)PHP_CLI_SERVER_WORKERS=(\d+)(?:\x00|$)/', $environment, $m)
        && (int)$m[1] > 1
    || !is_array($boundary) || empty($boundary['external_stubs'])
    || empty($boundary['redis_isolated']) || !empty($boundary['real_queue'])) {
    throw new RuntimeException('Isolated HTTP process/boundary drift');
}
$runtime = require $root . '/application/database.php';
if (!is_array($runtime) || (string)($runtime['prefix'] ?? '') !== 'ydy_') {
    throw new RuntimeException('Runtime DB config invalid');
}
if ($dialect === 'mysql') {
    $local = require '/workspace/zhct/zhctproject/store/application/config/local/database.php';
    if ((string)($runtime['type'] ?? '') !== 'mysql'
        || !in_array((string)($runtime['charset'] ?? ''), ['utf8', 'utf8mb4'], true)) {
        throw new RuntimeException('Code-local MySQL required');
    }
    foreach (['hostname', 'database', 'username', 'password'] as $key) {
        if (($runtime[$key] ?? null) !== ($local[$key] ?? null)) {
            throw new RuntimeException('Runtime differs from code local');
        }
    }
    if ((int)($runtime['hostport'] ?? 3306) !== (int)($local['hostport'] ?? 3306)) {
        throw new RuntimeException('Runtime MySQL port differs from code local');
    }
    $dsn = 'mysql:host=' . $runtime['hostname'] . ';port='
        . (int)($runtime['hostport'] ?? 3306) . ';dbname=' . $runtime['database']
        . ';charset=' . $runtime['charset'];
    $approvedDbSha = '003eb5aecf1cd4595b609c1f7f20b9ee325b578309fb9fe14fedaf77584fa401';
    $prefix = 'ydy_';
} else {
    if ((string)($runtime['type'] ?? '') !== 'app\\cores\\database\\Dm'
        || (string)getenv('POC_HOST') !== '127.0.0.1'
        || (string)getenv('POC_PORT') !== '5237'
        || strtoupper((string)getenv('POC_SCHEMA')) !== 'ZHCT_APP'
        || strtoupper((string)getenv('POC_USER')) !== 'ZHCT_APP') {
        throw new RuntimeException('Nonproduction DM target drift');
    }
    foreach (['hostname' => 'POC_HOST', 'hostport' => 'POC_PORT',
        'database' => 'POC_SCHEMA', 'username' => 'POC_USER',
        'password' => 'POC_PASSWORD'] as $key => $env) {
        if ((string)($runtime[$key] ?? '') !== (string)getenv($env)) {
            throw new RuntimeException('DM worker context drift');
        }
    }
    $machine = trim((string)@file_get_contents('/etc/machine-id'));
    if ($machine === '' || hash('sha256', gethostname() . '|' . $machine)
        !== 'd56d81988bb0f106946cce91c608fdd0ef1116e5150b23376ea87e086eace4b9') {
        throw new RuntimeException('DM host drift');
    }
    $listeners = [];
    @exec('/usr/sbin/ss -ltnp 2>/dev/null', $listeners);
    $dmLocal = false;
    foreach ($listeners as $line) {
        if (preg_match('/\*:5237\s+.*users:\(\("dmserver",pid=(\d+),/', $line, $m)) {
            $dmLocal = basename((string)@readlink('/proc/' . $m[1] . '/exe')) === 'dmserver';
            break;
        }
    }
    if (!$dmLocal) throw new RuntimeException('Nonproduction DM listener drift');
    $dsn = 'dm:host=127.0.0.1;port=5237;schema=ZHCT_APP';
    $approvedDbSha = 'bc98485aed26beab348770a82ae38dbf922b04ab88a210cd7282c4caf0156194';
    $prefix = 'YDY_';
}
try {
    $db = new PDO($dsn, (string)$runtime['username'], (string)$runtime['password'],
        [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_CASE => PDO::CASE_LOWER, PDO::ATTR_TIMEOUT => 5]);
} catch (Throwable $e) {
    throw new RuntimeException('Approved DB unavailable: ' . get_class($e));
}
$identity = $dialect === 'dm'
    ? 'ZHCT_APP|5237|' . (string)$db->query(
        "SELECT SYS_CONTEXT('USERENV','CURRENT_SCHEMA') FROM DUAL")->fetchColumn()
    : (string)$db->query(
        "SELECT CONCAT(@@server_uuid,'|',@@hostname,'|',@@port,'|',DATABASE())")
        ->fetchColumn();
if (!hash_equals($approvedDbSha, hash('sha256', $identity))) {
    throw new RuntimeException('Approved DB identity drift');
}
$query = static function (PDO $pdo, string $sql, array $args = []): array {
    $stmt = $pdo->prepare($sql);
    $stmt->execute($args);
    return array_change_key_case($stmt->fetch(PDO::FETCH_ASSOC) ?: [], CASE_LOWER);
};
$table = static function (string $name) use ($prefix, $dialect): string {
    return $prefix . ($dialect === 'dm' ? strtoupper($name) : strtolower($name));
};
$sport = $query($db, 'SELECT COUNT(*) AS N FROM ' . $table('sport'));
$departments = $query($db, 'SELECT COUNT(*) AS N FROM ' . $table('department')
    . ' WHERE STATUS=1 AND IS_SHOW=1');
$staffRel = $query($db, 'SELECT COUNT(*) AS N FROM ' . $table('staff')
    . ' s JOIN ' . $table('staff_department') . ' sd ON sd.STAFF_UUID=s.UUID'
    . ' JOIN ' . $table('department') . ' d ON d.UUID=sd.DEPARTMENT_UUID'
    . ' WHERE s.IS_SHOW=1 AND d.STATUS=1 AND d.IS_SHOW=1');
$athleteRel = $query($db, 'SELECT COUNT(*) AS N FROM ' . $table('staff')
    . ' s JOIN ' . $table('staff_department') . ' sd ON sd.STAFF_UUID=s.UUID'
    . ' JOIN ' . $table('department') . ' d ON d.UUID=sd.DEPARTMENT_UUID'
    . ' WHERE s.IS_SHOW=1 AND s.IS_ATHLETE=1 AND d.STATUS=1 AND d.IS_SHOW=1');
$recommend = $query($db, 'SELECT COUNT(*) AS N FROM ' . $table('menu_recommend'));
foreach (['sport' => $sport, 'active_department' => $departments,
    'visible_staff_relation' => $staffRel, 'athlete_relation' => $athleteRel,
    'menu_recommend' => $recommend] as $name => $row) {
    if ((int)($row['n'] ?? 0) < 1) throw new RuntimeException('Natural source empty: ' . $name);
    echo $name . '=' . (int)$row['n'] . PHP_EOL;
}
$candidateSql = 'SELECT d.UUID AS DEPARTMENT_UUID, COUNT(DISTINCT s.UUID) AS STAFF_COUNT'
    . ' FROM ' . $table('department') . ' d'
    . ' JOIN ' . $table('staff_department') . ' sd ON sd.DEPARTMENT_UUID=d.UUID'
    . ' JOIN ' . $table('staff') . ' s ON s.UUID=sd.STAFF_UUID'
    . ' WHERE d.STATUS=1 AND d.IS_SHOW=1 AND s.IS_SHOW=1 AND s.IS_ATHLETE=1'
    . ' AND NOT EXISTS (SELECT 1 FROM ' . $table('department')
    . ' child WHERE child.PUUID=d.UUID AND child.STATUS=1 AND child.IS_SHOW=1)'
    . ' GROUP BY d.UUID HAVING COUNT(DISTINCT s.UUID) BETWEEN 1 AND 8'
    . ' ORDER BY STAFF_COUNT DESC, d.UUID';
$candidateStmt = $db->query($candidateSql);
$candidates = $candidateStmt->fetchAll(PDO::FETCH_ASSOC);
if (count($candidates) < 1 || count($candidates) > 2500) {
    throw new RuntimeException('Leaf athlete department window unavailable/unbounded');
}
$selected = array_change_key_case($candidates[0], CASE_LOWER);
$dept = (string)$selected['department_uuid'];
$athletes = $db->prepare('SELECT s.UUID FROM ' . $table('staff') . ' s'
    . ' JOIN ' . $table('staff_department') . ' sd ON sd.STAFF_UUID=s.UUID'
    . ' WHERE sd.DEPARTMENT_UUID=? AND s.IS_SHOW=1 AND s.IS_ATHLETE=1'
    . ' ORDER BY s.UUID');
$athletes->execute([$dept]);
$staffUuids = array_values(array_unique(array_map('strval', $athletes->fetchAll(PDO::FETCH_COLUMN))));
if (count($staffUuids) !== (int)$selected['staff_count']
    || count($staffUuids) < 1 || count($staffUuids) > 8) {
    throw new RuntimeException('Leaf athlete source count drift');
}
$ordinary = $query($db, 'SELECT COUNT(DISTINCT s.UUID) AS N FROM '
    . $table('staff') . ' s JOIN ' . $table('staff_department')
    . ' sd ON sd.STAFF_UUID=s.UUID WHERE sd.DEPARTMENT_UUID=? AND s.IS_SHOW=1', [$dept]);
if ((int)($ordinary['n'] ?? 0) < 1 || (int)$ordinary['n'] > 15) {
    throw new RuntimeException('Menu list leaf department unbounded');
}
$bind = implode(',', array_fill(0, count($staffUuids), '?'));
$menu = $query($db, 'SELECT COUNT(*) AS N, MAX(MENU_DATE) AS LAST_DATE FROM '
    . $table('menu_recommend') . ' WHERE STAFF_UUID IN (' . $bind . ')', $staffUuids);
$lastDate = (string)($menu['last_date'] ?? '');
if ($lastDate !== '' && !preg_match('/^\d{4}-\d{2}-\d{2}/', $lastDate)) {
    throw new RuntimeException('Menu date format unexpected');
}
echo 'leaf_candidates=' . count($candidates)
    . ' leaf_department_sha12=' . substr(hash('sha256', $dept), 0, 12)
    . ' athlete_staff=' . count($staffUuids)
    . ' visible_staff=' . (int)$ordinary['n']
    . ' menu_rows=' . (int)($menu['n'] ?? 0)
    . ' menu_last_date=' . substr($lastDate, 0, 10) . PHP_EOL;
echo 'lane=' . $lane . ' dialect=' . $dialect
    . ' source_and_boundary=locked business_http=0 dml=0' . PHP_EOL;
