<?php

declare(strict_types=1);

$root = getenv('POC_TARGET_ROOT');
$dialect = getenv('POC_DIALECT');
if (!$root || !is_file($root . '/think-poc') || !in_array($dialect, ['mysql', 'dm'], true)) exit(2);
$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]);
$userTable = $dialect === 'dm' ? 'YOSHOP_USER' : 'yoshop_user';
$weightTable = $dialect === 'dm' ? 'YOSHOP_USER_WEIGHT' : 'yoshop_user_weight';
$metricTable = $dialect === 'dm' ? 'YOSHOP_USER_HEALTH_METRIC_RECORD' : 'yoshop_user_health_metric_record';
$pdo->query('SELECT COUNT(*) FROM ' . $weightTable . ' WHERE 1=0');
$pdo->query('SELECT COUNT(*) FROM ' . $metricTable . ' WHERE 1=0');
$marker = 'CDXBACKFILL' . strtoupper(bin2hex(random_bytes(5)));
$userId = 0;
$weightId = 0;
$testDate = date('Y-m-d', strtotime('-1 day'));
$testDateTs = strtotime($testDate);
$run = static function (bool $apply) use ($root, $dialect, $testDate, &$userId): array {
    $extensions = '';
    if ($dialect === 'dm') {
        $lib = (string)getenv('POC_DM_PHP_LIB');
        $driver = (string)getenv('POC_DM_PHP_PDO');
        if (!is_file($lib) || !is_file($driver)) {
            throw new RuntimeException('DM PHP command driver unavailable');
        }
        $extensions = ' -d extension=' . escapeshellarg($lib)
            . ' -d extension=' . escapeshellarg($driver);
    }
    $cmd = escapeshellarg(PHP_BINARY) . $extensions . ' '
        . escapeshellarg($root . '/think-poc')
        . ' healthWeightBackfill --store-id=10001'
        . ' --from=' . escapeshellarg($testDate)
        . ' --to=' . escapeshellarg($testDate)
        . ' --user-id=' . (int)$userId
        . ' --batch-size=1 ' . ($apply ? '--apply' : '--dry-run');
    $process = proc_open($cmd, [1 => ['pipe', 'w'], 2 => ['pipe', 'w']], $pipes, $root);
    if (!is_resource($process)) throw new RuntimeException('Backfill command could not start');
    $stdout = stream_get_contents($pipes[1]);
    $stderr = stream_get_contents($pipes[2]);
    fclose($pipes[1]);
    fclose($pipes[2]);
    $exit = proc_close($process);
    if ($exit !== 0) {
        throw new RuntimeException('Backfill command failed: exit=' . $exit
            . ' stderr_present=' . ($stderr !== '' ? 'yes' : 'no'));
    }
    $stats = [];
    foreach (preg_split('/\r?\n/', $stdout) as $line) {
        if (preg_match('/^([a-z_]+)=([^\r\n]+)$/', trim($line), $match)) {
            $stats[$match[1]] = $match[2];
        }
    }
    return $stats;
};
try {
    $insertUser = $pdo->prepare('INSERT INTO ' . $userTable
        . ' (STORE_ID,MOBILE,NICK_NAME,BALANCE,GIFT_BALANCE,IS_DELETE,CREATE_TIME)'
        . ' VALUES (10001,?,?,?,?,0,?)');
    $insertUser->execute(['', $marker, '0.00', '0.00', time()]);
    $userId = (int)$pdo->lastInsertId();
    if ($userId <= 0) throw new RuntimeException('Backfill synthetic user insert failed');
    $insertWeight = $pdo->prepare('INSERT INTO ' . $weightTable
        . ' (USER_ID,STORE_ID,DATE,WEIGHT,HEIGHT,BMI,CREATE_TIME,UPDATE_TIME)'
        . ' VALUES (?,10001,?,?,?,?,?,?)');
    $insertWeight->execute([$userId, $testDateTs, '66.5', '170', '23.01', time(), time()]);
    $weightId = (int)$pdo->lastInsertId();
    if ($weightId <= 0) throw new RuntimeException('Backfill source weight insert failed');
    $sourceKey = 'user-weight:' . $weightId;
    $targetCount = $pdo->prepare('SELECT COUNT(*) FROM ' . $metricTable
        . ' WHERE USER_ID=? AND SOURCE_KEY=?');
    $targetCount->execute([$userId, $sourceKey]);
    if ((int)$targetCount->fetchColumn() !== 0) {
        throw new RuntimeException('Backfill target was not initially empty');
    }
    $dry = $run(false);
    $targetCount->execute([$userId, $sourceKey]);
    if (($dry['mode'] ?? '') !== 'dry-run' || (int)($dry['source_rows'] ?? 0) !== 1
        || (int)($dry['would_insert'] ?? 0) !== 2
        || (int)$targetCount->fetchColumn() !== 0) {
        throw new RuntimeException('Backfill dry-run changed data or counted candidates incorrectly');
    }
    $applied = $run(true);
    $read = $pdo->prepare('SELECT METRIC_CODE,VALUE FROM ' . $metricTable
        . ' WHERE USER_ID=? AND SOURCE_KEY=? ORDER BY METRIC_CODE');
    $read->execute([$userId, $sourceKey]);
    $rows = array_map('array_change_key_case', $read->fetchAll(PDO::FETCH_ASSOC));
    if (($applied['mode'] ?? '') !== 'apply' || (int)($applied['inserted'] ?? 0) !== 2
        || count($rows) !== 2
        || (string)$rows[0]['metric_code'] !== 'bmi'
        || abs((float)$rows[0]['value'] - 23.01) > 0.001
        || (string)$rows[1]['metric_code'] !== 'weight'
        || abs((float)$rows[1]['value'] - 66.5) > 0.001) {
        throw new RuntimeException('Backfill apply/database readback mismatch');
    }
    $repeat = $run(true);
    $targetCount->execute([$userId, $sourceKey]);
    if ((int)($repeat['inserted'] ?? -1) !== 0
        || (int)($repeat['identical_skipped'] ?? 0) !== 2
        || (int)$targetCount->fetchColumn() !== 2) {
        throw new RuntimeException('Backfill repeat was not idempotent');
    }
    echo json_encode(['dialect' => $dialect, 'status' => 'passed',
        'command_dry_run_apply_repeat' => true,
        'source_rows' => 1, 'inserted_metrics' => 2,
        'repeat_identical_skipped' => 2]) . PHP_EOL;
} finally {
    if ($userId > 0) {
        $pdo->prepare('DELETE FROM ' . $metricTable . ' WHERE USER_ID=? AND SOURCE_KEY=?')
            ->execute([$userId, 'user-weight:' . $weightId]);
        $pdo->prepare('DELETE FROM ' . $weightTable . ' WHERE USER_ID=? AND ID=?')
            ->execute([$userId, $weightId]);
        $pdo->prepare('DELETE FROM ' . $userTable . ' WHERE USER_ID=? AND NICK_NAME=?')
            ->execute([$userId, $marker]);
        foreach ([$metricTable, $weightTable, $userTable] as $table) {
            $check = $pdo->prepare('SELECT COUNT(*) FROM ' . $table . ' WHERE USER_ID=?');
            $check->execute([$userId]);
            if ((int)$check->fetchColumn() !== 0) {
                throw new RuntimeException('Backfill synthetic cleanup left data');
            }
        }
    }
}
