<?php

declare(strict_types=1);

// A/B/C team-monitor five-read preflight. SELECT-only by construction.
set_exception_handler(static function (Throwable $e): void {
    fwrite(STDERR, 'TEAM5_PREFLIGHT_FAIL ' . get_class($e) . ':'
        . hash('sha256', $e->getMessage()) . PHP_EOL);
    exit(1);
});
if (($argv[1] ?? '') !== '--preflight') {
    fwrite(STDERR, "TEAM5 HTTP and DML disabled\n");
    exit(78);
}
$lane = (string)getenv('CDX_NEXT5_LANE');
$parentPreflight = $lane === 'C'
    ? '/tmp/zhct-next5-readonly-20261004/preflight_next5.php'
    : '/workspace/zhct/zhctprompt/work_store/apifox/2026-09-30-dm8-interface-acceptance/parallel-store-next5-readonly/preflight_next5.php';
if (!in_array($lane, ['A', 'B', 'C'], true)
    || !is_file($parentPreflight) || is_link($parentPreflight)
    || hash_file('sha256', $parentPreflight)
        !== 'e8e94b6cd6960ba2e8f1420c8d2520fb36ed8c41d8b928d047824c621a4c6c3e') {
    throw new RuntimeException('Parent isolation preflight absent or drifted');
}
require $parentPreflight; // Fixed local MySQL/nonproduction DM identity, PID/config/source, bounded leaf.
$stageSources = [
    'application/p/controller/Stageanalyze.php'
        => 'd08efcdced301f62d1602b6ded7f038860c6692d142ebfdf13cfd06e0e762474',
    'application/p/logic/Stageanalyze.php'
        => 'bf806025a3430a4941b280ab770ba693cf8e47150dd54cae0249ec11543843ad',
    'application/model/MenuRecommend.php'
        => '93cd644f5ac965702165fd206b788d3d381e18edb3d6904c94851a7b8611af6c',
    'application/model/DateMenu.php'
        => '61dd192dc186c334346bac06fb50243dc9dceb6315e75b836b2132b7c6173154',
    'application/model/Dishes.php'
        => 'e6f7a03b0adc458a3ed2042b6fead04b479e1793a79528f3e66ac641446a60b9',
];
foreach ($stageSources as $file => $sha) {
    $path = $root . '/' . $file;
    if (!is_file($path) || is_link($path) || hash_file('sha256', $path) !== $sha) {
        throw new RuntimeException('Team monitor source drift: ' . $file);
    }
}
$limit = static function (PDO $pdo, string $sql, array $args, int $cap): array {
    $stmt = $pdo->prepare($sql);
    $stmt->execute($args);
    $out = [];
    while (($row = $stmt->fetch(PDO::FETCH_ASSOC)) !== false) {
        if (count($out) >= $cap) throw new RuntimeException('Natural source cap exceeded');
        $clean = [];
        foreach (array_change_key_case($row, CASE_LOWER) as $key => $value) {
            $clean[$key] = is_resource($value) ? stream_get_contents($value) : $value;
        }
        $out[] = $clean;
    }
    return $out;
};
$in = implode(',', array_fill(0, count($staffUuids), '?'));
if (count($staffUuids) < 1 || count($staffUuids) > 8) {
    throw new RuntimeException('Team athlete set unbounded');
}
$dates = $limit($db, 'SELECT dm.MENU_DATE AS MENU_DATE,'
    . ' COUNT(*) AS ACTUAL_ROWS,COUNT(DISTINCT dm.STAFF_UUID) AS STAFF_COUNT'
    . ' FROM ' . $table('date_menu') . ' dm JOIN '
    . $table('menu_recommend') . ' mr ON mr.UUID=dm.RECOMMEND_UUID'
    . ' AND mr.STAFF_UUID=dm.STAFF_UUID'
    . ' WHERE dm.STAFF_UUID IN (' . $in . ') AND dm.MEAL_TYPE=3'
    . ' GROUP BY dm.MENU_DATE HAVING COUNT(*) BETWEEN 1 AND 100',
    $staffUuids, 250);
if (!$dates) throw new RuntimeException('No actual meal date in bounded natural staff set');
usort($dates, static function (array $a, array $b): int {
    $count = (int)$b['actual_rows'] <=> (int)$a['actual_rows'];
    return $count !== 0 ? $count : strcmp((string)$b['menu_date'], (string)$a['menu_date']);
});
$selected = $dates[0];
$rawDate = (string)$selected['menu_date'];
$day = substr($rawDate, 0, 10);
if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $day)
    || (int)$selected['actual_rows'] < 1
    || (int)$selected['actual_rows'] > 100) {
    throw new RuntimeException('Selected actual meal date invalid');
}
$actualRows = $limit($db, 'SELECT dm.STAFF_UUID,dm.MENU_DATE,dm.MEAL_TYPE,'
    . ' dm.MEAL_TIMES,dm.NUMBER,dm.DISHES_UUID,dm.RECOMMEND_UUID,'
    . ' mr.TOTAL_POWER,mr.PRESCRIPTION_POWER,d.ENERGY'
    . ' FROM ' . $table('date_menu') . ' dm JOIN '
    . $table('menu_recommend') . ' mr ON mr.UUID=dm.RECOMMEND_UUID'
    . ' AND mr.STAFF_UUID=dm.STAFF_UUID LEFT JOIN '
    . $table('dishes') . ' d ON d.UUID=dm.DISHES_UUID'
    . ' WHERE dm.STAFF_UUID IN (' . $in . ') AND dm.MEAL_TYPE=3'
    . ' AND dm.MENU_DATE=?', array_merge($staffUuids, [$rawDate]), 101);
