/**
 * Test reachability integration with all rule types
 */

import { test } from 'node:test';
import assert from 'node:assert/strict';
import { BigGraphGenerator } from '../helpers/big-graph-generator.js';
import { ChainRule } from '../../src/authorization/rules/ChainRule.js';
import { DirectRule } from '../../src/authorization/rules/DirectRule.js';
import { MultiHopRule } from '../../src/authorization/rules/MultiHopRule.js';

test('verifies all rules can use quick reachability failure checks', async () => {
  if (process.env.TEST_DEBUG === '1') console.log('🔍 Testing reachability integration with all rule types...');
  
  const generator = new BigGraphGenerator();
  const graphData = generator.generateGraph('enterprise');
  const arbiter = generator.loadIntoArbiter(graphData);
  
  // Initialize reachability checker
  await arbiter.initializeReachabilityChecker({
    strategy: 'auto',
    twoHopOptions: { remainderBits: 8 },
    treeCoverOptions: { remainderBits: 8 }
  });
  
  if (process.env.TEST_DEBUG === '1') console.log('   ✅ Reachability checker initialized');
  
  // Test with different rule types
  const ruleTypes = [
    { name: 'ChainRule', rule: new ChainRule(arbiter) },
    { name: 'DirectRule', rule: new DirectRule(arbiter) },
    { name: 'MultiHopRule', rule: new MultiHopRule(arbiter) }
  ];
  
  const testRelations = graphData.relations.filter(r => 
    r.src.startsWith('user:') && r.dst.startsWith('doc:')
  ).slice(0, 3);
  
  for (const { name, rule } of ruleTypes) {
    if (process.env.TEST_DEBUG === '1') console.log(`   Testing ${name} reachability integration...`);
    
    // Test quick reachability check
    const sourceKey = testRelations[0].src;
    const targetKey = testRelations[0].dst;
    
    // Test _quickReachabilityCheck
    const isReachable = rule._quickReachabilityCheck(sourceKey, targetKey);
    if (process.env.TEST_DEBUG === '1') console.log(`   ${name} quick check: ${sourceKey} -> ${targetKey}: ${isReachable}`);
    assert.ok(typeof isReachable === 'boolean' || isReachable === null, 'Should return boolean or null');
    
    // Test _quickReachabilityFailure
    const failureResult = rule._quickReachabilityFailure(sourceKey, targetKey, `Test failure for ${name}`);
    if (failureResult) {
      if (process.env.TEST_DEBUG === '1') console.log(`   ${name} quick failure: ${failureResult.possibility} (${failureResult.reason})`);
      assert.ok(failureResult.possibility === 0, 'Quick failure should return 0 possibility');
      assert.ok(failureResult.reason.includes(name), 'Should include rule name in reason');
    } else {
      if (process.env.TEST_DEBUG === '1') console.log(`   ${name} quick failure: No failure (reachable or no checker)`);
    }
    
    // Test _getReachableNodes
    const reachableNodes = rule._getReachableNodes(sourceKey, 5);
    if (reachableNodes) {
      if (process.env.TEST_DEBUG === '1') console.log(`   ${name} reachable nodes: ${reachableNodes.length} found`);
      assert.ok(Array.isArray(reachableNodes), 'Should return array of reachable nodes');
    } else {
      if (process.env.TEST_DEBUG === '1') console.log(`   ${name} reachable nodes: No checker available`);
    }
    
    // Test _getReachingNodes
    const reachingNodes = rule._getReachingNodes(targetKey, 5);
    if (reachingNodes) {
      if (process.env.TEST_DEBUG === '1') console.log(`   ${name} reaching nodes: ${reachingNodes.length} found`);
      assert.ok(Array.isArray(reachingNodes), 'Should return array of reaching nodes');
    } else {
      if (process.env.TEST_DEBUG === '1') console.log(`   ${name} reaching nodes: No checker available`);
    }
    
    if (process.env.TEST_DEBUG === '1') console.log(`   ✅ ${name} reachability integration working`);
  }
  
  if (process.env.TEST_DEBUG === '1') console.log('   ✅ All rule types can use reachability failure checks');
});

