<?php

declare(strict_types=1);

// A/B: one synthetic condiment + private CSV; real local-development MySQL CLI.
$root = (string)getenv('POC_APP_ROOT');
$label = (string)getenv('POC_LABEL');
$stub = (string)getenv('POC_TCHEF_STUB_FILE');
$preflightOnly = getenv('POC_PREFLIGHT_ONLY') === '1';
$localConfigFile = '/workspace/zhct/zhctproject/store/application/config/local/database.php';
if (getenv('POC_DIALECT') !== 'mysql' || getenv('POC_TCHEF_CONFIG_DISABLED') !== '1'
    || !in_array($label, ['A', 'B'], true)
    || strpos(realpath($root) ?: '', '/tmp/zhct-http-store-') !== 0
    || strpos(realpath($stub) ?: '', '/workspace/zhct/zhctprompt/') !== 0
    || !is_file($root . '/think') || !is_file($root . '/application/database.php')
    || !is_file($root . '/application/cron/command/TchefCondimentState.php')
    || !is_file($root . '/application/common/service/tchef/CondimentStateBackfill.php')
    || !is_file($stub) || !is_file($localConfigFile)) {
    throw new RuntimeException('A/B isolated CLI prerequisites unavailable');
}
$runtime = require $root . '/application/database.php';
$local = require $localConfigFile;
foreach (['hostname','database','username','password'] as $key) {
    if ((string)($runtime[$key] ?? '') !== (string)($local[$key] ?? '')) {
        throw new RuntimeException('Runtime connection diverges from Store local development config');
    }
}
if ((int)($runtime['hostport'] ?? 3306) !== (int)($local['hostport'] ?? 3306)) {
    throw new RuntimeException('Runtime port diverges from Store local development config');
}
$pdo = new PDO('mysql:host=' . $runtime['hostname']
    . ';port=' . ($runtime['hostport'] ?? 3306)
    . ';dbname=' . $runtime['database'] . ';charset=utf8mb4',
    $runtime['username'], $runtime['password'], [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_TIMEOUT => 5,
    ]);
$version = (string)$pdo->query('SELECT VERSION()')->fetchColumn();
if (strpos($version, '5.6.') !== 0) throw new RuntimeException('Expected local development MySQL 5.6');
$one = static function (string $sql, array $params = []) use ($pdo): array {
    $query = $pdo->prepare($sql); $query->execute($params);
    return array_change_key_case($query->fetch(PDO::FETCH_ASSOC) ?: [], CASE_LOWER);
};
$count = static function (string $sql, array $params = []) use ($pdo): int {
    $query = $pdo->prepare($sql); $query->execute($params);
    return (int)$query->fetchColumn();
};
$categories = $pdo->query("SELECT id FROM ydy_foods_cate WHERE name='调味品类' AND pid=0")
    ->fetchAll(PDO::FETCH_COLUMN);
