<?php
declare(strict_types=1);

// Two bounded Store report POSTs. Default is SELECT-only preflight; execution
// creates one random type-0 operator and deletes that exact row in finally.
$lane = (string)getenv('CDX_DETAIL2_LANE');
$action = (string)($argv[1] ?? '');
$targets = [
    'A' => ['/tmp/zhct-http-store-a.l5omH8', 'http://127.0.0.1:18097', 21023, 'mysql',
        '04e3f80cb0dddff6ec657f731185013ffffebcb4da48be8402b6d86547e14742',
        '95ce9bcee0f908ace8c86c1978ed9e41791e56a3ab53d53de17972d12e908341'],
    'B' => ['/tmp/zhct-http-store-mysql.dQTTBP', 'http://127.0.0.1:18081', 10001, 'mysql',
        '0581772a6831c86210372684867a5da5cb722855ef52ebfaf6776e1a6f971702',
        '8953e4be37bb3a1f6adf40c9da9b19de5e3eb2f61d595812b080a66bec10b7c2'],
    'C' => ['/tmp/zhct-dm-poc-20260928.fcpiiN/store', 'http://127.0.0.1:18080', 112175, 'dm',
        '0581772a6831c86210372684867a5da5cb722855ef52ebfaf6776e1a6f971702',
        '8953e4be37bb3a1f6adf40c9da9b19de5e3eb2f61d595812b080a66bec10b7c2'],
];
if (!isset($targets[$lane]) || !in_array($action, ['--preflight', '--execute'], true)
    || ($action === '--execute' && ((string)getenv('CDX_DETAIL2_EXECUTE') !== 'ROOT_APPROVED_DETAIL2_V3'
        || (string)getenv('CDX_DETAIL2_SHA') !== hash_file('sha256', __FILE__)))) {
    fwrite(STDERR, "Detail2 execution disabled\n");
    exit(78);
}
[$root, $base, $pid, $dialect, $logicSha, $userSha] = $targets[$lane];
if ((string)getenv('POC_APP_ROOT') !== $root || (string)getenv('POC_BASE_URL') !== $base
    || (string)getenv('POC_DIALECT') !== $dialect || is_link($root)
    || hash_file('sha256', $root . '/application/p/controller/Report.php')
        !== '1673113e55dc7f247f697a77ece16ebdb21d1572d8a202c40abb8764cbc83f7e'
    || hash_file('sha256', $root . '/application/p/logic/MealOrder.php') !== $logicSha
    || hash_file('sha256', $root . '/application/model/User.php') !== $userSha
    || hash_file('sha256', $root . '/application/route.php')
        !== '081b0186b7f40f0bdd237cecb3e2d678fc9344c656932c0d3b3052404e4f1510') {
    throw new RuntimeException('Approved report source/runtime mismatch');
}
$runtimeReady = static function () use ($root, $base, $pid): bool {
    $cmd = (string)@file_get_contents('/proc/' . $pid . '/cmdline');
    $env = (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);
    $port = (int)parse_url($base, PHP_URL_PORT);
    $hex = strtoupper(str_pad(dechex($port), 4, '0', STR_PAD_LEFT));
    $inode = '';
    foreach (@file('/proc/net/tcp', FILE_IGNORE_NEW_LINES) ?: [] as $line) {
        $parts = preg_split('/\s+/', trim($line));
        if (($parts[1] ?? '') === '0100007F:' . $hex && ($parts[3] ?? '') === '0A') {
            $inode = (string)($parts[9] ?? '');
            break;
        }
    }
    $owns = false;
    if ($inode !== '') foreach (@scandir('/proc/' . $pid . '/fd') ?: [] as $fd) {
        if ($fd !== '.' && $fd !== '..'
            && @readlink('/proc/' . $pid . '/fd/' . $fd) === 'socket:[' . $inode . ']') {
            $owns = true;
            break;
        }
    }
    $workers = preg_match('/(?:^|\x00)PHP_CLI_SERVER_WORKERS=(\d+)(?:\x00|$)/',
        $env, $match) && (int)$match[1] > 1;
    return strpos($cmd, '127.0.0.1:' . $port) !== false
        && strpos($cmd, $root . '/public') !== false && $env !== ''
        && trim($children) === '' && !$workers && $owns
        && is_array($boundary) && !empty($boundary['external_stubs'])
        && !empty($boundary['redis_isolated']) && empty($boundary['real_queue']);
};
if (!$runtimeReady()) throw new RuntimeException('Isolated HTTP boundary absent');
$runtime = (static function (string $path): array {
    $config = require $path;
    if (!is_array($config)) throw new RuntimeException('Invalid database config');
    return $config;
})($root . '/application/database.php');
if ((string)($runtime['prefix'] ?? '') !== 'ydy_') throw new RuntimeException('Table prefix mismatch');
if ($dialect === 'mysql') {
    $local = (static function (): array {
        $config = require '/workspace/zhct/zhctproject/store/application/config/local/database.php';
        if (!is_array($config)) throw new RuntimeException('Code local database config invalid');
        return $config;
    })();
    if ((string)($runtime['type'] ?? '') !== 'mysql'
        || !in_array((string)($runtime['charset'] ?? ''), ['utf8', 'utf8mb4'], true)) {
        throw new RuntimeException('MySQL driver/charset mismatch');
    }
    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('MySQL port mismatch');
    }
    $dsn = 'mysql:host=' . $runtime['hostname'] . ';port='
        . (int)($runtime['hostport'] ?? 3306) . ';dbname=' . $runtime['database']
        . ';charset=' . $runtime['charset'];
    $username = (string)$runtime['username'];
    $password = (string)$runtime['password'];
} 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 mismatch');
    }
    foreach (['hostname' => 'POC_HOST', 'hostport' => 'POC_PORT',
        'database' => 'POC_SCHEMA', 'username' => 'POC_USER',
        'password' => 'POC_PASSWORD'] as $key => $envKey) {
        if ((string)($runtime[$key] ?? '') !== (string)getenv($envKey)) {
            throw new RuntimeException('DM worker config mismatch');
        }
    }
    $dsn = 'dm:host=127.0.0.1;port=5237;schema=ZHCT_APP';
    $username = (string)getenv('POC_USER');
    $password = (string)getenv('POC_PASSWORD');
}
$connect = static function () use ($dsn, $username, $password): PDO {
    return new PDO($dsn, $username, $password, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_CASE => PDO::CASE_LOWER, PDO::ATTR_TIMEOUT => 5]);
};
try { $db = $connect(); }
catch (Throwable $e) {
    fwrite(STDERR, 'Database connection failed: ' . get_class($e) . PHP_EOL);
    exit(75);
}
if ($dialect === 'mysql') {
    $identity = (string)$db->query("SELECT CONCAT(@@server_uuid,'|',@@hostname,'|',@@port,'|',DATABASE())")
        ->fetchColumn();
    $hostFingerprint = null;
    $listenerLocal = null;
} else {
    $schema = (string)$db->query("SELECT SYS_CONTEXT('USERENV','CURRENT_SCHEMA') FROM DUAL")
        ->fetchColumn();
    if (strtoupper($schema) !== 'ZHCT_APP') throw new RuntimeException('DM schema mismatch');
    $identity = 'ZHCT_APP|5237|' . $schema;
    $machine = trim((string)@file_get_contents('/etc/machine-id'));
    if ($machine === '' || gethostname() === false) throw new RuntimeException('DM host unknown');
    $hostFingerprint = hash('sha256', gethostname() . '|' . $machine);
    $lines = [];
    $exit = 0;
    @exec('/usr/sbin/ss -ltnp 2>/dev/null', $lines, $exit);
    $listenerLocal = false;
    if ($exit === 0) foreach ($lines as $line) {
        if (preg_match('/\*:5237\s+.*users:\(\("dmserver",pid=(\d+),/', $line, $match)) {
            $exe = @readlink('/proc/' . $match[1] . '/exe');
            $listenerLocal = is_string($exe) && basename($exe) === 'dmserver';
            break;
        }
    }
    if (!$listenerLocal) throw new RuntimeException('DM listener not local');
}
$dbFingerprint = hash('sha256', $identity);
$approvedDbFingerprint = $dialect === 'mysql'
    ? '003eb5aecf1cd4595b609c1f7f20b9ee325b578309fb9fe14fedaf77584fa401'
    : 'bc98485aed26beab348770a82ae38dbf922b04ab88a210cd7282c4caf0156194';
