<?php

declare(strict_types=1);

$root = getenv('POC_TARGET_ROOT');
$dialect = getenv('POC_DIALECT');
$baseUrl = rtrim((string)getenv('POC_BASE_URL'), '/');
if (!$root || !$baseUrl || !in_array($dialect, ['mysql', 'dm'], true)) exit(2);
foreach (['HOST', 'PORT', 'SCHEMA', 'USER', 'PASSWORD',
    'AI_HOST', 'AI_PORT', 'AI_SCHEMA', 'AI_USER', 'AI_PASSWORD'] as $part) {
    if (!getenv('POC_' . $part)) exit(2);
}
define('TP_ENV', 'poc');
define('BUSINESS', 'aizhct');
define('ENTERPRISE_NO', '10001');
require $root . '/vendor/autoload.php';
(new \think\App($root))->setEnvName('poc')->initialize();

$host = getenv('POC_AI_HOST');
$port = getenv('POC_AI_PORT');
$schema = getenv('POC_AI_SCHEMA');
$dsn = $dialect === 'dm'
    ? "dm:host=$host;port=$port;schema=$schema"
    : "mysql:host=$host;port=$port;dbname=$schema;charset=utf8mb4";
$pdo = new PDO($dsn, getenv('POC_AI_USER'), getenv('POC_AI_PASSWORD'),
    [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$storeHost = getenv('POC_HOST');
$storePort = getenv('POC_PORT');
$storeSchema = getenv('POC_SCHEMA');
$storeDsn = $dialect === 'dm'
    ? "dm:host=$storeHost;port=$storePort;schema=$storeSchema"
    : "mysql:host=$storeHost;port=$storePort;dbname=$storeSchema;charset=utf8mb4";
$storePdo = new PDO($storeDsn, getenv('POC_USER'), getenv('POC_PASSWORD'),
    [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$userTable = $dialect === 'dm' ? 'YOSHOP_USER' : 'yoshop_user';
$targetTable = $dialect === 'dm' ? 'YOSHOP_USER_SPORT_TARGET' : 'yoshop_user_sport_target';
$staffTable = $dialect === 'dm' ? 'YOSHOP_STAFF' : 'yoshop_staff';
$weightTable = $dialect === 'dm' ? 'YOSHOP_USER_WEIGHT' : 'yoshop_user_weight';
$weightStatusTable = $dialect === 'dm' ? 'YOSHOP_USER_WEIGHT_STATUS' : 'yoshop_user_weight_status';
$scoreTable = $dialect === 'dm' ? 'YOSHOP_USER_SCORE' : 'yoshop_user_score';
$scoreLogTable = $dialect === 'dm' ? 'YOSHOP_USER_SCORE_LOG' : 'yoshop_user_score_log';
$bindTable = $dialect === 'dm' ? 'YOSHOP_USER_BIND' : 'yoshop_user_bind';
$sportItemTable = $dialect === 'dm' ? 'YOSHOP_SPORT_ITEM' : 'yoshop_sport_item';
$userSportItemTable = $dialect === 'dm' ? 'YOSHOP_USER_SPORT_ITEM' : 'yoshop_user_sport_item';
$userSportEnergyTable = $dialect === 'dm' ? 'YOSHOP_USER_SPORT_ENERGY' : 'yoshop_user_sport_energy';
$sessionTable = $dialect === 'dm' ? 'YDY_MEASUREMENT_SESSION' : 'ydy_measurement_session';
$rawTable = $dialect === 'dm' ? 'YDY_MEASUREMENT_SESSION_RAW' : 'ydy_measurement_session_raw';
$healthTable = $dialect === 'dm' ? 'YDY_HEALTH_RECORD' : 'ydy_health_record';
$metricTable = $dialect === 'dm' ? 'YDY_HEALTH_METRIC' : 'ydy_health_metric';
$marker = 'CDXAISPORT' . strtoupper(bin2hex(random_bytes(5)));
$token = 'CDXAISPORT-TOKEN-' . strtoupper(bin2hex(random_bytes(12)));
$userId = 0;
$created = false;
$requireStaff = getenv('POC_REQUIRE_STAFF') === '1';
$staffId = 0;
$insert = $pdo->prepare('INSERT INTO ' . $userTable
    . ' (STORE_ID,MOBILE,NICK_NAME,BALANCE,GIFT_BALANCE,IS_DELETE,CREATE_TIME)'
    . ' VALUES (10001,?,?,?,?,0,?)');
$insert->execute(['', $marker, '0.00', '0.00', time()]);
$userId = (int)$pdo->lastInsertId();
if ($userId <= 0) throw new RuntimeException('Synthetic AI user insert failed');
$created = true;
try {
    if ($requireStaff) {
        $boundary = json_decode((string)file_get_contents($baseUrl . '/__poc_boundary'), true);
        if (empty($boundary['external_stubs'])) {
            throw new RuntimeException('AI secondary weight test external stubs unavailable');
        }
        file_put_contents($root . '/runtime/poc-stub-hits.log', '');
        $createStaff = $pdo->prepare('INSERT INTO ' . $staffTable
            . ' (NAME,USER_ID,STORE_ID,HEIGHT,WEIGHT,GENDER,BIRTHDAY,PHONE,IS_DELETE)'
            . ' VALUES (?,?,10001,170,60,1,?,\'\',0)');
        $createStaff->execute([$marker, $userId, '1990-01-01']);
        $staffId = (int)$pdo->lastInsertId();
        if ($staffId <= 0) throw new RuntimeException('Synthetic AI staff insert failed');
    }
    \think\facade\Cache::set($token, [
        'user' => ['user_id' => $userId], 'password_version' => 0, 'login_type' => 'thirdparty',
    ], 300);
    $request = static function (string $path, ?array $form = null) use ($baseUrl, $token): array {
        $options = [
            'method' => $form === null ? 'GET' : 'POST',
            'header' => 'Access-Token: ' . $token . "\r\n"
                . "platform: POC\r\n"
                . 'Content-Type: application/x-www-form-urlencoded' . "\r\n",
            'timeout' => 15,
            'ignore_errors' => true,
        ];
        if ($form !== null) $options['content'] = http_build_query($form);
        $body = file_get_contents($baseUrl . $path, false,
            stream_context_create(['http' => $options]));
        $decoded = is_string($body) ? json_decode($body, true) : null;
        if (!is_array($decoded)) {
            throw new RuntimeException('AI HTTP response was not JSON: path=' . $path
                . ' status=' . (string)($http_response_header[0] ?? 'unknown')
                . ' bytes=' . (is_string($body) ? strlen($body) : 0)
                . ' text=' . mb_substr(preg_replace('/\s+/', ' ', strip_tags((string)$body)), 0, 160));
        }
        return $decoded;
    };
    $url = '/api/user.sport_target/set?storeId=10001';
    $first = $request($url, ['form' => ['type' => 2]]);
    if ((int)($first['status'] ?? 0) !== 200) {
        throw new RuntimeException('AI sport target creation HTTP failed: status='
            . (int)($first['status'] ?? 0) . ' message='
            . mb_substr((string)($first['message'] ?? ''), 0, 100));
    }
    $targetId = (int)($first['data']['id'] ?? 0);
    if ($targetId <= 0) throw new RuntimeException('AI sport target ID missing');
    $second = $request($url, ['form' => ['type' => 3]]);
    $current = $request('/api/user.sport_target/current?storeId=10001');
    if ((int)($second['status'] ?? 0) !== 200
        || (int)($current['status'] ?? 0) !== 200
        || (int)($second['data']['id'] ?? 0) !== $targetId
        || (int)($current['data']['id'] ?? 0) !== $targetId
        || (int)($current['data']['type'] ?? 0) !== 3) {
        throw new RuntimeException('AI sport target update/current HTTP mismatch');
    }
    $invalid = $request($url, ['form' => ['type' => 4]]);
    if ((int)($invalid['status'] ?? 200) === 200) {
        throw new RuntimeException('Invalid AI sport target type was accepted');
    }
    $read = $pdo->prepare('SELECT ID,TYPE FROM ' . $targetTable . ' WHERE STORE_ID=10001 AND USER_ID=?');
    $read->execute([$userId]);
    $rows = array_map('array_change_key_case', $read->fetchAll(PDO::FETCH_ASSOC));
    if (count($rows) !== 1 || (int)$rows[0]['id'] !== $targetId
        || (int)$rows[0]['type'] !== 3) {
        throw new RuntimeException('AI sport target database readback mismatch');
    }
    echo json_encode(['dialect' => $dialect, 'status' => 'passed',
        'create_update_current_invalid' => true, 'database_rows' => 1,
        'final_type' => 3]) . PHP_EOL;
    $metricCheck = $storePdo->prepare('SELECT COUNT(*) FROM ' . $metricTable
        . " WHERE METRIC_CODE='jump_count'");
    $metricCheck->execute();
    if ((int)$metricCheck->fetchColumn() !== 1) {
        throw new RuntimeException('Jump-count metric dictionary fixture missing');
    }
    $today = date('Y-m-d');
    $rope = $request('/api/wolland.rope/add?storeId=10001', ['form' => [
        'mac' => $marker, 'mode' => 'free', 'stoppedAt' => (string)(time() * 1000),
        'dateKey' => $today, 'count' => 123, 'duration' => 60,
        'calories' => 5.5,
    ]]);
    if ((int)($rope['status'] ?? 0) !== 200) {
        throw new RuntimeException('Welland rope upload HTTP failed: '
            . mb_substr((string)($rope['message'] ?? ''), 0, 100));
    }
    $sessionQuery = $storePdo->prepare('SELECT SESSION_ID FROM ' . $sessionTable
        . " WHERE AI_USER_ID=? AND VENDOR='welland'");
    $sessionQuery->execute([$userId]);
    $sessions = $sessionQuery->fetchAll(PDO::FETCH_COLUMN);
    if (count($sessions) !== 1) throw new RuntimeException('Welland rope session readback mismatch');
    $sessionId = (int)$sessions[0];
    $rawQuery = $storePdo->prepare('SELECT COUNT(*) FROM ' . $rawTable . ' WHERE SESSION_ID=?');
    $rawQuery->execute([$sessionId]);
    $jumpQuery = $storePdo->prepare('SELECT VALUE FROM ' . $healthTable
        . " WHERE SESSION_ID=? AND AI_USER_ID=? AND METRIC_CODE='jump_count'");
    $jumpQuery->execute([$sessionId, $userId]);
    $jumpValue = $jumpQuery->fetchColumn();
    if ((int)$rawQuery->fetchColumn() !== 1 || (int)$jumpValue !== 123) {
        throw new RuntimeException('Welland rope raw/metric database readback mismatch');
    }
    $stats = $request('/api/wolland.rope/stats?storeId=10001&date=' . $today);
    $session = $request('/api/wolland.rope/session?storeId=10001&session_id=' . $sessionId);
    $all = $request('/api/wolland.rope/all?storeId=10001&start_date=' . $today . '&end_date=' . $today);
    if ((int)($stats['status'] ?? 0) !== 200 || (int)($stats['data']['totalCount'] ?? 0) !== 123
        || (int)($session['status'] ?? 0) !== 200
        || (int)($session['data']['sessionId'] ?? 0) !== $sessionId
        || (int)($all['status'] ?? 0) !== 200
        || count((array)($all['data'] ?? [])) !== 1
        || (int)($all['data'][0]['totalCount'] ?? 0) !== 123
        || (int)($all['data'][0]['sessions'][0]['sessionId'] ?? 0) !== $sessionId) {
        throw new RuntimeException('Welland rope stats/session/all HTTP readback mismatch');
    }
    echo json_encode(['dialect' => $dialect, 'status' => 'passed',
        'device_http_upload_and_three_reads' => true, 'session_rows' => 1,
        'raw_rows' => 1, 'jump_count' => 123]) . PHP_EOL;
    $scale = $request('/api/yunkangbao.scale/add?storeId=10001', ['form' => [
        'weight' => 62.5, 'bmi' => 21.6, 'height' => 170,
        'measured_at' => time(), 'date' => $today,
    ]]);
    if ((int)($scale['status'] ?? 0) !== 200) {
        throw new RuntimeException('Yunkangbao scale upload HTTP failed: '
            . mb_substr((string)($scale['message'] ?? ''), 0, 100));
    }
    $scaleQuery = $storePdo->prepare('SELECT SESSION_ID FROM ' . $sessionTable
        . " WHERE AI_USER_ID=? AND VENDOR='yunkangbao'");
    $scaleQuery->execute([$userId]);
    $scaleSessions = $scaleQuery->fetchAll(PDO::FETCH_COLUMN);
    if (count($scaleSessions) !== 1) throw new RuntimeException('Scale session readback mismatch');
    $scaleSessionId = (int)$scaleSessions[0];
    $rawQuery->execute([$scaleSessionId]);
    $weightQuery = $storePdo->prepare('SELECT VALUE FROM ' . $healthTable
        . " WHERE SESSION_ID=? AND AI_USER_ID=? AND METRIC_CODE='weight'");
    $weightQuery->execute([$scaleSessionId, $userId]);
    $weight = (float)$weightQuery->fetchColumn();
    if ((int)$rawQuery->fetchColumn() !== 1 || abs($weight - 62.5) > 0.001) {
        throw new RuntimeException('Scale raw/weight database readback mismatch');
    }
    $latest = $request('/api/yunkangbao.scale/latest?storeId=10001');
    $byDate = $request('/api/yunkangbao.scale/by_date?storeId=10001&date=' . $today);
    $dates = $request('/api/yunkangbao.scale/dates?storeId=10001');
    if ((int)($latest['status'] ?? 0) !== 200
        || abs((float)($latest['data']['summary']['weight']['value'] ?? 0) - 62.5) > 0.001
        || (int)($byDate['status'] ?? 0) !== 200
        || abs((float)($byDate['data']['summary']['weight']['value'] ?? 0) - 62.5) > 0.001
        || (int)($dates['status'] ?? 0) !== 200
        || !in_array($today, (array)($dates['data']['list'] ?? []), true)) {
        throw new RuntimeException('Scale latest/by-date/dates HTTP readback mismatch: '
            . json_encode([
                'latest_status' => $latest['status'] ?? null,
                'latest_weight' => $latest['data']['summary']['weight']['value'] ?? null,
                'by_date_status' => $byDate['status'] ?? null,
                'by_date_message' => mb_substr((string)($byDate['message'] ?? ''), 0, 100),
                'by_date_weight' => $byDate['data']['summary']['weight']['value'] ?? null,
                'dates_status' => $dates['status'] ?? null,
                'dates_data_keys' => array_keys((array)($dates['data'] ?? [])),
            ]));
    }
    echo json_encode(['dialect' => $dialect, 'status' => 'passed',
        'scale_http_upload_and_three_reads' => true, 'session_rows' => 1,
        'raw_rows' => 1, 'weight' => 62.5]) . PHP_EOL;
    if ($requireStaff) {
        $readStaff = $pdo->prepare('SELECT WEIGHT FROM ' . $staffTable . ' WHERE ID=? AND USER_ID=?');
        $readStaff->execute([$staffId, $userId]);
        $staffWeight = (float)$readStaff->fetchColumn();
        $weightRows = $pdo->prepare('SELECT COUNT(*) FROM ' . $weightTable
            . ' WHERE USER_ID=? AND STORE_ID=10001 AND WEIGHT=?');
        $weightRows->execute([$userId, '62.5']);
        $bindRows = $pdo->prepare('SELECT COUNT(*) FROM ' . $bindTable . ' WHERE USER_ID=?');
        $bindRows->execute([$userId]);
        $stubHits = (string)file_get_contents($root . '/runtime/poc-stub-hits.log');
        if (abs($staffWeight - 62.5) > 0.001 || (int)$weightRows->fetchColumn() !== 1
            || (int)$bindRows->fetchColumn() !== 1
            || strpos($stubHits, 'queue_jump') === false
            || strpos($stubHits, 'user_sync') === false) {
            throw new RuntimeException('Scale secondary user-weight persistence or stubs not reached');
        }
        echo json_encode(['dialect' => $dialect, 'status' => 'passed',
            'secondary_weight_recorded' => true, 'staff_weight' => 62.5,
            'queue_and_external_sync_stubbed' => true]) . PHP_EOL;
    }
    $welland = $request('/api/wolland.scale/add?storeId=10001', ['form' => [
        'weight' => 64, 'bmi' => 22, 'height' => 170, 'date' => $today,
    ]]);
    if ((int)($welland['status'] ?? 0) !== 200) {
        throw new RuntimeException('Welland scale upload HTTP failed: '
            . mb_substr((string)($welland['message'] ?? ''), 0, 100));
    }
    $wellandQuery = $storePdo->prepare('SELECT SESSION_ID FROM ' . $sessionTable
        . " WHERE AI_USER_ID=? AND VENDOR='welland' AND DEVICE_TYPE='body_scale'");
    $wellandQuery->execute([$userId]);
    $wellandSessions = $wellandQuery->fetchAll(PDO::FETCH_COLUMN);
    if (count($wellandSessions) !== 1) throw new RuntimeException('Welland scale session readback mismatch');
    $wellandSessionId = (int)$wellandSessions[0];
    $rawQuery->execute([$wellandSessionId]);
    $weightQuery->execute([$wellandSessionId, $userId]);
    if ((int)$rawQuery->fetchColumn() !== 1
        || abs((float)$weightQuery->fetchColumn() - 64.0) > 0.001) {
        throw new RuntimeException('Welland scale raw/weight database readback mismatch');
    }
    $wellandLatest = $request('/api/wolland.scale/latest?storeId=10001');
    $wellandByDate = $request('/api/wolland.scale/by_date?storeId=10001&date=' . $today);
    $wellandDates = $request('/api/wolland.scale/dates?storeId=10001');
    if ((int)($wellandLatest['status'] ?? 0) !== 200
        || abs((float)($wellandLatest['data']['summary']['weight']['value'] ?? 0) - 64.0) > 0.001
        || (int)($wellandByDate['status'] ?? 0) !== 200
        || abs((float)($wellandByDate['data']['summary']['weight']['value'] ?? 0) - 64.0) > 0.001
        || (int)($wellandDates['status'] ?? 0) !== 200
        || !in_array($today, (array)($wellandDates['data']['list'] ?? []), true)) {
        throw new RuntimeException('Welland scale latest/by-date/dates HTTP readback mismatch');
    }
    if ($requireStaff) {
        $readStaff->execute([$staffId, $userId]);
        $weightRows = $pdo->prepare('SELECT COUNT(*) FROM ' . $weightTable
            . ' WHERE USER_ID=? AND STORE_ID=10001 AND WEIGHT=?');
        $weightRows->execute([$userId, '64']);
        if (abs((float)$readStaff->fetchColumn() - 64.0) > 0.001
            || (int)$weightRows->fetchColumn() !== 1) {
            throw new RuntimeException('Welland scale secondary user weight mismatch');
        }
    }
    echo json_encode(['dialect' => $dialect, 'status' => 'passed',
        'welland_scale_upload_and_three_reads' => true, 'session_rows' => 1,
        'raw_rows' => 1, 'weight' => 64]) . PHP_EOL;
    if ($requireStaff) {
        $weightDates = $request('/api/user.weight/dates?storeId=10001');
        $weightByDate = $request('/api/user.weight/by_date?storeId=10001&date=' . $today);
        $weightDetail = $request('/api/user.weight/by_date_detail?storeId=10001&date=' . $today);
        $weightStatus = $request('/api/user.weight/status?storeId=10001');
        $weightStatusRepeat = $request('/api/user.weight/status?storeId=10001');
        $statusCount = $pdo->prepare('SELECT COUNT(*) FROM ' . $weightStatusTable
            . ' WHERE USER_ID=? AND STORE_ID=10001 AND DELETE_FLAG=0');
        $statusCount->execute([$userId]);
        if ((int)($weightDates['status'] ?? 0) !== 200
            || !in_array($today, (array)($weightDates['data']['list'] ?? []), true)
            || (int)($weightByDate['status'] ?? 0) !== 200
            || abs((float)($weightByDate['data'][0]['weight'] ?? 0) - 64.0) > 0.001
            || (int)($weightDetail['status'] ?? 0) !== 200
            || abs((float)($weightDetail['data']['data']['weight'] ?? 0) - 64.0) > 0.001
            || (int)($weightStatus['status'] ?? 0) !== 200
            || (int)($weightStatusRepeat['status'] ?? 0) !== 200
            || (int)$statusCount->fetchColumn() !== 1) {
            throw new RuntimeException('User weight HTTP reads/default goal database readback mismatch');
        }
        echo json_encode(['dialect' => $dialect, 'status' => 'passed',
            'user_weight_four_reads' => true, 'default_goal_created_once' => true,
            'latest_weight' => 64]) . PHP_EOL;
        $catalogSql = 'SELECT ID FROM ' . $sportItemTable
            . ' WHERE STORE_ID=10001 AND IS_DELETE=0 AND INTENSITY>0 ORDER BY ID '
            . ($dialect === 'dm' ? 'FETCH FIRST 1 ROWS ONLY' : 'LIMIT 1');
        $itemId = (int)$pdo->query($catalogSql)->fetchColumn();
        if ($itemId <= 0) throw new RuntimeException('Sport item catalog fixture missing');
        $allItems = $request('/api/sport.item/all?storeId=10001');
        $grouped = $request('/api/sport.item/grouped?storeId=10001');
        $listed = $request('/api/sport.item/list?storeId=10001&page_size=100');
        $listedPost = $request('/api/sport.item/list?storeId=10001', ['page_size' => 100]);
        $allIds = array_map('intval', array_column((array)($allItems['data']['list'] ?? []), 'id'));
        $groupedIds = [];
        foreach ((array)($grouped['data']['list'] ?? []) as $category) {
            foreach ((array)($category['items'] ?? []) as $catalogItem) {
                $groupedIds[] = (int)($catalogItem['id'] ?? 0);
            }
        }
        if ((int)($allItems['status'] ?? 0) !== 200
            || (int)($grouped['status'] ?? 0) !== 200
            || (int)($listed['status'] ?? 0) !== 200
            || (int)($listedPost['status'] ?? 0) !== 200
            || !in_array($itemId, $allIds, true)
            || !in_array($itemId, $groupedIds, true)
            || empty($listed['data']['list']['data'])
            || empty($listedPost['data']['list']['data'])) {
            throw new RuntimeException('Sport catalog HTTP read endpoints failed');
        }
        $recordUrl = '/api/sport.item/record?storeId=10001';
        foreach ([15, 5] as $duration) {
            $recorded = $request($recordUrl, ['form' => [
                'sport_item_id' => $itemId, 'actual_duration' => $duration, 'date' => $today,
            ]]);
            if ((int)($recorded['status'] ?? 0) !== 200) {
                throw new RuntimeException('Sport record HTTP insert/accumulate failed');
            }
        }
        $itemQuery = $pdo->prepare('SELECT ID,ACTUAL_DURATION,ACTUAL_CONSUME FROM '
            . $userSportItemTable . ' WHERE STORE_ID=10001 AND USER_ID=? AND SPORT_ITEM_ID=?');
        $itemQuery->execute([$userId, $itemId]);
        $sportRows = array_map('array_change_key_case', $itemQuery->fetchAll(PDO::FETCH_ASSOC));
        if (count($sportRows) !== 1 || (int)$sportRows[0]['actual_duration'] !== 20) {
            throw new RuntimeException('Sport record accumulation database readback mismatch');
        }
        $sportRecordId = (int)$sportRows[0]['id'];
        $energyQuery = $pdo->prepare('SELECT ENERGY FROM ' . $userSportEnergyTable
            . ' WHERE STORE_ID=10001 AND USER_ID=? AND TYPE=4');
        $energyQuery->execute([$userId]);
        $energy = $energyQuery->fetchColumn();
        if ($energy === false) throw new RuntimeException('Sport daily energy row missing');
        $daily = $request('/api/sport.item/daily?storeId=10001&date=' . $today);
        $range = $request('/api/sport.item/range?storeId=10001&start_date=' . $today
            . '&end_date=' . $today);
        $consume = $request('/api/sport.item/consume?storeId=10001&sport_item_id=' . $itemId
            . '&duration=30');
        if ((int)($daily['status'] ?? 0) !== 200
            || (int)($daily['data']['total_duration'] ?? 0) !== 20
            || (int)($range['status'] ?? 0) !== 200
            || (int)($range['data']['total_duration'] ?? 0) !== 20
            || (int)($consume['status'] ?? 0) !== 200
            || (int)($consume['data']['sport_item_id'] ?? 0) !== $itemId) {
            throw new RuntimeException('Sport daily/range/consume HTTP readback mismatch');
        }
        $updated = $request('/api/sport.item/update?storeId=10001', ['form' => [
            'user_sport_item_id' => $sportRecordId, 'actual_duration' => 25,
        ]]);
        $itemQuery->execute([$userId, $itemId]);
        $afterUpdate = array_change_key_case($itemQuery->fetch(PDO::FETCH_ASSOC) ?: [], CASE_LOWER);
        if ((int)($updated['status'] ?? 0) !== 200
            || (int)($afterUpdate['actual_duration'] ?? 0) !== 25) {
            throw new RuntimeException('Sport record update database readback mismatch');
        }
        $deleted = $request('/api/sport.item/delete?storeId=10001', ['form' => [
            'user_sport_item_id' => $sportRecordId,
        ]]);
        $itemQuery->execute([$userId, $itemId]);
        if ((int)($deleted['status'] ?? 0) !== 200 || $itemQuery->fetch(PDO::FETCH_ASSOC)) {
            throw new RuntimeException('Sport record deletion database readback mismatch');
        }
        echo json_encode(['dialect' => $dialect, 'status' => 'passed',
            'sport_catalog_and_record_crud_http' => true, 'duration_after_record' => 20,
            'duration_after_update' => 25, 'record_deleted' => true]) . PHP_EOL;
    }
} finally {
    \think\facade\Cache::delete($token);
    if ($created) {
        $sessionQuery = $storePdo->prepare('SELECT SESSION_ID FROM ' . $sessionTable
            . " WHERE AI_USER_ID=? AND VENDOR IN ('welland','yunkangbao')");
        $sessionQuery->execute([$userId]);
        foreach ($sessionQuery->fetchAll(PDO::FETCH_COLUMN) as $testSessionId) {
            $storePdo->prepare('DELETE FROM ' . $healthTable . ' WHERE SESSION_ID=? AND AI_USER_ID=?')
                ->execute([(int)$testSessionId, $userId]);
            $storePdo->prepare('DELETE FROM ' . $rawTable . ' WHERE SESSION_ID=?')
                ->execute([(int)$testSessionId]);
            $storePdo->prepare('DELETE FROM ' . $sessionTable . ' WHERE SESSION_ID=? AND AI_USER_ID=?')
                ->execute([(int)$testSessionId, $userId]);
        }
        $sessionQuery->execute([$userId]);
        $healthCheck = $storePdo->prepare('SELECT COUNT(*) FROM ' . $healthTable
            . ' WHERE AI_USER_ID=?');
        $healthCheck->execute([$userId]);
        if (count($sessionQuery->fetchAll(PDO::FETCH_COLUMN)) !== 0
            || (int)$healthCheck->fetchColumn() !== 0) {
            throw new RuntimeException('Welland device test cleanup left store data');
        }
        $pdo->prepare('DELETE FROM ' . $targetTable . ' WHERE USER_ID=? AND STORE_ID=10001')
            ->execute([$userId]);
        if ($staffId > 0) {
            foreach ([$userSportItemTable, $userSportEnergyTable] as $table) {
                $pdo->prepare('DELETE FROM ' . $table . ' WHERE USER_ID=?')->execute([$userId]);
            }
            foreach ([$bindTable, $scoreLogTable, $scoreTable, $weightTable,
                $weightStatusTable] as $table) {
                $pdo->prepare('DELETE FROM ' . $table . ' WHERE USER_ID=?')->execute([$userId]);
            }
            $pdo->prepare('DELETE FROM ' . $staffTable . ' WHERE ID=? AND USER_ID=?')
                ->execute([$staffId, $userId]);
        }
        $pdo->prepare('DELETE FROM ' . $userTable . ' WHERE USER_ID=? AND NICK_NAME=?')
            ->execute([$userId, $marker]);
        $check = $pdo->prepare('SELECT COUNT(*) FROM ' . $targetTable . ' WHERE USER_ID=?');
        $check->execute([$userId]);
        if ((int)$check->fetchColumn() !== 0) {
            throw new RuntimeException('AI sport target cleanup left data');
        }
        $checkUser = $pdo->prepare('SELECT COUNT(*) FROM ' . $userTable
            . ' WHERE USER_ID=? AND NICK_NAME=?');
        $checkUser->execute([$userId, $marker]);
        if ((int)$checkUser->fetchColumn() !== 0) {
            throw new RuntimeException('Synthetic AI user cleanup left data');
        }
        if ($staffId > 0) {
            foreach ([$staffTable, $weightTable, $weightStatusTable, $scoreTable, $scoreLogTable, $bindTable,
                $userSportItemTable, $userSportEnergyTable] as $table) {
                $checkRelated = $pdo->prepare('SELECT COUNT(*) FROM ' . $table . ' WHERE USER_ID=?');
                $checkRelated->execute([$userId]);
                if ((int)$checkRelated->fetchColumn() !== 0) {
                    throw new RuntimeException('Synthetic AI secondary weight cleanup left data');
                }
            }
        }
    }
}