$priorMarkers = $count("SELECT COUNT(*) FROM ydy_foods_composition WHERE name LIKE 'CDXPARCONDM%'");
$preflight = [
    'label' => $label, 'dialect' => 'mysql', 'mysql_version' => $version,
    'source_config_is_local' => true, 'category_count' => count($categories),
    'category_id' => count($categories) === 1 ? (int)$categories[0] : null,
    'prior_cdxparcondm_rows' => $priorMarkers,
    'command_sha256' => hash_file('sha256', $root . '/application/cron/command/TchefCondimentState.php'),
    'service_sha256' => hash_file('sha256', $root . '/application/common/service/tchef/CondimentStateBackfill.php'),
];
if ($preflightOnly) {
    echo json_encode(['phase' => 'preflight', 'result' => $preflight],
        JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . PHP_EOL;
    exit(0);
}
if (count($categories) !== 1 || $priorMarkers !== 0) {
    throw new RuntimeException('Synthetic fixture guard failed');
}
$categoryId = (int)$categories[0];
$marker = 'CDXPARCONDM' . strtoupper(bin2hex(random_bytes(4)));
$runCli = static function (string $file, bool $apply) use ($root, $stub): array {
    $args = [PHP_BINARY, '-d', 'auto_prepend_file=' . $stub,
        $root . '/think', 'TchefCondimentState', 'import', '--file=' . $file];
    if ($apply) $args[] = '--apply';
    $command = implode(' ', array_map('escapeshellarg', $args));
    $pipes = [];
    $process = proc_open($command, [1 => ['pipe', 'w'], 2 => ['pipe', 'w']], $pipes, $root);
    if (!is_resource($process)) throw new RuntimeException('CLI child unavailable');
    $stdout = (string)stream_get_contents($pipes[1]);
    $stderr = (string)stream_get_contents($pipes[2]);
    fclose($pipes[1]); fclose($pipes[2]);
    $exit = proc_close($process);
    $stubActive = strpos($stderr, 'POC_TCHEF_CONFIG_DISABLED_PREPEND_ACTIVE') !== false;
    $json = null;
    foreach (array_reverse(preg_split('/\r?\n/', trim($stdout))) as $line) {
        $parsed = json_decode($line, true);
        if (is_array($parsed) && isset($parsed['status'])) { $json = $parsed; break; }
    }
    return ['exit' => $exit, 'same_cli_tchef_stub_active' => $stubActive, 'result' => $json,
        'error_class' => $exit === 0 ? null
            : (strpos($stdout . $stderr, 'SQLSTATE') !== false ? 'database-error' : 'cli-error')];
};
$output = ['preflight' => $preflight, 'marker' => $marker,
    'dry_run' => null, 'apply' => null, 'repeat' => null, 'cleanup' => []];
$id = 0;
$csvFile = '';
$error = null;
try {
    $insert = $pdo->prepare('INSERT INTO ydy_foods_composition'
        . ' (name,category,condiment_state,is_delete,create_by) VALUES (?,?,0,0,?)');
    $insert->execute([$marker, $categoryId, 'CODEX']);
    $row = $one('SELECT id,name,category,condiment_state,is_delete'
        . ' FROM ydy_foods_composition WHERE name=?', [$marker]);
    $id = (int)($row['id'] ?? 0);
    if ($id <= 0 || (int)$row['category'] !== $categoryId
        || (int)$row['condiment_state'] !== 0 || (int)$row['is_delete'] !== 0) {
        throw new RuntimeException('Synthetic insert readback mismatch');
    }
    $csvFile = tempnam('/tmp', 'CDXPARCONDM_');
    if ($csvFile === false) throw new RuntimeException('Private CSV path unavailable');
    $handle = fopen($csvFile, 'wb');
    if ($handle === false) throw new RuntimeException('Private CSV unavailable');
    fputcsv($handle, ['food_id','food_name','second_category','third_category',
        'current_state','target_state','state_options']);
    fputcsv($handle, [$id,$marker,'','',0,1,'1液体/2粉末/3酱料膏状']);
    fclose($handle);
    chmod($csvFile, 0600);

    $output['dry_run'] = $runCli($csvFile, false);
    if ($output['dry_run']['exit'] !== 0 || !$output['dry_run']['same_cli_tchef_stub_active']
        || ($output['dry_run']['result']['status'] ?? '') !== 'validated'
        || (int)($output['dry_run']['result']['would_update'] ?? -1) !== 1
        || (int)$one('SELECT condiment_state FROM ydy_foods_composition WHERE id=?', [$id])['condiment_state'] !== 0) {
        throw new RuntimeException('Dry-run or Tchef isolation gate failed');
    }
    $output['apply'] = $runCli($csvFile, true);
    if ($output['apply']['exit'] !== 0 || !$output['apply']['same_cli_tchef_stub_active']
        || ($output['apply']['result']['status'] ?? '') !== 'applied'
        || (int)($output['apply']['result']['updated'] ?? -1) !== 1
        || (int)($output['apply']['result']['queued'] ?? -1) !== 0
        || ($output['apply']['result']['integration_enabled'] ?? null) !== false
        || (int)$one('SELECT condiment_state FROM ydy_foods_composition WHERE id=?', [$id])['condiment_state'] !== 1) {
        throw new RuntimeException('Apply or exact DB readback gate failed');
    }
    $output['repeat'] = $runCli($csvFile, true);
    if ($output['repeat']['exit'] !== 0 || !$output['repeat']['same_cli_tchef_stub_active']
        || ($output['repeat']['result']['status'] ?? '') !== 'applied'
        || (int)($output['repeat']['result']['updated'] ?? -1) !== 0
        || (int)($output['repeat']['result']['already_applied'] ?? -1) !== 1
        || (int)($output['repeat']['result']['queued'] ?? -1) !== 0
        || ($output['repeat']['result']['integration_enabled'] ?? null) !== false
        || (int)$one('SELECT condiment_state FROM ydy_foods_composition WHERE id=?', [$id])['condiment_state'] !== 1) {
        throw new RuntimeException('Repeat idempotency/readback gate failed');
    }
} catch (Throwable $exception) {
    $error = get_class($exception) . ': ' . substr($exception->getMessage(), 0, 160);
} finally {
    try {
        if ($id <= 0) {
            $existing = $count('SELECT COUNT(*) FROM ydy_foods_composition WHERE name=?', [$marker]);
            if ($existing > 1) throw new RuntimeException('Marker not unique during cleanup');
            if ($existing === 1) {
                $row = $one('SELECT id FROM ydy_foods_composition WHERE name=?', [$marker]);
                $id = (int)($row['id'] ?? 0);
            }
        }
        if ($id > 0) {
            $row = $one('SELECT id,name,category,is_delete FROM ydy_foods_composition WHERE id=?', [$id]);
            if (!$row || (string)$row['name'] !== $marker || (int)$row['category'] !== $categoryId
                || (int)$row['is_delete'] !== 0) {
                throw new RuntimeException('Synthetic cleanup guard failed');
            }
            $delete = $pdo->prepare('DELETE FROM ydy_foods_composition'
                . ' WHERE id=? AND name=? AND category=? AND is_delete=0');
            $delete->execute([$id,$marker,$categoryId]);
            $output['cleanup']['food_exact_deleted'] = $delete->rowCount() === 1
                && $count('SELECT COUNT(*) FROM ydy_foods_composition WHERE id=? OR name=?', [$id,$marker]) === 0;
        }
        if ($csvFile !== '' && is_file($csvFile)) {
            $output['cleanup']['csv_exact_deleted'] = unlink($csvFile) && !is_file($csvFile);
        }
    } catch (Throwable $cleanupException) {
        $output['cleanup_error'] = get_class($cleanupException) . ': '
            . substr($cleanupException->getMessage(), 0, 160);
    }
}
$output['status'] = !$error && !isset($output['cleanup_error'])
    && !in_array(false, $output['cleanup'], true) ? 'passed' : 'failed';
if ($error) $output['failure'] = $error;
echo json_encode($output, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . PHP_EOL;
if ($output['status'] !== 'passed') exit(1);
