import { readdirSync, readFileSync } from 'fs';
import { join, relative } from 'path';

const SRC = join(import.meta.dirname, '..', 'src');
const results = [];

function walk(dir) {
  for (const entry of readdirSync(dir, { withFileTypes: true })) {
    const full = join(dir, entry.name);
    if (entry.isDirectory() && entry.name !== 'node_modules') walk(full);
    else if (/\.(tsx?|jsx?)$/.test(entry.name)) {
      const content = readFileSync(full, 'utf-8');
      const lines = content.split('\n').length;
      results.push({ file: relative(join(SRC, '..'), full), lines, content });
    }
  }
}
walk(SRC);
results.sort((a, b) => b.lines - a.lines);

console.log('=== TOP 30 FILES BY LINE COUNT ===');
for (const r of results.slice(0, 30)) {
  console.log(`${String(r.lines).padStart(5)}  ${r.file}`);
}

// Detect nested loops (3+ levels)
console.log('\n=== NESTED LOOP DETECTION (3+ levels) ===');
const loopPatterns = [
  /for\s*\(/g, /while\s*\(/g, /\.forEach\s*\(/g, /\.map\s*\(/g,
  /\.filter\s*\(/g, /\.reduce\s*\(/g, /\.some\s*\(/g, /\.every\s*\(/g,
  /\.flatMap\s*\(/g, /\.find\s*\(/g
];

for (const r of results) {
  const lines = r.content.split('\n');
  for (let i = 0; i < lines.length; i++) {
    const line = lines[i];
    let loopCount = 0;
    for (const p of loopPatterns) {
      p.lastIndex = 0;
      if (p.test(line)) loopCount++;
    }
    // Check surrounding context for nesting
    if (loopCount > 0 || /for\s*\(/.test(line) || /\.map\(/.test(line) || /\.forEach\(/.test(line) || /\.filter\(/.test(line) || /\.reduce\(/.test(line)) {
      // Count loop keywords on this single line
      let singleLineLoops = 0;
      for (const p of loopPatterns) {
        p.lastIndex = 0;
        const matches = line.match(new RegExp(p.source, 'g'));
        if (matches) singleLineLoops += matches.length;
      }
      if (singleLineLoops >= 2) {
        console.log(`  [NESTED] ${r.file}:${i + 1} (${singleLineLoops} loops on one line)`);
        console.log(`    ${line.trim().substring(0, 120)}`);
      }
    }
  }
}

// Detect missing cleanup in useEffect
console.log('\n=== MEMORY LEAK RISK: useEffect without cleanup ===');
for (const r of results) {
  if (!r.file.endsWith('.tsx') && !r.file.endsWith('.ts')) continue;
  const content = r.content;
  // Find useEffect blocks that contain setInterval/setTimeout/addEventListener but no return
  const useEffectRegex = /useEffect\s*\(\s*\(\)\s*=>\s*\{([\s\S]*?)\}\s*,/g;
  let match;
  while ((match = useEffectRegex.exec(content)) !== null) {
    const body = match[1];
    const hasTimer = /setInterval|setTimeout/.test(body);
    const hasListener = /addEventListener/.test(body);
    const hasSubscribe = /\.subscribe\(/.test(body);
    const hasCleanup = /return\s*\(\)\s*=>|return\s*function|return\s*\(\{/.test(body);
    
    if ((hasTimer || hasListener || hasSubscribe) && !hasCleanup) {
      const lineNum = content.substring(0, match.index).split('\n').length;
      console.log(`  [RISK] ${r.file}:${lineNum}`);
      if (hasTimer) console.log(`    - Has setInterval/setTimeout without cleanup`);
      if (hasListener) console.log(`    - Has addEventListener without cleanup`);
      if (hasSubscribe) console.log(`    - Has subscribe without cleanup`);
      console.log(`    ${body.trim().substring(0, 200)}`);
      console.log('');
    }
  }
}

// Detect objects/arrays/functions created in render body (not memoized)
console.log('\n=== REDUNDANT COMPUTATION: Non-memoized values in components ===');
for (const r of results) {
  if (!r.file.endsWith('.tsx')) continue;
  const lines = r.content.split('\n');
  // Look for const x = [...], const x = {...}, const x = (...) => patterns outside useMemo
  let inUseMemo = 0;
  for (let i = 0; i < lines.length; i++) {
    if (/useMemo\s*\(/.test(lines[i])) inUseMemo++;
    if (inUseMemo > 0 && /\)/.test(lines[i])) {
      // Rough heuristic - not perfect
    }
    if (inUseMemo === 0) {
      // Expensive operations in render
      if (/\.map\s*\(.*\.map\s*\(/.test(lines[i])) {
        console.log(`  [PERF] ${r.file}:${i + 1} - Chained .map calls in render`);
        console.log(`    ${lines[i].trim().substring(0, 120)}`);
      }
      if (/\.filter\s*\(.*\.map\s*\(/.test(lines[i]) || /\.map\s*\(.*\.filter\s*\(/.test(lines[i])) {
        console.log(`  [PERF] ${r.file}:${i + 1} - filter+map chain in render`);
        console.log(`    ${lines[i].trim().substring(0, 120)}`);
      }
    }
  }
}

// Detect deeply nested conditionals (4+ levels)
console.log('\n=== HIGH COMPLEXITY: Deep nesting ===');
for (const r of results) {
  const lines = r.content.split('\n');
  for (let i = 0; i < lines.length; i++) {
    const line = lines[i];
    if (line.trim() === '') continue;
    const indent = line.match(/^(\s*)/)[1].length;
    // Only flag if inside if/else/switch/ternary
    if (indent >= 16 && /if\s*\(|else|switch\s*\(|case\s+/.test(line.trim())) {
      console.log(`  [DEEP] ${r.file}:${i + 1} (indent=${indent})`);
      console.log(`    ${line.trim().substring(0, 120)}`);
    }
  }
}

// Detect inline style objects in JSX (recreated every render)
console.log('\n=== REDUNDANT: Inline style objects in JSX ===');
for (const r of results) {
  if (!r.file.endsWith('.tsx')) continue;
  const lines = r.content.split('\n');
  for (let i = 0; i < lines.length; i++) {
    if (/style\s*=\s*\{\s*\{/.test(lines[i]) && !/useMemo/.test(lines[i])) {
      console.log(`  [INLINE] ${r.file}:${i + 1}`);
      console.log(`    ${lines[i].trim().substring(0, 120)}`);
    }
  }
}

// Total stats
console.log('\n=== SUMMARY ===');
console.log(`Total files: ${results.length}`);
console.log(`Total lines: ${results.reduce((s, r) => s + r.lines, 0)}`);
console.log(`Files > 500 lines: ${results.filter(r => r.lines > 500).length}`);
console.log(`Files > 1000 lines: ${results.filter(r => r.lines > 1000).length}`);
