/**
 * P0-3 smoke test — NotificationChannel.config is serialized as an
 * AES-256-GCM envelope, never plaintext.
 *
 * Run: npx tsx scripts/smoke/p0-3-channel-encrypt.ts
 *
 * Offline-safe: drives the serialize/decrypt helpers directly. Verifies
 * that the canonical write-path (serializeChannelConfig) produces a v1
 * envelope, that legacy plaintext still decrypts via decryptIfNeeded, and
 * that two encryptions of the same payload differ (proper IV).
 */
import crypto from 'crypto';
import { ok, fail } from './_lib';
import { _resetKeyCacheForTests, decrypt, decryptIfNeeded, isEncrypted } from '../../src/lib/crypto/secret-vault';
import { serializeChannelConfig } from '../../src/lib/notification-system/channel-config';

async function main(): Promise<void> {
    process.env.CHANNEL_ENCRYPTION_KEY = crypto.randomBytes(32).toString('base64');
    _resetKeyCacheForTests();

    // 1. Object input → v1 envelope, round-trips correctly.
    const env1 = serializeChannelConfig({ webhookUrl: 'https://hooks.slack.com/secret' });
    if (!isEncrypted(env1)) fail('P0-3 object encrypts', `expected v1 envelope, got ${env1.slice(0, 32)}`);
    ok('Object input produces v1 envelope');
    const decoded1 = JSON.parse(decrypt(env1));
    if (decoded1.webhookUrl !== 'https://hooks.slack.com/secret') {
        fail('P0-3 round-trip', `expected webhookUrl, got ${JSON.stringify(decoded1)}`);
    }
    ok('Object decrypt round-trip');

    // 2. JSON-string input also encrypts.
    const env2 = serializeChannelConfig('{"chatId":"123"}');
    if (!isEncrypted(env2)) fail('P0-3 string encrypts', 'expected v1 envelope');
    ok('JSON-string input produces v1 envelope');

    // 3. Two encryptions of the same payload differ (fresh IV).
    const a = serializeChannelConfig({ x: 1 });
    const b = serializeChannelConfig({ x: 1 });
    if (a === b) fail('P0-3 fresh IV', 'identical envelopes — IV is not random');
    ok('Fresh IV per call (no determinism)');

    // 4. Empty/null inputs are rejected.
    try {
        serializeChannelConfig('');
        fail('P0-3 empty rejected', 'expected throw on empty input');
    } catch {
        ok('Empty input rejected');
    }
    try {
        serializeChannelConfig(null);
        fail('P0-3 null rejected', 'expected throw on null input');
    } catch {
        ok('Null input rejected');
    }

    // 5. Legacy plaintext (pre-migration) still decrypts via decryptIfNeeded.
    const legacy = '{"webhookUrl":"https://old.example.com"}';
    const passthrough = decryptIfNeeded(legacy);
    if (passthrough !== legacy) fail('P0-3 legacy plaintext', 'plaintext should pass through unchanged');
    ok('Legacy plaintext read-path still works');

    ok('P0-3 channel-encrypt', 'all serialization paths produce encrypted envelopes');
}

main().catch((err) => fail('P0-3 channel-encrypt', String(err)));