if (!hash_equals($approvedDbFingerprint, $dbFingerprint)
    || ($dialect === 'dm' && $hostFingerprint
        !== 'd56d81988bb0f106946cce91c608fdd0ef1116e5150b23376ea87e086eace4b9')) {
    throw new RuntimeException('Database/host identity differs from approved target');
}
if ($action === '--execute' && ((string)getenv('CDX_DETAIL2_DB_SHA') !== $dbFingerprint
    || ($dialect === 'dm' && (string)getenv('CDX_DETAIL2_HOST_SHA') !== $hostFingerprint))) {
    throw new RuntimeException('Execution fingerprint confirmation missing');
}

$prefix = $dialect === 'dm' ? 'YDY_' : 'ydy_';
$window = $dialect === 'dm' ? '2025-02-17' : '2026-09-18';
$departmentSql = 'SELECT DISTINCT sd.DEPARTMENT_UUID FROM '
    . $prefix . 'meal_order meal JOIN ' . $prefix . 'user u ON u.ID=meal.USER_ID'
    . ' JOIN (SELECT x.STAFF_UUID,x.DEPARTMENT_UUID FROM '
    . $prefix . 'staff_department x JOIN (SELECT STAFF_UUID,MIN(ID) AS MIN_ID FROM '
    . $prefix . 'staff_department GROUP BY STAFF_UUID) y ON y.MIN_ID=x.ID) sd'
    . ' ON sd.STAFF_UUID=u.STAFF_UUID'
    . ' JOIN ' . $prefix . 'department dep ON dep.UUID=sd.DEPARTMENT_UUID AND dep.IS_SHOW=1'
    . ' JOIN ' . $prefix . 'initial_menu menu ON menu.MEAL_ORDER_ID=meal.ID'
    . ' WHERE meal.ORDER_STATUS=30 AND meal.REFUND_STATUS IN (0,1,2)'
    . ' AND meal.IS_DELETE=0 AND u.IS_DELETE=0'
    . " AND menu.DISHES_UUID NOT IN ('custom_dish','package_fee')"
    . ' AND meal.RESTAURANT_ID=1 AND meal.MEAL_DATE=?'
    . ' AND meal.BIND_TIME BETWEEN ? AND ?';