test('verifies batch reachability checking', async () => {
  if (process.env.TEST_DEBUG === '1') console.log('📦 Testing batch reachability checking...');
  
  const generator = new BigGraphGenerator();
  const graphData = generator.generateGraph('enterprise');
  const arbiter = generator.loadIntoArbiter(graphData);
  
  // Initialize reachability checker
  await arbiter.initializeReachabilityChecker({
    strategy: 'auto',
    twoHopOptions: { remainderBits: 8 },
    treeCoverOptions: { remainderBits: 8 }
  });
  
  const rule = new ChainRule(arbiter);
  
  // Test batch reachability check
  const testPairs = graphData.relations.filter(r => 
    r.src.startsWith('user:') && r.dst.startsWith('doc:')
  ).slice(0, 5).map(r => ({ sourceKey: r.src, targetKey: r.dst }));
  
  if (process.env.TEST_DEBUG === '1') console.log(`   Testing batch check for ${testPairs.length} pairs...`);
  
  const batchResults = rule._batchReachabilityCheck(testPairs);
  
  if (batchResults) {
    if (process.env.TEST_DEBUG === '1') console.log(`   Batch results: ${Object.keys(batchResults).length} pairs checked`);
    
    for (const [pair, result] of Object.entries(batchResults)) {
      if (process.env.TEST_DEBUG === '1') console.log(`   ${pair}: ${result}`);
      assert.ok(typeof result === 'boolean' || result === null, 'Should return boolean or null');
    }
    
    if (process.env.TEST_DEBUG === '1') console.log('   ✅ Batch reachability checking working');
  } else {
    if (process.env.TEST_DEBUG === '1') console.log('   📝 No reachability checker available for batch checking');
  }
});

test('verifies reachability integration in rule evaluation', async () => {
  if (process.env.TEST_DEBUG === '1') console.log('⚡ Testing reachability integration in actual rule evaluation...');
  
  const generator = new BigGraphGenerator();
  const graphData = generator.generateGraph('enterprise');
  const arbiter = generator.loadIntoArbiter(graphData);
  
  // Initialize reachability checker
  await arbiter.initializeReachabilityChecker({
    strategy: 'auto',
    twoHopOptions: { remainderBits: 8 },
    treeCoverOptions: { remainderBits: 8 }
  });
  
  const rule = new ChainRule(arbiter);
  
  // Test actual rule evaluation with reachability
  const testRelation = graphData.relations.find(r => 
    r.src.startsWith('user:') && r.dst.startsWith('doc:')
  );
  
  if (testRelation) {
    if (process.env.TEST_DEBUG === '1') console.log(`   Testing rule evaluation: ${testRelation.src} -> ${testRelation.dst}`);
    
    // Create a simple chain rule configuration
    const ruleConfig = {
      type: 'chain',
      relations: ['role_membership', 'role_permission'],
      maxSteps: 3
    };
    
    // Test rule evaluation
    const result = rule.evaluate(
      arbiter.nodeIdByKey.get(testRelation.src),
      testRelation.src,
      arbiter.nodeIdByKey.get(testRelation.dst),
      testRelation.dst,
      ruleConfig,
      new Set(),
      'can_read_via_role',
      {}
    );
    
    if (process.env.TEST_DEBUG === '1') console.log(`   Rule evaluation result: ${result.possibility} (${result.reason})`);
    if (process.env.TEST_DEBUG === '1') console.log(`   Meta method: ${result.meta?.method || 'unknown'}`);
    
    assert.ok(typeof result.possibility === 'number', 'Should return numeric possibility');
    assert.ok(result.reason, 'Should have a reason');
    
    if (process.env.TEST_DEBUG === '1') console.log('   ✅ Rule evaluation with reachability integration working');
  } else {
    if (process.env.TEST_DEBUG === '1') console.log('   📝 No suitable test relation found');
  }
});
