<?php
declare(strict_types=1);

// Independent process SELECT-only owned-zero audit; removes only its private journal.
$lane = (string)getenv('CDX_EM_LOG_LANE');
$journalPath = (string)getenv('CDX_EM_LOG_JOURNAL');
if (!in_array($lane, ['A', 'B', 'C'], true)
    || count($argv) !== 2 || ($argv[1] ?? '') !== '--audit-zero'
    || (string)getenv('CDX_EM_LOG_AUDIT') !== 'ROOT_APPROVED_OWNED_LOG_ZERO_V1'
    || !hash_equals((string)hash_file('sha256', __FILE__),
        (string)getenv('CDX_EM_LOG_AUDIT_SHA'))
    || !preg_match('~^/tmp/cdx-em-log-cdxemlog[a-f0-9]{12}/recovery\.json$~D',
        $journalPath)) {
    echo json_encode(['status' => 'default-deny', 'db_connected' => false,
        'business_http_sent' => false, 'dml_sent' => false]), PHP_EOL;
    exit(78);
}
$stage = 'private_journal';
set_exception_handler(static function (Throwable $error) use (&$stage): void {
    echo json_encode(['status' => 'redacted_stop', 'stage' => $stage,
        'error_class' => get_class($error), 'code' => (string)$error->getCode(),
        'journal_retained' => true]), PHP_EOL;
    exit(2);
});
if (is_link($journalPath) || realpath($journalPath) !== $journalPath
    || is_link(dirname($journalPath))
    || (((int)fileperms(dirname($journalPath)) & 0077) !== 0)
    || (((int)fileperms($journalPath) & 0077) !== 0)) {
    throw new RuntimeException('Private journal unsafe or absent');
}
$journal = json_decode((string)file_get_contents($journalPath), true);
if (!is_array($journal) || ($journal['lane'] ?? null) !== $lane
    || ($journal['phase'] ?? null) !== 'cleanup_committed_pending_independent_audit'
    || !preg_match('/^CDXEMLOG[A-F0-9]{12}$/D', (string)($journal['marker'] ?? ''))
    || !preg_match('/^[A-F0-9]{32}$/D', (string)($journal['menu_uuid'] ?? ''))
    || !preg_match('/^[A-F0-9]{32}$/D', (string)($journal['device_uuid'] ?? ''))
    || !preg_match('/^[a-f0-9]{64}$/D', (string)($journal['public_token'] ?? ''))
    || (int)($journal['menu_id'] ?? 0) <= 0
    || (int)($journal['device_record_id'] ?? 0) <= 0
    || !is_array($journal['source_before'] ?? null)) {
    throw new RuntimeException('Owned journal identity invalid');
}
$stage = 'approved_database';
$preflight = __DIR__ . '/preflight_log_batch.php';
if (!hash_equals('8c619b96c447f849b551b5c7119007fee90a34d9ce623eb05e9027280a87fef9',
    (string)hash_file('sha256', $preflight))) {
    throw new RuntimeException('Source preflight drift');
}
putenv('CDX_EM_LOG_PREFLIGHT=OWNED_DEVICE_LOG_BATCH_SELECT_ONLY_V1');
putenv('CDX_EM_LOG_PREFLIGHT_SHA=8c619b96c447f849b551b5c7119007fee90a34d9ce623eb05e9027280a87fef9');
$outerArgv = $argv;
$argv[1] = '--preflight-only';
ob_start();
require $preflight;
$preflightText = (string)ob_get_clean();
$argv = $outerArgv;
restore_exception_handler();
$summary = json_decode(trim($preflightText), true);
if (!is_array($summary) || ($summary['status'] ?? null) !== 'select_only_pass'
    || ($summary['lane'] ?? null) !== $lane
    || ($summary['prior_owned_marker_counts'] ?? null)
        !== ['menu' => 0, 'device' => 0, 'log' => 0]
    || ($summary['auto_id_on_three_tables'] ?? null) !== true
    || (int)($summary['trigger_count'] ?? -1) !== 0
    || (int)($summary['incoming_outgoing_fk_count'] ?? -1) !== 0) {
    throw new RuntimeException('Independent approved DB identity changed');
}
$t = static function (string $name) use ($dialect): string {
    if (!in_array($name, ['electronic_menu', 'electronic_menu_device',
        'electronic_menu_device_log'], true)) {
        throw new RuntimeException('Unapproved audit table');
    }
    return $dialect === 'dm' ? strtoupper('ydy_' . $name) : 'ydy_' . $name;
};
$stage = 'owned_zero_and_three_table_baseline';
$check = $db->prepare('SELECT COUNT(*) FROM ' . $t('electronic_menu')
    . ' WHERE ID=? OR UUID=? OR PUBLIC_TOKEN=? OR CREATE_BY=?');
$check->execute([(int)$journal['menu_id'], $journal['menu_uuid'],
    $journal['public_token'], $journal['marker']]);
$menuCount = (int)$check->fetchColumn();
$check = $db->prepare('SELECT COUNT(*) FROM ' . $t('electronic_menu_device')
    . ' WHERE ID=? OR UUID=? OR DEVICE_ID=? OR MENU_ID=?');
$check->execute([(int)$journal['device_record_id'], $journal['device_uuid'],
    $journal['marker'], (int)$journal['menu_id']]);
$deviceCount = (int)$check->fetchColumn();
$check = $db->prepare('SELECT COUNT(*) FROM ' . $t('electronic_menu_device_log')
    . ' WHERE DEVICE_RECORD_ID=? OR MENU_ID=? OR CREATE_BY=?');
$check->execute([(int)$journal['device_record_id'],
    (int)$journal['menu_id'], 'device:' . $journal['marker']]);
$logCount = (int)$check->fetchColumn();
if ($menuCount !== 0 || $deviceCount !== 0 || $logCount !== 0) {
    throw new RuntimeException('Owned test rows remain');
}
$expected = ['electronic_menu', 'electronic_menu_device',
    'electronic_menu_device_log'];
$keys = array_keys($journal['source_before']);
sort($keys);
$sortedExpected = $expected;
sort($sortedExpected);
if ($keys !== $sortedExpected) throw new RuntimeException('Baseline table set changed');
foreach ($expected as $name) {
    $actual = hash('sha256', serialize($db->query('SELECT * FROM '
        . $t($name) . ' ORDER BY ID')->fetchAll(PDO::FETCH_ASSOC)));
    if (!hash_equals((string)$journal['source_before'][$name], $actual)) {
        throw new RuntimeException('Original table fingerprint not restored');
    }
}
if (!unlink($journalPath) || !rmdir(dirname($journalPath))) {
    throw new RuntimeException('Private journal removal failed');
}
echo json_encode(['status' => 'independent_zero_pass', 'lane' => $lane,
    'menu_rows' => 0, 'device_rows' => 0, 'log_rows' => 0,
    'three_table_fingerprints_restored' => true,
    'private_journal_removed' => true,
    'business_http_sent' => false, 'dml_sent' => false]), PHP_EOL;
