<?php

declare(strict_types=1);

$dialect = getenv('POC_DIALECT');
$baseUrl = rtrim((string)getenv('POC_BASE_URL'), '/');
if (!$baseUrl || !in_array($dialect, ['mysql', 'dm'], true)) exit(2);
$host = getenv('POC_HOST');
$port = getenv('POC_PORT');
$schema = getenv('POC_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_USER'), getenv('POC_PASSWORD'),
    [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$equipmentTable = $dialect === 'dm' ? 'YDY_EQUIPMENT' : 'ydy_equipment';
$dishTable = $dialect === 'dm' ? 'YDY_DISHES' : 'ydy_dishes';
$historyTable = $dialect === 'dm' ? 'YDY_EQUIPMENT_PUSH_DISHES' : 'ydy_equipment_push_dishes';
$candidateSql = 'SELECT ID,CODE,LEFT_DISHES_UUID,RIGHT_DISHES_UUID,PUSH_DISHES_USER,'
    . ' PUSH_DISHES_TIME,LEFT_DISHES_WEIGHT,LEFT_DISHES_WEIGHT_MAX,RIGHT_DISHES_WEIGHT_MAX'
    . ' FROM ' . $equipmentTable
    . " WHERE DEL_FLAG=0 AND TYPE IN (2,3,4,10) AND COALESCE(MATE_FLAG,0)<>1 AND CODE<>''"
    . ' ORDER BY ID ' . ($dialect === 'dm' ? 'FETCH FIRST 1 ROWS ONLY' : 'LIMIT 1');
$equipment = array_change_key_case($pdo->query($candidateSql)->fetch(PDO::FETCH_ASSOC) ?: [], CASE_LOWER);
if (!$equipment || (int)$equipment['id'] <= 0) {
    throw new RuntimeException('No offline weighing device fixture; no equipment modified');
}
$dishQuery = $pdo->prepare('SELECT UUID FROM ' . $dishTable
    . ' WHERE IS_DEL=1 AND STATUS=1 AND UUID<>? ORDER BY ID '
    . ($dialect === 'dm' ? 'FETCH FIRST 1 ROWS ONLY' : 'LIMIT 1'));
$dishQuery->execute([(string)($equipment['left_dishes_uuid'] ?? '')]);
$newLeft = (string)$dishQuery->fetchColumn();
if ($newLeft === '') throw new RuntimeException('Alternative dish fixture missing; no equipment modified');
$equipmentId = (int)$equipment['id'];
$baselineHistory = $pdo->prepare('SELECT COALESCE(MAX(ID),0) FROM ' . $historyTable
    . ' WHERE EQUIPMENT_ID=?');
$baselineHistory->execute([$equipmentId]);
$maxBefore = (int)$baselineHistory->fetchColumn();
$post = static function (array $payload) use ($baseUrl): array {
    $context = stream_context_create(['http' => [
        'method' => 'POST',
        'header' => "Content-Type: application/x-www-form-urlencoded\r\n",
        'content' => http_build_query($payload, '', '&', PHP_QUERY_RFC3986),
        'timeout' => 15, 'ignore_errors' => true,
    ]]);
    $body = file_get_contents($baseUrl . '/api/device/equipment/pushDishes', false, $context);
    $response = is_string($body) ? json_decode($body, true) : null;
    if (!is_array($response)) throw new RuntimeException('Device push HTTP response was not JSON');
    return $response;
};
$historyId = 0;
$current = $pdo->prepare('SELECT LEFT_DISHES_UUID,RIGHT_DISHES_UUID,PUSH_DISHES_USER,'
    . ' PUSH_DISHES_TIME,LEFT_DISHES_WEIGHT_MAX,RIGHT_DISHES_WEIGHT_MAX FROM '
    . $equipmentTable . ' WHERE ID=?');
try {
    $response = $post([
        'equipment_id' => $equipmentId,
        'left_dishes_uuid' => $newLeft,
        'right_dishes_uuid' => (string)($equipment['right_dishes_uuid'] ?? ''),
    ]);
    $current->execute([$equipmentId]);
    $after = array_change_key_case($current->fetch(PDO::FETCH_ASSOC) ?: [], CASE_LOWER);
    $history = $pdo->prepare('SELECT ID,LEFT_DISHES_UUID,CREATE_BY FROM ' . $historyTable
        . ' WHERE EQUIPMENT_ID=? AND ID>? ORDER BY ID');
    $history->execute([$equipmentId, $maxBefore]);
    $newRows = array_map('array_change_key_case', $history->fetchAll(PDO::FETCH_ASSOC));
    if ((int)($response['code'] ?? -1) !== 0
        || (string)($after['left_dishes_uuid'] ?? '') !== $newLeft
        || (string)($after['push_dishes_user'] ?? '') !== '设备端'
        || abs((float)($after['left_dishes_weight_max'] ?? 0)
            - (float)($equipment['left_dishes_weight'] ?? 0)) > 0.001
        || count($newRows) !== 1
        || (string)$newRows[0]['left_dishes_uuid'] !== $newLeft) {
        throw new RuntimeException('Offline device push/equipment/history readback mismatch');
    }
    $historyId = (int)$newRows[0]['id'];
    $invalid = $post(['equipment_id' => 0]);
    if ((int)($invalid['code'] ?? 0) === 0) {
        throw new RuntimeException('Missing equipment identity was accepted');
    }
    echo json_encode(['dialect' => $dialect, 'status' => 'passed',
        'offline_equipment_push' => true, 'equipment_updated' => true,
        'history_rows' => 1, 'invalid_rejected' => true]) . PHP_EOL;
} finally {
    $current->execute([$equipmentId]);
    $observed = array_change_key_case($current->fetch(PDO::FETCH_ASSOC) ?: [], CASE_LOWER);
    if ((string)($observed['left_dishes_uuid'] ?? '') === $newLeft
        && (string)($observed['push_dishes_user'] ?? '') === '设备端') {
        $restore = $pdo->prepare('UPDATE ' . $equipmentTable
            . ' SET LEFT_DISHES_UUID=?,RIGHT_DISHES_UUID=?,PUSH_DISHES_USER=?,PUSH_DISHES_TIME=?,'
            . ' LEFT_DISHES_WEIGHT_MAX=?,RIGHT_DISHES_WEIGHT_MAX=?'
            . ' WHERE ID=? AND LEFT_DISHES_UUID=? AND PUSH_DISHES_USER=?');
        $restore->execute([
            (string)($equipment['left_dishes_uuid'] ?? ''),
            (string)($equipment['right_dishes_uuid'] ?? ''),
            (string)($equipment['push_dishes_user'] ?? ''),
            $equipment['push_dishes_time'] ?? null,
            $equipment['left_dishes_weight_max'] ?? null,
            $equipment['right_dishes_weight_max'] ?? null,
            $equipmentId, $newLeft, '设备端',
        ]);
        if ($restore->rowCount() !== 1) throw new RuntimeException('Equipment restore compare-and-set failed');
    }
    if ($historyId <= 0) {
        $findHistory = $pdo->prepare('SELECT ID FROM ' . $historyTable
            . ' WHERE EQUIPMENT_ID=? AND ID>? AND LEFT_DISHES_UUID=? AND CREATE_BY=?');
        $findHistory->execute([$equipmentId, $maxBefore, $newLeft, '设备端']);
        $ids = $findHistory->fetchAll(PDO::FETCH_COLUMN);
        if (count($ids) > 1) throw new RuntimeException('Multiple synthetic device history rows');
        $historyId = (int)($ids[0] ?? 0);
    }
    if ($historyId > 0) {
        $pdo->prepare('DELETE FROM ' . $historyTable . ' WHERE ID=? AND EQUIPMENT_ID=?')
            ->execute([$historyId, $equipmentId]);
    }
    $current->execute([$equipmentId]);
    $restored = array_change_key_case($current->fetch(PDO::FETCH_ASSOC) ?: [], CASE_LOWER);
    foreach (['left_dishes_uuid','right_dishes_uuid','push_dishes_user','push_dishes_time',
        'left_dishes_weight_max','right_dishes_weight_max'] as $field) {
        if ((string)($restored[$field] ?? '') !== (string)($equipment[$field] ?? '')) {
            throw new RuntimeException('Offline equipment original fields were not restored');
        }
    }
    $baselineHistory->execute([$equipmentId]);
    if ((int)$baselineHistory->fetchColumn() !== $maxBefore) {
        throw new RuntimeException('Synthetic device push history was not removed');
    }
}
