<?php

declare(strict_types=1);

// Read only the isolated A response log and code-local MySQL source. No HTTP/DML.
if (($argv[1] ?? '') !== '--read-only') exit(78);
set_exception_handler(static function (Throwable $e): void {
    fwrite(STDERR, 'Small5 A diagnostic failed ' . get_class($e) . ':'
        . hash('sha256', $e->getMessage()) . PHP_EOL);
    exit(1);
});
$root = '/tmp/zhct-http-store-a.l5omH8';
$log = $root . '/runtime/log/202610/04.log';
$lines = file($log, FILE_IGNORE_NEW_LINES);
if (!is_array($lines)) throw new RuntimeException('A report log unreadable');
$response = null;
foreach ($lines as $i => $line) {
    if (strpos($line, 'POST 127.0.0.1:18097/p/Ontoanalysis/StaffInfo') === false) continue;
    foreach (array_slice($lines, $i + 1, 5) as $after) {
        if (strpos($after, '[ log ] ') !== 0) continue;
        $decoded = json_decode(substr($after, 8), true);
        if (is_array($decoded)) $response = $decoded;
        break;
    }
}
if (!is_array($response) || ($response['code'] ?? null) !== 0
    || !is_array($response['data'] ?? null)) {
    throw new RuntimeException('A StaffInfo business log absent');
}
$actual = $response['data'];
$config = require '/workspace/zhct/zhctproject/store/application/config/local/database.php';
$db = new PDO('mysql:host=' . $config['hostname'] . ';port='
    . (int)($config['hostport'] ?? 3306) . ';dbname=' . $config['database']
    . ';charset=' . ($config['charset'] ?? 'utf8'),
    $config['username'], $config['password'],
    [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_CASE => PDO::CASE_LOWER, PDO::ATTR_TIMEOUT => 5]);
$identity = (string)$db->query(
    "SELECT CONCAT(@@server_uuid,'|',@@hostname,'|',@@port,'|',DATABASE())")
    ->fetchColumn();
if (hash('sha256', $identity)
    !== '003eb5aecf1cd4595b609c1f7f20b9ee325b578309fb9fe14fedaf77584fa401') {
    throw new RuntimeException('A diagnostic DB identity drift');
}
$staff = $db->query('SELECT UUID FROM ydy_staff WHERE ID=1')->fetchColumn();
if (substr(hash('sha256', (string)$staff), 0, 12) !== 'e8189d2c8d10') {
    throw new RuntimeException('A diagnostic staff source drift');
}
$sql = 'SELECT a.UUID,a.NAME,a.HEAD_IMG,a.SEX,a.HEIGHT,a.BIRTHDAY,a.WEIGHT,'
    . ' f.UUID D_UUID,f.NAME D_NAME,c.NAME S_NAME,a.SPORT_EVENT_UUID,'
    . ' IFNULL(b.STATUS,2) STATUS,a.GRADE,a.SPORT_UUID'
    . ' FROM ydy_staff a'
    . ' LEFT JOIN ydy_member_weight_status b ON a.UUID=b.STAFF_UUID'
    . ' LEFT JOIN ydy_sport c ON a.SPORT_UUID=c.UUID'
    . ' LEFT JOIN ydy_staff_department sd ON a.UUID=sd.STAFF_UUID'
    . ' LEFT JOIN ydy_department f ON sd.DEPARTMENT_UUID=f.UUID'
    . ' WHERE a.UUID=? ORDER BY b.ID DESC LIMIT 1';
$stmt = $db->prepare($sql);
$stmt->execute([(string)$staff]);
$expected = $stmt->fetch(PDO::FETCH_ASSOC);
if (!is_array($expected)) throw new RuntimeException('A diagnostic joined row absent');
$diff = [];
foreach (['uuid', 'name', 'sex', 'height', 'birthday', 'weight',
    'd_uuid', 'd_name', 's_name', 'status', 'grade', 'sport_uuid'] as $key) {
    $a = $actual[$key] ?? null;
    $e = $expected[$key] ?? null;
    if ((string)$a === (string)$e) continue;
    $diff[] = ['field' => $key, 'actual_type' => gettype($a),
        'expected_type' => gettype($e),
        'actual_sha12' => substr(hash('sha256', (string)$a), 0, 12),
        'expected_sha12' => substr(hash('sha256', (string)$e), 0, 12),
        'actual_length' => strlen((string)$a),
        'expected_length' => strlen((string)$e),
        'numeric_equal' => is_numeric($a) && is_numeric($e)
            && abs((float)$a - (float)$e) < 0.000001,
        'bc_equal_2dp' => is_numeric($a) && is_numeric($e)
            && bccomp((string)$a, (string)$e, 2) === 0];
}
$expectedKeys = array_keys($expected);
$actualKeys = array_keys($actual);
$responseTypes = array_map('gettype', $actual);
ksort($responseTypes);
$heightColumn = $db->query("SELECT DATA_TYPE,NUMERIC_PRECISION,NUMERIC_SCALE,IS_NULLABLE"
    . " FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=DATABASE()"
    . " AND TABLE_NAME='ydy_staff' AND COLUMN_NAME='height'")
    ->fetch(PDO::FETCH_ASSOC);
$heightNull = (int)$db->query('SELECT COUNT(*) FROM ydy_staff'
    . ' WHERE IS_SHOW=1 AND HEIGHT IS NULL')->fetchColumn();
$heightZero = (int)$db->query('SELECT COUNT(*) FROM ydy_staff'
    . ' WHERE IS_SHOW=1 AND HEIGHT=0')->fetchColumn();
$heightActual = $actual['height'] ?? null;
$heightExpected = $expected['height'] ?? null;
echo json_encode(['route' => 'StaffInfo',
    'http_log_response_code' => $response['code'],
    'first_mismatch' => $diff[0] ?? null,
    'mismatch_field_names' => array_column($diff, 'field'),
    'missing_expected_keys' => array_values(array_diff($expectedKeys, $actualKeys)),
    'extra_response_keys' => array_values(array_diff($actualKeys, $expectedKeys)),
    'a_baseline_response_field_types' => $responseTypes,
    'a_height_format' => [
        'response_type' => gettype($heightActual),
        'response_strict_two_decimal_string' => is_string($heightActual)
            && preg_match('/^-?\d+\.\d{2}$/D', $heightActual) === 1,
        'raw_strict_two_decimal_string' => is_string($heightExpected)
            && preg_match('/^-?\d+\.\d{2}$/D', $heightExpected) === 1,
        'selected_raw_null' => $heightExpected === null,
        'selected_raw_numeric_zero' => is_numeric($heightExpected)
            && bccomp((string)$heightExpected, '0', 2) === 0,
        'column_type' => is_array($heightColumn) ? $heightColumn['data_type'] : null,
        'column_precision' => is_array($heightColumn)
            ? $heightColumn['numeric_precision'] : null,
        'column_scale' => is_array($heightColumn)
            ? $heightColumn['numeric_scale'] : null,
        'column_nullable' => is_array($heightColumn)
            ? $heightColumn['is_nullable'] : null,
        'visible_staff_null_rows' => $heightNull,
        'visible_staff_zero_rows' => $heightZero,
    ],
    'business_http_executed' => false, 'dml_executed' => false],
    JSON_UNESCAPED_SLASHES), PHP_EOL;
