/**
 * relation-cache-extraction.test.js — verifies RF-08 deletion test closure.
 *
 * Before this refactor, RelationManager aliased 7 cache fields from
 * RelationCaches (this._relationLookupCache, this._valueLookupCache, etc.).
 * Removing RelationCaches.js from disk without removing the aliases
 * would have left broken references. This test confirms:
 *   - The aliases no longer exist on RelationManager
 *   - All cache state lives under RelationManager._caches
 *   - Functional behavior is unchanged: relations still work, caches still
 *     populate and serve lookups
 */
import { describe, it } from 'node:test';
import assert from 'node:assert/strict';
import { Arbiter } from '../../src/index.js';

describe('RF-08: RelationManager cache extraction', () => {
  it('does not alias cache fields (deletion test)', () => {
    const arbiter = new Arbiter();
    const rm = arbiter.relationManager;

    // The seven aliased fields that used to live on RelationManager
    // are gone. Each must be undefined.
    assert.equal(rm._maxCacheSize, undefined);
    assert.equal(rm._relationLookupCache, undefined);
    assert.equal(rm._valueLookupCache, undefined);
    assert.equal(rm._relationLookupCacheKeys, undefined);
    assert.equal(rm._valueLookupCacheKeys, undefined);
    assert.equal(rm._valueRelationsBySrcCache, undefined);
    assert.equal(rm._valueRelationsByDstCache, undefined);
    assert.equal(rm._valueRelationsByNameCache, undefined);

    // The only cache surface is now _caches (the RelationCaches instance).
    assert.ok(rm._caches);
    assert.ok(rm._caches.relationLookupCache);
    assert.ok(rm._caches.valueLookupCache);
    assert.ok(rm._caches.valueRelationsBySrcCache);
    assert.ok(rm._caches.valueRelationsByDstCache);
    assert.ok(rm._caches.valueRelationsByNameCache);
  });

  it('functional cache behavior is preserved', () => {
    const arbiter = new Arbiter();
    arbiter.addNode('user', 'user');
    arbiter.addNode('doc', 'document');
    arbiter.addRelation('user', 'can_read', 'doc', 1.0);

    const srcId = arbiter.nodeIdByKey.get('user');
    const dstId = arbiter.nodeIdByKey.get('doc');

    // First call populates cache
    const r1 = arbiter.relationManager.getDirectRelation(srcId, 'can_read', dstId);
    assert.ok(r1);

    const cacheKey = arbiter.relationManager._makeDirectCacheKey(srcId, 'can_read', dstId);
    assert.ok(arbiter.relationManager._caches.relationLookupCache.has(cacheKey));

    // Second call hits cache
    const r2 = arbiter.relationManager.getDirectRelation(srcId, 'can_read', dstId);
    assert.equal(r1, r2);

    // Removal invalidates
    arbiter.removeRelation('user', 'can_read', 'doc');
    assert.equal(arbiter.relationManager._caches.relationLookupCache.has(cacheKey), false);
  });

  it('value relation caches still work end-to-end', () => {
    const arbiter = new Arbiter();
    arbiter.addNode('user', 'user');
    arbiter.addNode('account', 'account');
    arbiter.addRelation('user', 'has_balance', 'account', 1.0, { value: 100 });

    const srcId = arbiter.nodeIdByKey.get('user');
    const dstId = arbiter.nodeIdByKey.get('account');

    // Populate
    const v1 = arbiter.relationManager.getValueRelation(srcId, 'has_balance', dstId);
    assert.ok(v1);
    assert.equal(v1.pointValue, 100);

    const cacheKey = arbiter.relationManager._makeValueCacheKey(srcId, 'has_balance', dstId);
    assert.ok(arbiter.relationManager._caches.valueLookupCache.has(cacheKey));

    // Update — should invalidate
    arbiter.relationManager._modifyRelation('user', 'has_balance', 'account', { value: 200 });
    assert.equal(arbiter.relationManager._caches.valueLookupCache.has(cacheKey), false);

    // Re-fetch reflects new value
    const v2 = arbiter.relationManager.getValueRelation(srcId, 'has_balance', dstId);
    assert.equal(v2.pointValue, 200);
  });

  it('cache stats reference _caches.size() correctly', () => {
    const arbiter = new Arbiter();
    arbiter.addNode('a', 'x');
    arbiter.addNode('b', 'x');
    arbiter.addRelation('a', 'rel', 'b', 1.0);

    const srcId = arbiter.nodeIdByKey.get('a');
    const dstId = arbiter.nodeIdByKey.get('b');
    arbiter.relationManager.getDirectRelation(srcId, 'rel', dstId);

    const stats = arbiter.relationManager.getCacheStats();
    assert.ok(typeof stats.relationCacheSize === 'number');
    assert.ok(typeof stats.valueCacheSize === 'number');
    assert.ok(stats.relationCacheSize >= 1);
  });
});