$departmentSql .= $dialect === 'dm' ? ' AND ROWNUM<=21' : ' LIMIT 21';
$departmentArgs = [$window, $window . ' 00:00:00', $window . ' 23:59:59'];
$stmt = $db->prepare($departmentSql);
$stmt->execute($departmentArgs);
$departments = $stmt->fetchAll(PDO::FETCH_COLUMN);
if (!$departments || count($departments) > 20) {
    throw new RuntimeException('No small audited department set');
}
if ($dialect === 'mysql') {
    if (count($departments) !== 1) throw new RuntimeException('MySQL audited department changed');
    $department = (string)$departments[0];
} else {
    $matching = array_values(array_filter($departments, static function ($candidate): bool {
        return strpos(hash('sha256', (string)$candidate), 'b42d4036c9d8') === 0;
    }));
    if (count($matching) !== 1) throw new RuntimeException('Audited DM department changed');
    $department = (string)$matching[0];
}
if ($department === '') throw new RuntimeException('Empty audited department');
$sourceSql = 'SELECT meal.ID AS MEAL_ID,meal.ORDER_NO,meal.BIND_TIME,meal.MEAL_DATE,'
    . ' meal.MEAL_NUMBER,meal.TOTAL_PRICE,meal.PAY_PRICE,meal.REFUND_AMOUNT,meal.REMARK,'
    . ' u.NAME AS USER_NAME,u.MOBILE,sd.DEPARTMENT_UUID,dep.NAME AS DEPARTMENT_NAME,'
    . ' menu.ID AS MENU_ID,menu.DISHES_UUID,menu.NUMBER AS DISH_NUMBER,'
    . ' menu.TOTAL_PRICE AS DISH_TOTAL_PRICE,d.NAME AS DISH_NAME'
    . ' FROM ' . $prefix . 'meal_order meal'
    . ' JOIN ' . $prefix . 'user u ON u.ID=meal.USER_ID'
    . ' JOIN (SELECT x.STAFF_UUID,x.DEPARTMENT_UUID FROM '
    . $prefix . 'staff_department x JOIN (SELECT STAFF_UUID,MIN(ID) AS MIN_ID FROM '
    . $prefix . 'staff_department GROUP BY STAFF_UUID) y ON y.MIN_ID=x.ID) sd'
    . ' ON sd.STAFF_UUID=u.STAFF_UUID'
    . ' JOIN ' . $prefix . 'department dep ON dep.UUID=sd.DEPARTMENT_UUID AND dep.IS_SHOW=1'
    . ' JOIN ' . $prefix . 'initial_menu menu ON menu.MEAL_ORDER_ID=meal.ID'
    . ' LEFT JOIN ' . $prefix . 'dishes d ON d.UUID=menu.DISHES_UUID'
    . ' WHERE meal.ORDER_STATUS=30 AND meal.REFUND_STATUS IN (0,1,2)'
    . ' AND meal.IS_DELETE=0 AND u.IS_DELETE=0'
    . " AND menu.DISHES_UUID NOT IN ('custom_dish','package_fee')"
    . ' AND meal.RESTAURANT_ID=1 AND meal.MEAL_DATE=?'
    . ' AND meal.BIND_TIME BETWEEN ? AND ? AND sd.DEPARTMENT_UUID=?';
