import { describe, test } from 'node:test';
import assert from 'node:assert/strict';
import fc from 'fast-check';
import { Arbiter } from '../../src/core/Arbiter.js';

function keyFor(srcId, dstId) {
  return `${srcId}->${dstId}`;
}

describe('Fast-check: direct relations invariants', () => {
  test('direct checks match add/remove sequence', () => {
    fc.assert(
      fc.property(
        fc.integer({ min: 1, max: 5 }),
        fc.integer({ min: 1, max: 5 }),
        fc.array(
          fc.record({
            src: fc.integer({ min: 0, max: 4 }),
            dst: fc.integer({ min: 0, max: 4 }),
            op: fc.constantFrom('add', 'remove')
          }),
          { minLength: 1, maxLength: 50 }
        ),
        (userCount, docCount, ops) => {
          const arbiter = new Arbiter();
          arbiter.setRelationConfig('owner', { type: 'direct' });
          for (let u = 0; u < userCount; u++) {
            arbiter.addNode(`user:${u}`, 'user');
          }
          for (let d = 0; d < docCount; d++) {
            arbiter.addNode(`doc:${d}`, 'doc');
          }

          const model = new Set();
          for (const op of ops) {
            const src = op.src % userCount;
            const dst = op.dst % docCount;
            if (op.op === 'add') {
              arbiter.addRelation(`user:${src}`, 'owner', `doc:${dst}`, 1.0);
              model.add(keyFor(src, dst));
            } else {
              arbiter.removeRelation(`user:${src}`, 'owner', `doc:${dst}`);
              model.delete(keyFor(src, dst));
            }
          }

          for (let u = 0; u < userCount; u++) {
            for (let d = 0; d < docCount; d++) {
              const result = arbiter.check(`user:${u}`, 'owner', `doc:${d}`);
              const hasEdge = model.has(keyFor(u, d));
              assert.strictEqual(result.possibility > 0, hasEdge);
            }
          }
        }
      ),
      { numRuns: 50 }
    );
  });
});