if (count($actualRows) !== (int)$selected['actual_rows']) {
    throw new RuntimeException('Actual meal selected-date count drift');
}
$nonNullDishes = 0;
$staffSeen = [];
foreach ($actualRows as $row) {
    if (is_numeric($row['energy'] ?? null)) $nonNullDishes++;
    $staffSeen[(string)$row['staff_uuid']] = true;
}
if ($nonNullDishes < 1 || count($staffSeen) !== (int)$selected['staff_count']) {
    throw new RuntimeException('Actual dish energy/staff source unavailable');
}
$canonical = [];
foreach ($actualRows as $row) {
    ksort($row, SORT_STRING);
    $canonical[] = serialize($row);
}
sort($canonical, SORT_STRING);
$dateSourceSha = hash('sha256', implode("\n", $canonical));
$dateObj = DateTimeImmutable::createFromFormat('!Y-m-d', $day);
if (!$dateObj) throw new RuntimeException('Natural date parse failed');
$range = [$dateObj->modify('-1 day')->format('Y-m-d'),
    $dateObj->modify('+1 day')->format('Y-m-d')];
$namesStmt = $db->prepare('SELECT UUID,NAME FROM ' . $table('staff')
    . ' WHERE UUID IN (' . $in . ') AND IS_SHOW=1');
$namesStmt->execute($staffUuids);
$nameRows = $namesStmt->fetchAll(PDO::FETCH_ASSOC);
if (count($nameRows) !== count($staffUuids)) {
    throw new RuntimeException('Bounded staff-name source count drift');
}
$names = [];
foreach ($nameRows as $nameRow) {
    $nameRow = array_change_key_case($nameRow, CASE_LOWER);
    $names[] = (string)$nameRow['name'];
}
if (count(array_unique($names)) !== count($names)) {
    throw new RuntimeException('Duplicate staff names make monitor result ambiguous');
}
$rangeRows = $limit($db, 'SELECT dm.STAFF_UUID,dm.MENU_DATE,dm.MEAL_TYPE,'
    . ' dm.MEAL_TIMES,dm.NUMBER,dm.DISHES_UUID,dm.RECOMMEND_UUID,'
    . ' mr.TOTAL_POWER,mr.PRESCRIPTION_POWER,d.ENERGY'
    . ' FROM ' . $table('date_menu') . ' dm JOIN '
    . $table('menu_recommend') . ' mr ON mr.UUID=dm.RECOMMEND_UUID'
    . ' AND mr.STAFF_UUID=dm.STAFF_UUID LEFT JOIN '
    . $table('dishes') . ' d ON d.UUID=dm.DISHES_UUID'
    . ' WHERE dm.STAFF_UUID IN (' . $in . ') AND dm.MEAL_TYPE=3'
    . ' AND dm.MENU_DATE BETWEEN ? AND ?',
    array_merge($staffUuids, $range), 301);
if (count($rangeRows) < count($actualRows)) {
    throw new RuntimeException('Three-day actual source excludes selected date');
}
$rangeCanonical = [];
foreach ($rangeRows as $row) {
    ksort($row, SORT_STRING);
    $rangeCanonical[] = serialize($row);
}
sort($rangeCanonical, SORT_STRING);
$rangeSourceSha = hash('sha256', implode("\n", $rangeCanonical));
echo json_encode(['lane' => $lane, 'mode' => 'select-only',
    'leaf_department_sha12' => substr(hash('sha256', $dept), 0, 12),
    'athletes' => count($staffUuids), 'visible_staff' => (int)$ordinary['n'],
    'date_candidates' => count($dates), 'selected_day' => $day,
    'selected_day_actual_rows' => count($actualRows),
    'selected_day_actual_staff' => count($staffSeen),
    'selected_day_with_energy_rows' => $nonNullDishes,
    'selected_day_source_sha' => $dateSourceSha,
    'three_day_range' => $range,
    'three_day_actual_rows' => count($rangeRows),
    'three_day_source_sha' => $rangeSourceSha,
    'unique_staff_names' => true,
    'business_http' => 0, 'dml' => 0], JSON_UNESCAPED_SLASHES), PHP_EOL;