$sourceSql .= $dialect === 'dm' ? ' AND ROWNUM<=101 ORDER BY menu.ID'
    : ' ORDER BY menu.ID LIMIT 101';
$sourceArgs = [$window, $window . ' 00:00:00', $window . ' 23:59:59', $department];
$readSource = static function (PDO $pdo) use ($sourceSql, $sourceArgs): array {
    $stmt = $pdo->prepare($sourceSql);
    $stmt->execute($sourceArgs);
    return $stmt->fetchAll(PDO::FETCH_ASSOC);
};
$source = $readSource($db);
if (!$source || count($source) > 100
    || count($source) !== ($dialect === 'dm' ? 5 : 11)) {
    throw new RuntimeException('Audited source row bound changed');
}
foreach ($source as $row) {
    if ((string)$row['department_uuid'] !== $department) {
        throw new RuntimeException('Source department escaped filter');
    }
}
$orderIds = array_values(array_unique(array_map(static function (array $row): string {
    return (string)$row['meal_id'];
}, $source)));
if (count($orderIds) !== 1 || count($source) !== ($dialect === 'dm' ? 5 : 11)) {
    throw new RuntimeException('Source department is not one small order');
}
$sourceBefore = hash('sha256', serialize($source));
$money = static function ($value): string { return number_format((float)$value, 2, '.', ''); };
$twoDecimal = static function ($value): bool {
    return is_string($value) && preg_match('/^-?\d+\.\d{2}$/', $value) === 1;
};
$first = $source[0];
$expectedGroup = ['total_number' => $money($first['meal_number']),
    'total_price' => $money($first['total_price']),
    'pay_amount' => $money((float)$first['pay_price'] - (float)$first['refund_amount'])];
$dishGroups = [];
foreach ($source as $row) {
    $key = (string)$row['dishes_uuid'] . '|' . (string)$row['dish_name'];
    if (!isset($dishGroups[$key])) $dishGroups[$key] = [
        'dishes_uuid' => (string)$row['dishes_uuid'],
        'dishes_name' => (string)$row['dish_name'], 'number' => 0.0, 'price' => 0.0];
    $dishGroups[$key]['number'] += (float)$row['dish_number'];
    $dishGroups[$key]['price'] += (float)$row['dish_total_price'];
}
$markerCount = (int)$db->query('SELECT COUNT(*) FROM ' . $prefix . 'user'
    . " WHERE ACCOUNT LIKE 'CDXRD2%'")->fetchColumn();
if ($action === '--preflight') {
    echo json_encode(['lane' => $lane, 'mode' => 'select-only-preflight',
        'db_target' => $dialect === 'dm' ? 'nonprod-dm-store' : 'code-local-dev-mysql',
        'db_fingerprint' => $dbFingerprint, 'host_fingerprint' => $hostFingerprint,
        'dm_listener_local' => $listenerLocal, 'source_rows' => count($source),
        'source_orders' => count($orderIds), 'source_dish_groups' => count($dishGroups),
        'existing_synthetic_operators' => $markerCount], JSON_UNESCAPED_SLASHES) . PHP_EOL;
    exit(0);
}
if ($markerCount !== 0) throw new RuntimeException('Old synthetic operator requires review');
$db->query('SELECT ID,UUID,ACCOUNT,PWD,SALT,NAME,TYPE,CREATE_TIME,CREATE_BY,IS_DELETE'
    . ' FROM ' . $prefix . 'user WHERE 1=0');
$marker = 'CDXRD2' . strtoupper(bin2hex(random_bytes(8)));
$journalDir = sys_get_temp_dir() . '/zhct-report-detail2-' . $marker;
if (file_exists($journalDir) || !mkdir($journalDir, 0700)) {
    throw new RuntimeException('Private recovery journal unavailable');
}
chmod($journalDir, 0700);
$journal = ['lane' => $lane, 'marker' => $marker,
    'db_fingerprint' => $dbFingerprint, 'operator_id' => 0, 'status' => 'prepared'];
