/**
 * Analysis of which rules use reachability optimization
 */

import { test } from 'node:test';
import assert from 'node:assert/strict';
import { BigGraphGenerator } from '../helpers/big-graph-generator.js';

test('analyzes which rules use reachability optimization', async () => {
  if (process.env.TEST_DEBUG === '1') console.log('🔍 Analyzing which rules use reachability optimization...');
  
  const generator = new BigGraphGenerator();
  const graphData = generator.generateGraph('enterprise');
  const arbiter = generator.loadIntoArbiter(graphData);
  
  // Initialize reachability checker
  await arbiter.initializeReachabilityChecker({
    strategy: 'auto',
    twoHopOptions: {},
    treeCoverOptions: {}
  });
  
  // Get initial reachability stats
  const initialStats = arbiter.getReachabilityStats();
  if (process.env.TEST_DEBUG === '1') console.log(`Initial reachability stats: ${initialStats.totalQueries} queries`);
  
  // Test different rule types
  const testCases = [
    {
      name: 'DirectRule',
      relation: 'can_read',
      description: 'Direct relations (should use fast path)'
    },
    {
      name: 'ChainRule', 
      relation: 'can_read_via_role',
      description: 'Chain relations (should use reachability)'
    },
    {
      name: 'MultiHopRule',
      relation: 'can_access_multi_hop', 
      description: 'Multi-hop relations (should use reachability)'
    },
    {
      name: 'ParentRule',
      relation: 'can_read', // Parent rule uses direct relations
      description: 'Parent relations (might use reachability)'
    },
    {
      name: 'TupleToUsersetRule',
      relation: 'can_read',
      description: 'Tuple-to-userset relations (might use reachability)'
    }
  ];
  
  const results = {};
  
  for (const testCase of testCases) {
    if (process.env.TEST_DEBUG === '1') console.log(`\\n=== TESTING ${testCase.name} ===`);
    if (process.env.TEST_DEBUG === '1') console.log(`Description: ${testCase.description}`);
    
    // Reset reachability stats
    const beforeStats = arbiter.getReachabilityStats();
    
    // Test the rule
    const testRelations = graphData.relations.filter(r => 
      r.src.startsWith('user:') && r.dst.startsWith('doc:') && 
      r.relation === 'can_read'
    ).slice(0, 3);
    
    const startTime = Date.now();
    let queryCount = 0;
    const latencies = [];
    
    for (const relation of testRelations) {
      const queryStart = process.hrtime.bigint();
      try {
        const result = arbiter.check(relation.src, testCase.relation, relation.dst);
        const queryEnd = process.hrtime.bigint();
        const latency = Number(queryEnd - queryStart) / 1000000;
        latencies.push(latency);
        queryCount++;
      } catch (error) {
        queryCount++;
      }
    }
    
    const duration = Date.now() - startTime;
    const qps = (queryCount / duration) * 1000;
    const avgLatency = latencies.length > 0 ? 
      latencies.reduce((a, b) => a + b, 0) / latencies.length : 0;
    
    // Get reachability stats after
    const afterStats = arbiter.getReachabilityStats();
    const reachabilityQueries = afterStats.totalQueries - beforeStats.totalQueries;
    const twoHopHits = afterStats.twoHopHits - beforeStats.twoHopHits;
    const treeCoverHits = afterStats.treeCoverHits - beforeStats.treeCoverHits;
    const fallbackQueries = afterStats.fallbackQueries - beforeStats.fallbackQueries;
    
    results[testCase.name] = {
      qps,
      avgLatency,
      reachabilityQueries,
      twoHopHits,
      treeCoverHits,
      fallbackQueries,
      usesReachability: reachabilityQueries > 0
    };
    
    if (process.env.TEST_DEBUG === '1') console.log(`   QPS: ${qps.toFixed(2)}`);
    if (process.env.TEST_DEBUG === '1') console.log(`   Avg Latency: ${avgLatency.toFixed(3)}ms`);
    if (process.env.TEST_DEBUG === '1') console.log(`   Reachability Queries: ${reachabilityQueries}`);
    if (process.env.TEST_DEBUG === '1') console.log(`   TwoHop Hits: ${twoHopHits}`);
    if (process.env.TEST_DEBUG === '1') console.log(`   TreeCover Hits: ${treeCoverHits}`);
    if (process.env.TEST_DEBUG === '1') console.log(`   Fallback Queries: ${fallbackQueries}`);
    if (process.env.TEST_DEBUG === '1') console.log(`   Uses Reachability: ${reachabilityQueries > 0 ? '✅ YES' : '❌ NO'}`);
  }
  
  // Analysis
  if (process.env.TEST_DEBUG === '1') console.log('\\n=== REACHABILITY OPTIMIZATION ANALYSIS ===');
  
  const rulesUsingReachability = Object.entries(results)
    .filter(([name, result]) => result.usesReachability)
    .map(([name, result]) => name);
    
  const rulesNotUsingReachability = Object.entries(results)
    .filter(([name, result]) => !result.usesReachability)
    .map(([name, result]) => name);
  
  if (process.env.TEST_DEBUG === '1') console.log(`\\n✅ Rules USING reachability optimization:`);
  rulesUsingReachability.forEach(rule => {
    const result = results[rule];
    if (process.env.TEST_DEBUG === '1') console.log(`   - ${rule}: ${result.reachabilityQueries} queries, ${result.treeCoverHits} tree-cover hits`);
  });
  
  if (process.env.TEST_DEBUG === '1') console.log(`\\n❌ Rules NOT using reachability optimization:`);
  rulesNotUsingReachability.forEach(rule => {
    const result = results[rule];
    if (process.env.TEST_DEBUG === '1') console.log(`   - ${rule}: ${result.qps.toFixed(2)} QPS, ${result.avgLatency.toFixed(3)}ms avg`);
  });
  
  // Performance comparison
  if (process.env.TEST_DEBUG === '1') console.log(`\\n=== PERFORMANCE COMPARISON ===`);
  const reachabilityRules = rulesUsingReachability.map(rule => ({ name: rule, ...results[rule] }));
  const nonReachabilityRules = rulesNotUsingReachability.map(rule => ({ name: rule, ...results[rule] }));
  
  if (reachabilityRules.length > 0) {
    const avgReachabilityQPS = reachabilityRules.reduce((sum, rule) => sum + rule.qps, 0) / reachabilityRules.length;
    if (process.env.TEST_DEBUG === '1') console.log(`Average QPS for rules WITH reachability: ${avgReachabilityQPS.toFixed(2)}`);
  }
  
  if (nonReachabilityRules.length > 0) {
    const avgNonReachabilityQPS = nonReachabilityRules.reduce((sum, rule) => sum + rule.qps, 0) / nonReachabilityRules.length;
    if (process.env.TEST_DEBUG === '1') console.log(`Average QPS for rules WITHOUT reachability: ${avgNonReachabilityQPS.toFixed(2)}`);
  }
  
  // Recommendations
  if (process.env.TEST_DEBUG === '1') console.log(`\\n=== RECOMMENDATIONS ===`);
  if (rulesNotUsingReachability.length > 0) {
    if (process.env.TEST_DEBUG === '1') console.log(`Consider optimizing these rules with reachability indexes:`);
    rulesNotUsingReachability.forEach(rule => {
      if (process.env.TEST_DEBUG === '1') console.log(`   - ${rule}: Could benefit from reachability optimization`);
    });
  } else {
    if (process.env.TEST_DEBUG === '1') console.log(`All tested rules are using reachability optimization! 🎉`);
  }
  
  // Final stats
  const finalStats = arbiter.getReachabilityStats();
  if (process.env.TEST_DEBUG === '1') console.log(`\\n=== FINAL REACHABILITY STATS ===`);
  if (process.env.TEST_DEBUG === '1') console.log(`Total queries: ${finalStats.totalQueries}`);
  if (process.env.TEST_DEBUG === '1') console.log(`TwoHop hits: ${finalStats.twoHopHits}`);
  if (process.env.TEST_DEBUG === '1') console.log(`TreeCover hits: ${finalStats.treeCoverHits}`);
  if (process.env.TEST_DEBUG === '1') console.log(`Fallback queries: ${finalStats.fallbackQueries}`);
  if (process.env.TEST_DEBUG === '1') console.log(`Strategy: ${finalStats.strategy}`);
});
