/**
 * SnapshotBinary round-trip tests.
 *
 * Verifies:
 *   - serialize/deserialize preserves nodes and relations
 *   - Deserialized snapshots are marked _snapshotReadOnly
 *   - UTF-8 keys survive round-trip
 *   - Relation configs survive round-trip
 *
 * Run: node --test --test-force-exit lib/tests/property-based/snapshot-binary.test.js
 */
import { Arbiter } from '../../src/core/Arbiter.js';
import { describe, it } from 'node:test';
import assert from 'node:assert/strict';

function createArbiterFactory() {
  return () => new Arbiter({ fastConstructionMode: true, enableInference: false });
}

async function loadSnapshotModule() {
  return import('../../src/core/SnapshotBinary.js');
}

describe('SnapshotBinary — Round-Trip', () => {
  it('serialize and deserialize preserves nodes and relations', async () => {
    const { serializeArbiterSnapshot, deserializeArbiterSnapshot } = await loadSnapshotModule();

    const original = new Arbiter({ fastConstructionMode: true, enableInference: false });
    original.addNode('user:alice', 'user');
    original.addNode('project:secret', 'project');
    original.addRelation('user:alice', 'can_read', 'project:secret', { possibility: 0.9, value: 100 });
    original.setRelationConfig('can_read', { type: 'direct' });
    original.enableCondensedSnapshot();

    const buffer = serializeArbiterSnapshot(original);
    assert.ok(buffer instanceof ArrayBuffer);
    assert.ok(buffer.byteLength > 0);

    const restored = deserializeArbiterSnapshot(buffer, createArbiterFactory());
    assert.ok(restored.nodeIdByKey.has('user:alice'));
    assert.ok(restored.nodeIdByKey.has('project:secret'));

    const nodes = [...restored.nodes.values()].filter(Boolean);
    assert.ok(nodes.length >= 2);
  });

  it('deserialized snapshot is marked read-only', async () => {
    const { serializeArbiterSnapshot, deserializeArbiterSnapshot } = await loadSnapshotModule();

    const original = new Arbiter({ fastConstructionMode: true, enableInference: false });
    original.addNode('user:alice', 'user');
    original.addNode('project:secret', 'project');
    original.addRelation('user:alice', 'can_read', 'project:secret', { possibility: 0.9 });
    original.enableCondensedSnapshot();

    const buffer = serializeArbiterSnapshot(original);
    const restored = deserializeArbiterSnapshot(buffer, createArbiterFactory());

    assert.strictEqual(restored._snapshotReadOnly, true);
    assert.strictEqual(restored.snapshotEnabled, true);
    assert.ok(restored.snapshotGraph);
  });

  it('UTF-8 keys survive round-trip', async () => {
    const { serializeArbiterSnapshot, deserializeArbiterSnapshot } = await loadSnapshotModule();

    const original = new Arbiter({ fastConstructionMode: true, enableInference: false });
    original.addNode('user:alice', 'user');
    original.addNode('project:résumé', 'project');
    original.addRelation('user:alice', 'can_read', 'project:résumé', { possibility: 0.9 });
    original.setRelationConfig('can_read', { type: 'direct' });
    original.enableCondensedSnapshot();

    const buffer = serializeArbiterSnapshot(original);
    const restored = deserializeArbiterSnapshot(buffer, createArbiterFactory());

    assert.ok(restored.nodeIdByKey.has('project:résumé'));
    assert.strictEqual(restored.relationConfigs.has('can_read'), true);
  });

  it('relation configs survive round-trip', async () => {
    const { serializeArbiterSnapshot, deserializeArbiterSnapshot } = await loadSnapshotModule();

    const original = new Arbiter({ fastConstructionMode: true, enableInference: false });
    original.addNode('user:alice', 'user');
    original.addNode('project:secret', 'project');
    original.addRelation('user:alice', 'can_access', 'project:secret', {
      possibility: 0.8,
      value: 42,
      reliability: 0.95
    });
    original.setRelationConfig('can_access', { type: 'chain', steps: [{ relation: 'parent', direction: 'out' }] });
    original.setRelationConfig('can_read', { type: 'direct', minPossibility: 0.5 });
    original.enableCondensedSnapshot();

    const buffer = serializeArbiterSnapshot(original);
    const restored = deserializeArbiterSnapshot(buffer, createArbiterFactory());

    const accessConfig = restored.relationConfigs.get('can_access');
    assert.strictEqual(accessConfig && accessConfig.type, 'chain');
    assert.deepStrictEqual(accessConfig && accessConfig.steps, [{ relation: 'parent', direction: 'out' }]);

    const readConfig = restored.relationConfigs.get('can_read');
    assert.strictEqual(readConfig && readConfig.type, 'direct');
    assert.strictEqual(readConfig && readConfig.minPossibility, 0.5);
  });
});