$writeJournal = static function (array $changes) use (&$journal, $journalDir): void {
    $journal = array_merge($journal, $changes);
    $next = $journalDir . '/recovery.next';
    if (file_put_contents($next, json_encode($journal, JSON_UNESCAPED_SLASHES)) === false) {
        throw new RuntimeException('Recovery journal write failed');
    }
    chmod($next, 0600);
    if (!rename($next, $journalDir . '/recovery.json')) {
        throw new RuntimeException('Recovery journal replace failed');
    }
};
$writeJournal([]);
$operatorId = 0;
$results = [];
$failure = '';
$cleanup = [];
$httpSent = false;
$httpConfirmed = true;
$types = static function (array $value): array {
    $result = array_map('gettype', $value);
    ksort($result);
    return $result;
};
$scrub = static function ($value) use (&$scrub) {
    if (!is_array($value)) return $value;
    $result = [];
    foreach ($value as $key => $item) {
        if (is_string($key) && preg_match('/(?:^id$|_id$|ids$|uuid|name|mobile|phone|order_no|remark|token|account)/i', $key)) {
            $result[$key] = '<redacted>';
        } else {
            $result[$key] = $scrub($item);
        }
    }
    return $result;
};
try {
    $stmt = $db->prepare('SELECT COUNT(*) FROM ' . $prefix . 'user WHERE UUID=? OR ACCOUNT=?');
    $stmt->execute([$marker, $marker]);
    if ((int)$stmt->fetchColumn() !== 0) throw new RuntimeException('Marker collision');
    $stmt = $db->prepare('INSERT INTO ' . $prefix . 'user'
        . ' (UUID,ACCOUNT,PWD,SALT,NAME,TYPE,CREATE_TIME,CREATE_BY,IS_DELETE)'
        . ' VALUES (?,?,?,?,?,?,?,?,?)');
    $stmt->execute([$marker, $marker, 'DISABLED', strtoupper(bin2hex(random_bytes(8))),
        $marker, 0, date('Y-m-d H:i:s'), 'CODEX', 0]);
    $stmt = $db->prepare('SELECT ID FROM ' . $prefix . 'user'
        . ' WHERE UUID=? AND ACCOUNT=? AND TYPE=0 AND CREATE_BY=?');
    $stmt->execute([$marker, $marker, 'CODEX']);
    $operatorId = (int)$stmt->fetchColumn();
    if ($operatorId <= 0) throw new RuntimeException('Synthetic operator not readable');
    $writeJournal(['status' => 'operator_inserted', 'operator_id' => $operatorId]);
    require_once $root . '/application/base/Security.php';
    $token = \app\base\Security::encrypt(implode("\t",
        [(string)$operatorId, $marker, $marker, '0', '', '', $marker]));
    if (!is_string($token) || $token === '') throw new RuntimeException('Synthetic token unavailable');
    $baseForm = ['bind_start_date' => $window, 'bind_end_date' => $window,
        'meal_start_date' => $window, 'meal_end_date' => $window,
        'restaurantIds' => '1', 'page' => 1, 'list_rows' => 15];
    foreach (['dishSalesVolumeDetailList', 'dishSalesVolumeDetailUserList'] as $route) {
        if (!$runtimeReady()) throw new RuntimeException('HTTP isolation drift');
        $form = $baseForm + ($route === 'dishSalesVolumeDetailList'
            ? ['department_uuids' => $department] : ['department_uuid' => $department]);
        $context = stream_context_create(['http' => ['method' => 'POST',
            'header' => "Content-Type: application/x-www-form-urlencoded\r\n"
                . 'token: ' . $token . "\r\n",
            'content' => http_build_query($form, '', '&', PHP_QUERY_RFC3986),
            'timeout' => 25, 'ignore_errors' => true]]);
        $httpConfirmed = false;
        $httpSent = true;
        $stream = @fopen($base . '/p/report/' . $route, 'rb', false, $context);
        $body = is_resource($stream) ? stream_get_contents($stream, 256 * 1024 + 1) : false;
        $streamMeta = is_resource($stream) ? stream_get_meta_data($stream) : [];
        if (is_resource($stream)) fclose($stream);
        if (!is_string($body) || !empty($streamMeta['timed_out'])
            || strlen($body) > 256 * 1024) {
            throw new RuntimeException('HTTP response incomplete or exceeds 256KiB');
        }
        $httpConfirmed = true;
        $headers = $http_response_header ?? [];
        preg_match('/HTTP\/\S+\s+(\d+)/', (string)($headers[0] ?? ''), $match);
        $http = (int)($match[1] ?? 0);
        $response = is_string($body) ? json_decode($body, true) : null;
        $data = is_array($response) ? ($response['data'] ?? null) : null;
        $rows = is_array($data) ? ($data['data'] ?? null) : null;
        $positive = $http === 200 && is_array($response) && ($response['code'] ?? null) === 0
            && is_array($rows) && count($rows) > 0;
        $sourceMatch = false;
        $amountTypes = false;
        $metaMatch = false;
        $summaryMatch = null;
        $firstDishTypes = [];
        $typeMismatches = [];
        $unitPriceTypes = [];
        $indexTypes = [];
        $dishNumberTypes = [];
        $sourceMismatchKeys = [];
        if ($positive) {
            $expectedTotal = $route === 'dishSalesVolumeDetailList' ? 1 : count($source);
            $metaMatch = (int)($data['total'] ?? -1) === $expectedTotal
                && count($rows) === $expectedTotal
                && (int)($data['current_page'] ?? -1) === 1
                && (int)($data['per_page'] ?? -1) === 15;
            if ($route === 'dishSalesVolumeDetailList') {
                $row = $rows[0];
                $summary = $data['summary'] ?? null;
                $summaryMatch = is_array($summary);
                foreach ($expectedGroup as $field => $value) {
                    $summaryMatch = $summaryMatch && isset($summary[$field])
                        && $twoDecimal($summary[$field]) && $summary[$field] === $value;
                }
                $amountTypes = is_array($row) && $summaryMatch;
                foreach ($expectedGroup as $field => $value) {
                    $amountTypes = $amountTypes && isset($row[$field])
                        && $twoDecimal($row[$field]) && $row[$field] === $value;
                }
                $sourceMatch = $amountTypes && (string)($row['department_uuid'] ?? '') === $department
                    && (string)($row['department_name'] ?? '') === (string)$first['department_name']
                    && substr((string)($row['bind_date'] ?? ''), 0, 10) === $window
                    && substr((string)($row['meal_date'] ?? ''), 0, 10) === $window
                    && (string)($row['order_ids'] ?? '') === $orderIds[0]
                    && (int)($row['index'] ?? 0) === 1
                    && is_array($row['view_params'] ?? null)
                    && (string)($row['view_params']['department_uuid'] ?? '') === $department;
                $actualDishes = $row['dishes'] ?? null;
                $remaining = $dishGroups;
                $sourceMatch = $sourceMatch && is_array($actualDishes)
                    && count($actualDishes) === count($dishGroups);
                if (is_array($actualDishes) && $actualDishes) {
                    $firstDishTypes = $types($actualDishes[0]);
                    foreach ($actualDishes as $dish) {
                        if (!is_array($dish)) { $sourceMatch = false; break; }
                        $key = (string)($dish['dishes_uuid'] ?? '') . '|'
                            . (string)($dish['dishes_name'] ?? '');
                        if (!isset($remaining[$key])) { $sourceMatch = false; break; }
                        $expected = $remaining[$key];
                        $unit = $expected['number'] == 0.0 ? '0.00'
                            : $money(round($expected['price'] / $expected['number'], 2));
                        foreach (['dish_number' => $money($expected['number']),
                            'dish_total_price' => $money($expected['price']),
                            'unit_price' => $unit] as $field => $value) {
                            if (!isset($dish[$field]) || !$twoDecimal($dish[$field])
                                || $dish[$field] !== $value) $sourceMatch = false;
                        }
                        unset($remaining[$key]);
                    }
                    if ($remaining) $sourceMatch = false;
                }
            } else {
                $remaining = $source;
                $amountTypes = true;
                $sourceMatch = true;
                foreach ($rows as $index => $row) {
                    if (!is_array($row)) {
                        $sourceMatch = false;
                        break;
                    }
                    $indexType = isset($row['index']) ? gettype($row['index']) : 'missing';
                    $indexTypes[$indexType] = ($indexTypes[$indexType] ?? 0) + 1;
                    foreach (['total_price', 'pay_amount',
                        'dish_total_price'] as $field) {
                        if (!isset($row[$field]) || !$twoDecimal($row[$field])) {
                            $amountTypes = false;
                            $typeMismatches[$field] = ($typeMismatches[$field] ?? 0) + 1;
                        }
                    }
                    $numberType = isset($row['dish_number'])
                        ? gettype($row['dish_number']) : 'missing';
                    $dishNumberTypes[$numberType] = ($dishNumberTypes[$numberType] ?? 0) + 1;
                    if (!isset($row['dish_number']) || !is_string($row['dish_number'])
                        || !is_numeric($row['dish_number'])) {
                        $amountTypes = false;
                        $typeMismatches['dish_number_contract'] =
                            ($typeMismatches['dish_number_contract'] ?? 0) + 1;
                    }
                    $unitType = isset($row['unit_price']) ? gettype($row['unit_price']) : 'missing';
                    $unitPriceTypes[$unitType] = ($unitPriceTypes[$unitType] ?? 0) + 1;
                    if (!isset($row['unit_price'])
                        || !(is_int($row['unit_price']) || is_float($row['unit_price']))) {
                        $amountTypes = false;
                        $typeMismatches['unit_price_contract'] =
                            ($typeMismatches['unit_price_contract'] ?? 0) + 1;
                    }
                    if ($indexType !== 'missing') {
                        $amountTypes = false;
                        $typeMismatches['unexpected_index'] =
                            ($typeMismatches['unexpected_index'] ?? 0) + 1;
                    }
                    $found = false;
                    $nearestMismatch = null;
                    foreach ($remaining as $slot => $expected) {
                        $number = (float)$expected['dish_number'];
                        $unit = $number == 0.0 ? '0.00'
                            : $money(round((float)$expected['dish_total_price'] / $number, 2));
                        $checks = [
                            'id' => (string)$expected['meal_id'],
                            'order_no' => (string)$expected['order_no'],
                            'bind_date' => $window, 'meal_date' => $window,
                            'total_price' => $money($expected['total_price']),
                            'pay_amount' => $money((float)$expected['pay_price']
                                - (float)$expected['refund_amount']),
                            'remark' => (string)$expected['remark'],
                            'user_name' => (string)$expected['user_name'],
                            'mobile' => (string)$expected['mobile'],
                            'department_name' => (string)$expected['department_name'],
                            'dishes_uuid' => (string)$expected['dishes_uuid'],
                            'dishes_name' => (string)$expected['dish_name'],
                            'dish_number' => $money($number),
                            'dish_total_price' => $money($expected['dish_total_price']),
                            'unit_price' => $unit,
                        ];
                        $mismatches = [];
                        foreach ($checks as $key => $value) {
                            if (in_array($key, ['total_price', 'pay_amount', 'unit_price',
                                'dish_number', 'dish_total_price'], true)) {
                                if (!isset($row[$key]) || !is_numeric($row[$key])
                                    || $money($row[$key]) !== $value) {
                                    $mismatches[] = $key;
                                }
                            } elseif ((string)($row[$key] ?? '') !== $value) {
                                $mismatches[] = $key;
                            }
                        }
                        if (!$mismatches) { unset($remaining[$slot]); $found = true; break; }
                        if ($nearestMismatch === null
                            || count($mismatches) < count($nearestMismatch)) {
                            $nearestMismatch = $mismatches;
                        }
                    }
                    if (!$found) {
                        $sourceMatch = false;
                        foreach ($nearestMismatch ?? [] as $key) {
                            $sourceMismatchKeys[$key] = ($sourceMismatchKeys[$key] ?? 0) + 1;
                        }
                    }
                }
                if ($remaining) $sourceMatch = false;
            }
        }
        $positive = $positive && $metaMatch && $sourceMatch && $amountTypes
            && ($summaryMatch === null || $summaryMatch);
        $sanitized = is_array($response) ? $scrub($response) : null;
        $results[$route] = ['http' => $http,
            'code' => is_array($response) ? ($response['code'] ?? null) : null,
            'positive' => $positive, 'pagination_match' => $metaMatch,
            'source_match' => $sourceMatch, 'baseline_field_type_contract' => $amountTypes,
            'decimal_type_mismatch_counts' => $typeMismatches,
            'unit_price_type_counts' => $unitPriceTypes,
            'index_type_counts' => $indexTypes,
            'dish_number_type_counts' => $dishNumberTypes,
            'source_field_mismatch_counts' => $sourceMismatchKeys,
            'summary_match' => $summaryMatch, 'rows' => is_array($rows) ? count($rows) : null,
            'top_key_types' => is_array($response) ? $types($response) : [],
            'data_key_types' => is_array($data) ? $types($data) : [],
            'first_row_key_types' => is_array($rows) && isset($rows[0]) && is_array($rows[0])
                ? $types($rows[0]) : [],
            'first_dish_key_types' => $firstDishTypes,
            'sanitized_sha256' => is_array($sanitized)
                ? hash('sha256', json_encode($sanitized, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES))
                : null,
            'body_bytes' => is_string($body) ? strlen($body) : null];
        if (!$positive) throw new RuntimeException('Report positive branch failed: ' . $route);
    }
    $token = '';
    $verify = $connect();
    $again = $readSource($verify);
    if (hash('sha256', serialize($again)) !== $sourceBefore) {
        throw new RuntimeException('Report source changed during HTTP reads');
    }
    $results['source_unchanged'] = true;
} catch (Throwable $e) {
    $failure = get_class($e) . ':' . hash('sha256', $e->getMessage());
} finally {
    $cleanup['http_worker_stopped'] = !is_dir('/proc/' . $pid);
    $cleanup['http_runtime_ready'] = !$cleanup['http_worker_stopped'] && $runtimeReady();
    $cleanup['http_outcome_confirmed'] = !$httpSent || $httpConfirmed;
    $cleanup['barrier_safe'] = ($cleanup['http_runtime_ready'] || $cleanup['http_worker_stopped'])
        && ($cleanup['http_worker_stopped'] || $cleanup['http_outcome_confirmed']);
    if ($cleanup['barrier_safe']) {
        try {
            $db = $connect();
            $cleanupIdentity = $dialect === 'mysql'
                ? (string)$db->query("SELECT CONCAT(@@server_uuid,'|',@@hostname,'|',@@port,'|',DATABASE())")
                    ->fetchColumn()
                : 'ZHCT_APP|5237|' . (string)$db->query(
                    "SELECT SYS_CONTEXT('USERENV','CURRENT_SCHEMA') FROM DUAL")->fetchColumn();
            if (!hash_equals($approvedDbFingerprint, hash('sha256', $cleanupIdentity))) {
                throw new RuntimeException('Cleanup database identity differs');
            }
            $stmt = $db->prepare('SELECT ID FROM ' . $prefix . 'user'
                . ' WHERE UUID=? AND ACCOUNT=? AND TYPE=0 AND CREATE_BY=?');
            $stmt->execute([$marker, $marker, 'CODEX']);
            $owned = $stmt->fetchAll(PDO::FETCH_ASSOC);
            if (count($owned) > 1) throw new RuntimeException('Ambiguous operator cleanup');
            if ($owned) {
                $id = (int)$owned[0]['id'];
                if ($operatorId > 0 && $id !== $operatorId) {
                    throw new RuntimeException('Operator ID drift');
                }
                $delete = $db->prepare('DELETE FROM ' . $prefix . 'user'
                    . ' WHERE ID=? AND UUID=? AND ACCOUNT=? AND TYPE=0 AND CREATE_BY=?');
                $delete->execute([$id, $marker, $marker, 'CODEX']);
                if ($delete->rowCount() !== 1) {
                    throw new RuntimeException('Exact operator cleanup affected rows mismatch');
                }
            }
        } catch (Throwable $e) {
            $cleanup['error_class'] = get_class($e);
            $cleanup['error_sha256'] = hash('sha256', $e->getMessage());
        }
    }
    try {
        $db = $connect();
        $stmt = $db->prepare('SELECT COUNT(*) FROM ' . $prefix . 'user'
            . ' WHERE UUID=? OR ACCOUNT=?');
        $stmt->execute([$marker, $marker]);
        $cleanup['operator_zero'] = (int)$stmt->fetchColumn() === 0;
    } catch (Throwable $e) {
        $cleanup['verify_error_class'] = get_class($e);
    }
}
$clean = !empty($cleanup['barrier_safe']) && !empty($cleanup['operator_zero'])
    && empty($cleanup['error_class']);
try {
    $writeJournal(['status' => $clean ? 'cleaned' : 'needs_recovery',
        'cleanup' => $cleanup, 'failure' => $failure]);
} catch (Throwable $e) {
    $cleanup['journal_error_class'] = get_class($e);
    $clean = false;
}
echo json_encode(['lane' => $lane, 'suite' => 'store-report-detail2',
    'marker' => $marker, 'source_rows' => count($source),
    'source_orders' => count($orderIds), 'source_dish_groups' => count($dishGroups),
    'results' => $results, 'failure' => $failure, 'cleanup' => $cleanup],
    JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . PHP_EOL;
if ($failure !== '' || !$clean) exit(1);
