import { test } from 'node:test';
import assert from 'node:assert/strict';
import {
  buildLayerConformanceMatrix,
  getAllowedRelationsForLayer,
  getAllowedCategoriesForLayer,
  getProhibitedCategoriesForLayer,
  getRelationCategory,
  getSupportedReducersForRelation,
  isReducerAllowedForRelation,
  listLayerNames,
  resolveLayerName,
  validateReducerConfig,
  validateClaimsForLayer
} from '../../../src/core/partial-graph/layer-registry.js';

test('ADR-042: layer registry exposes all named layers and aliases', () => {
  const expected = [
    'token_projection',
    'workflow_overlay',
    'request_observed',
    'attested_context',
    'caller_declared',
    'challenge_evidence',
    'provenance_overlay',
    'delegation_evidence',
    'approval_evidence'
  ];
  assert.deepEqual(listLayerNames(), expected);
  assert.equal(resolveLayerName(' workflow_claims '), 'workflow_overlay');
  assert.equal(resolveLayerName('REQUEST_OBSERVED'), 'request_observed');
  assert.equal(resolveLayerName(''), null);
});

test('ADR-042: conformance matrix is complete and enforced for all layers', () => {
  const matrix = buildLayerConformanceMatrix();
  const names = new Set(listLayerNames());

  assert.equal(matrix.layer_count, names.size);
  assert.ok(Array.isArray(matrix.layers));
  assert.equal(matrix.layers.length, names.size);

  for (const layer of matrix.layers) {
    assert.ok(names.has(layer.layer_name));
    assert.equal(layer.conformance, 'enforced');
    assert.ok(Array.isArray(layer.allowed_relations));
    assert.ok(layer.allowed_relations.length > 0);
    assert.deepEqual(layer.allowed_relations, getAllowedRelationsForLayer(layer.layer_name));
    assert.deepEqual(layer.allowed_categories, getAllowedCategoriesForLayer(layer.layer_name));
    assert.deepEqual(layer.prohibited_categories, getProhibitedCategoriesForLayer(layer.layer_name));
  }
});

test('ADR-042: relation allowlists are enforced with accepted/rejected claims', () => {
  const ok = validateClaimsForLayer('request_observed', [
    { relation: 'from_ip', object: 'ip:10.0.0.1' },
    { relation: 'request_has_id', object: 'req:1' }
  ]);
  assert.equal(ok.valid, true);
  assert.equal(ok.accepted_claims.length, 2);
  assert.equal(ok.rejected_claims.length, 0);

  const bad = validateClaimsForLayer('caller_declared', [
    { relation: 'client_fingerprint_evidence', object: 'fp:abc' },
    { relation: 'delegated_authority', object: 'resource:x' }
  ]);
  assert.equal(bad.valid, false);
  assert.equal(bad.accepted_claims.length, 1);
  assert.equal(bad.rejected_claims.length, 1);
  assert.deepEqual(bad.disallowed_relations, ['delegated_authority']);
});

test('ADR-042: invalid layers and caller allowlist restrictions are enforced', () => {
  const invalid = validateClaimsForLayer('not_a_layer', [
    { relation: 'from_ip', object: 'ip:10.0.0.1' }
  ]);
  assert.equal(invalid.valid, false);
  assert.equal(invalid.error, 'invalid_layer_type');
  assert.deepEqual(invalid.allowed_layers, listLayerNames());

  const callerRestricted = validateClaimsForLayer(
    'token_projection',
    [
      { relation: 'workflow_handoff', object: 'wf:1' },
      { relation: 'delegated_authority', object: 'resource:1' }
    ],
    ['workflow_handoff']
  );
  assert.equal(callerRestricted.valid, false);
  assert.equal(callerRestricted.accepted_claims.length, 1);
  assert.equal(callerRestricted.rejected_claims.length, 1);
  assert.deepEqual(callerRestricted.disallowed_relations, ['delegated_authority']);
});

test('ADR-042: category-level conformance is enforced', () => {
  assert.equal(getRelationCategory('from_ip'), 'request_metadata');
  assert.equal(getRelationCategory('workflow_handoff'), 'workflow_authority');
  assert.equal(getRelationCategory('unknown_relation'), 'unclassified');

  const result = validateClaimsForLayer('caller_declared', [
    { relation: 'workflow_handoff', object: 'wf:1' }
  ]);

  assert.equal(result.valid, false);
  assert.equal(result.category_conflicts.length, 1);
  assert.equal(result.category_conflicts[0].category, 'workflow_authority');
});

test('ADR-042: reducer support is relation-scoped and validated', () => {
  assert.deepEqual(getSupportedReducersForRelation('request_has_timestamp'), ['latest', 'first', 'unique']);
  assert.equal(isReducerAllowedForRelation('request_has_timestamp', 'latest'), true);
  assert.equal(isReducerAllowedForRelation('request_has_timestamp', 'union_refs'), false);

  const validation = validateReducerConfig({
    request_has_timestamp: 'latest',
    provenance_hash_ref: 'union_refs',
    delegated_authority: 'strongest'
  });

  assert.equal(validation.ok, false);
  assert.deepEqual(validation.valid, {
    request_has_timestamp: 'latest',
    provenance_hash_ref: 'union_refs'
  });
  assert.equal(validation.invalid.length, 1);
  assert.equal(validation.invalid[0].relation, 'delegated_authority');
});
