<?php
declare(strict_types=1);

// Offline contract comparator; login token values were already redacted on capture.
$paths = ['B' => (string)getenv('CDX_PASSPORT_B_REDACTED'),
    'C' => (string)getenv('CDX_PASSPORT_C_REDACTED')];
$expectedFiles = [
    'B' => 'd5eb8703b818c1359d350f795f8ec0fd52fc0aca5a8148cd56388a57577d7ab6',
    'C' => '2b4bd4de568a6928036cf9bdccf16b71bdda2573c1c5d1f263a6c75e127a6385',
];
$ownIds = ['B' => 46919, 'C' => 1934];
$sequence = ['loginAccount', 'loginNumber', 'loginDepartment',
    'changePassword', 'loginAccount', 'loginAccount'];
$canonical = null;
$canonical = static function ($value) use (&$canonical) {
    if (!is_array($value)) return $value;
    foreach ($value as $key => $part) $value[$key] = $canonical($part);
    if ($value !== [] && array_keys($value) !== range(0, count($value) - 1)) {
        ksort($value, SORT_STRING);
    }
    return $value;
};
$hashes = [];
$statuses = [];
foreach ($paths as $side => $path) {
    if (!is_file($path) || !hash_equals($expectedFiles[$side],
        (string)hash_file('sha256', $path))) {
        echo json_encode(['status' => 'missing_or_changed_private_evidence',
            'side' => $side]), PHP_EOL;
        exit(78);
    }
    $lines = file($path, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
    if (!is_array($lines) || count($lines) !== count($sequence)) {
        echo json_encode(['status' => 'case_count_mismatch', 'side' => $side]), PHP_EOL;
        exit(78);
    }
    foreach ($lines as $index => $line) {
        $record = json_decode($line, true);
        $body = $record['response_redacted'] ?? null;
        if (!is_array($record) || !is_array($body)
            || ($record['case'] ?? null) !== $sequence[$index]
            || (int)($record['http'] ?? 0) !== 200) {
            echo json_encode(['status' => 'invalid_redacted_record',
                'side' => $side, 'index' => $index]), PHP_EOL;
            exit(78);
        }
        unset($body['trace_id']);
        if (isset($body['data']['userId'])) {
            if (!is_int($body['data']['userId'])
                || $body['data']['userId'] !== $ownIds[$side]
                || ($body['data']['token'] ?? null) !== '<redacted-token>') {
                echo json_encode(['status' => 'non_own_actor_or_token_not_redacted',
                    'side' => $side, 'index' => $index]), PHP_EOL;
                exit(78);
            }
            $body['data']['userId'] = '<own_synthetic_actor>';
        }
        $hashes[$side][$index] = hash('sha256', json_encode($canonical($body),
            JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
        $statuses[$side][$index] = (int)($body['status'] ?? 0);
    }
}
$equal = $hashes['B'] === $hashes['C'];
echo json_encode(['status' => $equal ? 'six_redacted_business_bodies_equal'
        : 'passport_contract_mismatch',
    'methods' => $sequence, 'http_all_200' => true,
    'business_statuses' => $statuses,
    'per_case_business_body_sha256' => $hashes,
    'only_removed_or_normalized' => ['trace_id', 'own_synthetic_userId',
        'captured_token_was_redacted_before_disk'],
    'database_or_http_calls' => 0], JSON_UNESCAPED_SLASHES), PHP_EOL;
exit($equal ? 0 : 4);
