<?php
$project = dirname(__DIR__, 2);
require $project . '/autoload.php';
use ForumRewrite\ReadModel\ReadModelBuilder;
use ForumRewrite\Canonical\CanonicalRecordRepository;
// Audit-only synthetic data. Use a fresh directory outside the project.
$dir = realpath($argv[2] ?? '');
if ($dir === false || !is_dir($dir) || $dir === $project || str_starts_with($dir, $project . '/')) {
    throw new RuntimeException('Pass an existing temporary workspace outside the repository as argument 2.');
}
$marker = $dir . '/qdb-memory-audit.txt';
if (($argv[1] ?? '') === 'setup') {
    if (count(scandir($dir)) !== 2) throw new RuntimeException('Setup requires an empty workspace.');
    file_put_contents($marker, "Purpose: Synthetic QDB memory audit\n");
} elseif (!is_file($marker)) {
    throw new RuntimeException('Run setup in this workspace first.');
}
$db = $dir . '/model.sqlite';
$root = $dir . '/repository';
$mode = $argv[1];
if ($mode === 'setup') {
    mkdir($root);
    $src = $project . '/tests/fixtures/parity_minimal_v1';
    foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($src, FilesystemIterator::SKIP_DOTS), RecursiveIteratorIterator::SELF_FIRST) as $file) {
        $target = $root . substr($file->getPathname(), strlen($src));
        $file->isDir() ? mkdir($target) : copy($file->getPathname(), $target);
    }
    (new ReadModelBuilder($root, $db, new CanonicalRecordRepository($root)))->rebuild();
    $pdo = new PDO('sqlite:' . $db, null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
    $pdo->beginTransaction();
    $post = $pdo->prepare("INSERT INTO posts(post_id,thread_id,created_at,subject,body,board_tags_json,sequence_number,author_label) VALUES (?,?,'2026-10-30T00:00:00Z','quote',?,'[\"general\"]',1,'guest')");
    $thread = $pdo->prepare("INSERT INTO threads(root_post_id,root_post_created_at,last_activity_at,subject,body_preview,board_tags_json,thread_labels_json,reply_count,last_post_id,score_total,vote_count) VALUES (?,'2026-10-30T00:00:00Z','2026-10-30T00:00:00Z','quote',?,'[\"general\"]','[]',0,?,0,0)");
    for ($i = 1; $i <= 40000; $i++) {
        $id = 'thread-20261030000000-qdb-' . (400000 + $i);
        $post->execute([$id, $id, str_repeat('q', 2048)]);
        $thread->execute([$id, str_repeat('q', 1024), $id]);
    }
    $pdo->commit();
    echo "Setup: 40000 synthetic quotes, 2048-byte bodies, 1024-byte previews\n";
    exit;
}
if ($mode === 'setup-records') {
    for ($i = 1; $i <= 40000; $i++) {
        $id = 'thread-20261030000000-qdb-' . (400000 + $i);
        file_put_contents($root . '/records/posts/' . $id . '.txt',
            "Post-ID: {$id}\nCreated-At: 2026-10-30T00:00:00Z\nBoard-Tags: general\nSubject: quote\n\n" . str_repeat('q', 2048) . "\n");
    }
    echo "Canonical posts generated: 40000\n";
    exit;
}
if ($mode === 'setup-commit') {
    $gitRoot = $dir . '/large-commit';
    if (file_exists($gitRoot)) throw new RuntimeException('Commit fixture already exists.');
    mkdir($gitRoot);
    $run = static function (array $command): string {
        $process = proc_open($command, [0 => ['file', '/dev/null', 'r'], 1 => ['pipe', 'w'], 2 => ['file', '/dev/null', 'w']], $pipes);
        if (!is_resource($process)) throw new RuntimeException('Cannot start Git.');
        $out = stream_get_contents($pipes[1]); fclose($pipes[1]);
        if (proc_close($process) !== 0) throw new RuntimeException('Git fixture command failed.');
        return $out;
    };
    $run(['git', 'init', '-q', $gitRoot]);
    $process = proc_open(['git', '-C', $gitRoot, 'fast-import', '--quiet'], [0 => ['pipe', 'r'], 1 => ['file', '/dev/null', 'w'], 2 => ['file', '/dev/null', 'w']], $pipes);
    if (!is_resource($process)) throw new RuntimeException('Cannot start Git import.');
    fwrite($pipes[0], "blob\nmark :1\ndata 1\nx\ncommit refs/heads/main\ncommitter Audit <audit@example.invalid> 1793318400 +0000\ndata 5\naudit\n");
    for ($i = 0; $i < 100000; $i++) fwrite($pipes[0], sprintf("M 100644 :1 records/posts/post-%06d.txt\n", $i));
    fwrite($pipes[0], "\ndone\n"); fclose($pipes[0]);
    if (proc_close($process) !== 0) throw new RuntimeException('Git fixture import failed.');
    file_put_contents($dir . '/sha', trim($run(['git', '-C', $gitRoot, 'rev-parse', 'refs/heads/main'])));
    echo "Synthetic commit paths: 100000\n";
    exit;
}
$pdo = new PDO('sqlite:' . $db, null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC]);
$retainedMiB = (int) ($argv[3] ?? 0);
$retained = $retainedMiB ? str_repeat('x', $retainedMiB * 1024 * 1024) : '';
echo "Mode: $mode\nRetained MiB: $retainedMiB\n";
if ($mode === 'board') {
    $result = ForumRewrite\ReadModel\ThreadRepository::fetchThreads($pdo);
} elseif ($mode === 'qdb-static') {
    putenv('FORUM_SITE_ID=qdb');
    $builder = new ForumRewrite\Host\StaticArtifactBuilder($project, $root, $db, $dir . '/static');
    $builder->buildFromReadModel();
    $result = [];
} elseif ($mode === 'offline-select') {
    $builder = new ForumRewrite\Offline\PublicOfflineSnapshotBuilder($project);
    $result = (new ReflectionMethod($builder, 'snapshotThreadRows'))->invoke($builder, $pdo, 200);
} elseif ($mode === 'static-tags') {
    $builder = new ForumRewrite\Host\StaticArtifactBuilder($project, $root, $db, $dir . '/static');
    $result = (new ReflectionMethod($builder, 'fetchVisibleTagRoutes'))->invoke($builder);
} elseif ($mode === 'fastmod-audit') {
    $store = new ForumRewrite\Scoring\SqliteFastScoreStore(new PDO('sqlite:' . $dir . '/scores.sqlite'));
    $result = (new ForumRewrite\Scoring\FastmodHistoricalAuditService($pdo, $store, 'audit'))->audit();
} elseif ($mode === 'commit-evidence') {
    $service = new ForumRewrite\Activity\ActivityService(static fn (): PDO => $pdo, $dir . '/large-commit', $db);
    $service->primeCommitEvidence([trim(file_get_contents($dir . '/sha'))]);
    $result = [];
} elseif ($mode === 'rebuild') {
    (new ReadModelBuilder($root, $dir . '/rebuilt.sqlite', new CanonicalRecordRepository($root), 'memory_audit', static function (string $message): void {
        if (str_ends_with($message, '...')) echo $message . "\n";
    }))->rebuild();
    $result = [];
} elseif ($mode === 'access-log') {
    file_put_contents($dir . '/access.log', "127.0.0.1 - - [30/Oct/2026:00:00:00 +0000] \"GET /latest HTTP/1.1\" 200 100\n");
    $cache = new ForumRewrite\Host\HighTrafficCache($dir, $root, $db, $dir . '/public');
    $result = (new ForumRewrite\Host\HighTrafficRefresh($cache))->popular($dir . '/access.log');
} elseif ($mode === 'parser-headers') {
    $contents = str_repeat("A: x\n", 2500000) . "\nbody\n";
    echo 'Input bytes: ' . strlen($contents) . "\n";
    $result = [(new ForumRewrite\Canonical\GenericTextRecordParser())->parse($contents)];
} else { throw new RuntimeException('Unknown probe'); }
echo 'Result count: ' . count($result) . "\nPeak PHP MiB: " . round(memory_get_peak_usage(true) / 1048576, 2) . "\n";