<?php

declare(strict_types=1);

// A single synthetic condiment: real ThinkPHP CLI dry-run/apply/repeat, exact cleanup.
$root = (string)getenv('POC_APP_ROOT');
$stub = (string)getenv('POC_TCHEF_STUB_FILE');
if (getenv('POC_DIALECT') !== 'dm' || getenv('POC_TCHEF_CONFIG_DISABLED') !== '1'
    || strpos(realpath($root) ?: '', '/tmp/zhct-') !== 0
    || strpos(realpath($stub) ?: '', '/tmp/zhct-') !== 0
    || !is_file($root . '/think') || !is_file($stub)
    || !is_file($root . '/application/database.php')) {
    throw new RuntimeException('Isolated C command prerequisites unavailable');
}
$config = require $root . '/application/database.php';
$pdo = new PDO('dm:host=' . $config['hostname'] . ';port=' . $config['hostport']
    . ';schema=' . $config['database'], $config['username'], $config['password'],
    [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$one = static function (string $sql, array $params = []) use ($pdo): array {
    $statement = $pdo->prepare($sql); $statement->execute($params);
    return array_change_key_case($statement->fetch(PDO::FETCH_ASSOC) ?: [], CASE_LOWER);
};
$count = static function (string $sql, array $params = []) use ($pdo): int {
    $statement = $pdo->prepare($sql); $statement->execute($params);
    return (int)$statement->fetchColumn();
};
$categoryRows = $pdo->query("SELECT ID FROM YDY_FOODS_CATE WHERE NAME='调味品类' AND PID=0")
    ->fetchAll(PDO::FETCH_COLUMN);
if (count($categoryRows) !== 1) throw new RuntimeException('Top-level condiment category not unique');
$categoryId = (int)$categoryRows[0];
$marker = 'CDXPARCOND' . strtoupper(bin2hex(random_bytes(4)));
if ($count('SELECT COUNT(*) FROM YDY_FOODS_COMPOSITION WHERE NAME=?', [$marker]) !== 0) {
    throw new RuntimeException('Synthetic marker collision');
}
$runCli = static function (string $file, bool $apply) use ($root, $stub): array {
    $args = [PHP_BINARY,
        '-d', 'extension=/home/dmdba/dmdbms/drivers/php_pdo/libphp73_dm.so',
        '-d', 'extension=/home/dmdba/dmdbms/drivers/php_pdo/php73_pdo_dm.so',
        '-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, 'stub_active_in_same_cli' => $stubActive, 'result' => $json,
        'error_class' => $exit === 0 ? null
            : (strpos($stdout . $stderr, 'SQLSTATE') !== false ? 'database-error' : 'cli-error')];
};
$output = ['dialect' => 'dm', 'marker' => $marker, 'category_id' => $categoryId,
    'dry_run' => null, 'apply' => null, 'repeat' => null, 'cleanup' => []];
$id = 0;
$file = '';
$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']);
    $idRow = $one('SELECT ID,NAME,CATEGORY,CONDIMENT_STATE,IS_DELETE FROM YDY_FOODS_COMPOSITION WHERE NAME=?',
        [$marker]);
    $id = (int)($idRow['id'] ?? 0);
    if ($id <= 0 || (int)$idRow['category'] !== $categoryId
        || (int)$idRow['condiment_state'] !== 0 || (int)$idRow['is_delete'] !== 0) {
        throw new RuntimeException('Synthetic food insert readback mismatch');
    }
    $file = tempnam('/tmp/zhct-dm-poc-20260928.fcpiiN', 'CDXPARCOND_');
    if ($file === false) throw new RuntimeException('Private CSV path unavailable');
    $handle = fopen($file, '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($file, 0600);

    $output['dry_run'] = $runCli($file, false);
    if ($output['dry_run']['exit'] !== 0 || !$output['dry_run']['stub_active_in_same_cli']
        || ($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/CLI isolation gate failed');
    }
    $output['apply'] = $runCli($file, true);
    if ($output['apply']['exit'] !== 0 || !$output['apply']['stub_active_in_same_cli']
        || ($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($file, true);
    if ($output['repeat']['exit'] !== 0 || !$output['repeat']['stub_active_in_same_cli']
        || ($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) {
            $markerCount = $count('SELECT COUNT(*) FROM YDY_FOODS_COMPOSITION WHERE NAME=?', [$marker]);
            if ($markerCount > 1) throw new RuntimeException('Synthetic marker not unique during cleanup');
            if ($markerCount === 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 food 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 ($file !== '' && is_file($file)) {
            $output['cleanup']['csv_exact_deleted'] = unlink($file) && !is_file($file);
        }
    } 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);
