/**
 * Dynamic analysis without Playwright - uses Node.js to analyze module structure,
 * dependency graph, import patterns, and potential runtime costs.
 */
import { readFileSync, readdirSync, statSync } from 'fs';
import { join, relative, basename } from 'path';

const SRC = join(import.meta.dirname, '..', 'src');
const DIST = join(import.meta.dirname, '..', 'dist');

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');
      results.push({ file: relative(join(SRC, '..'), full), content, lines: content.split('\n').length });
    }
  }
}
walk(SRC);

// ─── 1. Dependency Graph Analysis ───
console.log('═══════════════════════════════════════════════');
console.log('  1. MODULE DEPENDENCY GRAPH ANALYSIS');
console.log('═══════════════════════════════════════════════');

const importMap = new Map(); // file -> [imports]

for (const r of results) {
  const imports = [];
  // Match import statements
  const importRe = /import\s+(?:.*?\s+from\s+)?['"]([^'"]+)['"]/g;
  let m;
  while ((m = importRe.exec(r.content)) !== null) {
    imports.push(m[1]);
  }
  // Match dynamic imports
  const dynRe = /import\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
  while ((m = dynRe.exec(r.content)) !== null) {
    imports.push(`[dynamic]${m[1]}`);
  }
  importMap.set(r.file, imports);
}

// Find circular dependencies
console.log('\n--- Circular Dependency Detection ---');
function findCircular(file, visited = new Set(), path = []) {
  if (visited.has(file)) {
    if (path.includes(file)) {
      console.log(`  [CIRCULAR] ${path.slice(path.indexOf(file)).join(' -> ')} -> ${file}`);
    }
    return;
  }
  visited.add(file);
  path.push(file);
  const deps = importMap.get(file) || [];
  for (const dep of deps) {
    if (dep.startsWith('.') || dep.startsWith('/')) {
      // Resolve relative path
      const dir = file.split('/').slice(0, -1).join('/');
      const resolved = dep.replace(/^\.\//, dir + '/').replace(/^\.\.\//, '');
      // Find matching file
      for (const r of results) {
        if (r.file.includes(resolved) || r.file.includes(basename(resolved))) {
          findCircular(r.file, new Set(visited), [...path]);
        }
      }
    }
  }
}
for (const file of importMap.keys()) {
  findCircular(file);
}

// Check high-fanin files (imported by many)
const fanIn = new Map();
for (const imports of importMap.values()) {
  for (const imp of imports) {
    const key = imp.replace(/\[dynamic\]/, '');
    fanIn.set(key, (fanIn.get(key) || 0) + 1);
  }
}

console.log('\n--- High Fan-In Modules (most imported) ---');
const sortedFanIn = [...fanIn.entries()].sort((a, b) => b[1] - a[1]).slice(0, 15);
for (const [mod, count] of sortedFanIn) {
  const bar = '█'.repeat(Math.min(30, count));
  console.log(`  ${mod.padEnd(50)} ${String(count).padStart(3)}x  ${bar}`);
}

// Check high-fanout files (import many)
console.log('\n--- High Fan-Out Modules (import most) ---');
const sortedFanOut = [...importMap.entries()]
  .map(([f, imps]) => [f, imps.length])
  .sort((a, b) => b[1] - a[1]).slice(0, 15);
for (const [file, count] of sortedFanOut) {
  const bar = '█'.repeat(Math.min(30, count));
  console.log(`  ${file.padEnd(50)} ${String(count).padStart(3)} deps  ${bar}`);
}

// Dynamic imports analysis (lazy loading effectiveness)
console.log('\n--- Lazy Loading (Dynamic Imports) ---');
let dynamicImports = 0, staticImports = 0;
for (const imports of importMap.values()) {
  for (const imp of imports) {
    if (imp.startsWith('[dynamic]')) dynamicImports++;
    else staticImports++;
  }
}
console.log(`  Static imports:     ${staticImports}`);
console.log(`  Dynamic imports:    ${dynamicImports}`);
console.log(`  Lazy load ratio:    ${((dynamicImports / (staticImports + dynamicImports)) * 100).toFixed(1)}%`);

// Find files that should be lazy loaded but aren't
const largePages = results.filter(r => r.lines > 500 && r.file.includes('Page'));
for (const r of largePages) {
  const isLazyImported = [...importMap.values()].some(imps => 
    imps.some(i => i.startsWith('[dynamic]') && i.includes(basename(r.file, '.tsx')))
  );
  if (!isLazyImported && !r.file.includes('App')) {
    // Check if it's referenced in App.tsx
    const appContent = results.find(x => x.file === 'src/App.tsx')?.content || '';
    if (appContent.includes(basename(r.file, '.tsx'))) {
      console.log(`  [INFO] ${r.file} (${r.lines} lines) - loaded via App.tsx`);
    }
  }
}

// ─── 2. React Rendering Cost Analysis ───
console.log('\n═══════════════════════════════════════════════');
console.log('  2. REACT RENDERING COST ANALYSIS');
console.log('═══════════════════════════════════════════════');

// Count useState/useReducer per component (state update triggers re-render)
console.log('\n--- State Hook Density ---');
for (const r of results) {
  if (!r.file.endsWith('.tsx')) continue;
  const stateHooks = (r.content.match(/useState\s*[<(]/g) || []).length;
  const reducers = (r.content.match(/useReducer\s*[<(]/g) || []).length;
  const effects = (r.content.match(/useEffect\s*\(/g) || []).length;
  const memos = (r.content.match(/useMemo\s*\(/g) || []).length;
  const callbacks = (r.content.match(/useCallback\s*[<(]/g) || []).length;
  const refs = (r.content.match(/useRef\s*[<(]/g) || []).length;
  
  const totalHooks = stateHooks + reducers + effects + memos + callbacks + refs;
  if (totalHooks > 15) {
    const risk = totalHooks > 30 ? '🔴 HIGH' : totalHooks > 20 ? '🟡 MEDIUM' : '🟢 LOW';
    console.log(`  ${risk}  ${r.file}`);
    console.log(`         useState:${stateHooks} useReducer:${reducers} useEffect:${effects} useMemo:${memos} useCallback:${callbacks} useRef:${refs} (total:${totalHooks})`);
    
    // Check if there are many state updates that could be batched
    const setters = r.content.match(/set\w+\(/g) || [];
    if (setters.length > 20) {
      console.log(`         ⚠️  ${setters.length} state setter calls — potential for excessive re-renders`);
    }
    
    // Check for missing useMemo on expensive computations
    const expensiveInRender = (r.content.match(/\.map\(|\.filter\(|\.reduce\(|\.sort\(/g) || []).length;
    if (expensiveInRender > 5 && memos === 0) {
      console.log(`         ⚠️  ${expensiveInRender} array operations in render body with 0 useMemo`);
    }
  }
}

// ─── 3. useEffect Dependency Analysis ───
console.log('\n═══════════════════════════════════════════════');
console.log('  3. useEffect DEPENDENCY ANALYSIS');
console.log('═══════════════════════════════════════════════');

for (const r of results) {
  if (!r.file.endsWith('.tsx')) continue;
  // Find useEffect with no dependency array (runs every render)
  const noDeps = (r.content.match(/useEffect\s*\(\s*\(\)\s*=>\s*\{[\s\S]*?\}\s*\)/g) || []).length;
  // Find useEffect with empty deps
  const emptyDeps = (r.content.match(/useEffect\s*\(\s*\(\)\s*=>\s*\{[\s\S]*?\}\s*,\s*\[\s*\]\s*\)/g) || []).length;
  
  if (noDeps > 0) {
    console.log(`  [RENDER-COST] ${r.file}: ${noDeps} useEffect(s) run EVERY render`);
  }
  if (emptyDeps > 0) {
    console.log(`  [MOUNT-EFFECT] ${r.file}: ${emptyDeps} useEffect(s) run on mount only`);
  }
}

// ─── 4. Zustand Store Analysis ───
console.log('\n═══════════════════════════════════════════════');
console.log('  4. ZUSTAND STORE ANALYSIS');
console.log('═══════════════════════════════════════════════');

const storeFiles = results.filter(r => r.file.includes('store') || r.file.includes('Store'));
for (const r of storeFiles) {
  const stateFields = (r.content.match(/^\s+\w+:/gm) || []).length;
  const actions = (r.content.match(/^\s+\w+\s*:\s*(\(|function|\w+\s*=>)/gm) || []).length;
  const subscribers = (r.content.match(/subscribe\s*\(/g) || []).length;
  
  console.log(`\n  ${r.file}`);
  console.log(`    State fields: ~${stateFields}`);
  console.log(`    Actions:      ~${actions}`);
  console.log(`    Subscribers:  ${subscribers}`);
  
  // Check for selector usage patterns
  if (r.content.includes('set(') && !r.content.includes('useShallow')) {
    console.log(`    ⚠️  Uses set() without useShallow — may cause unnecessary re-renders`);
  }
}

// ─── 5. Bundle Composition Analysis ───
console.log('\n═══════════════════════════════════════════════');
console.log('  5. BUNDLE COMPOSITION ANALYSIS');
console.log('═══════════════════════════════════════════════');

if (readdirSync(DIST).includes('assets')) {
  const assets = readdirSync(join(DIST, 'assets'));
  const jsFiles = assets.filter(f => f.endsWith('.js') && !f.endsWith('.br'));
  const cssFiles = assets.filter(f => f.endsWith('.css') && !f.endsWith('.br'));
  
  let totalJs = 0, totalCss = 0;
  const chunks = [];
  for (const f of jsFiles) {
    const size = statSync(join(DIST, 'assets', f)).size;
    totalJs += size;
    chunks.push({ name: f, sizeKB: size / 1024, type: 'js' });
  }
  for (const f of cssFiles) {
    const size = statSync(join(DIST, 'assets', f)).size;
    totalCss += size;
    chunks.push({ name: f, sizeKB: size / 1024, type: 'css' });
  }
  
  chunks.sort((a, b) => b.sizeKB - a.sizeKB);
  
  console.log(`\n  Total JS:  ${(totalJs / 1024).toFixed(1)} KB (${(totalJs / 1024 / 1024).toFixed(2)} MB)`);
  console.log(`  Total CSS: ${(totalCss / 1024).toFixed(1)} KB (${(totalCss / 1024 / 1024).toFixed(2)} MB)`);
  console.log(`  Total:     ${((totalJs + totalCss) / 1024).toFixed(1)} KB`);
  
  // CSS is suspiciously large
  const cssRatio = totalCss / totalJs;
  if (cssRatio > 0.5) {
    console.log(`\n  ⚠️  CSS/JS ratio: ${(cssRatio * 100).toFixed(0)}% — CSS bundle may contain unused styles`);
    console.log(`     Consider: PurgeCSS, CSS Modules, or extracting to separate loads`);
  }
  
  // Check initial load budget
  const initialChunks = chunks.filter(c => 
    c.name.includes('index') || c.name.includes('vendor-react') || c.name.includes('vendor-antd')
  );
  const initialLoad = initialChunks.reduce((s, c) => s + c.sizeKB, 0);
  console.log(`\n  Critical path (initial load):`);
  for (const c of initialChunks) {
    console.log(`    ${c.name.padEnd(45)} ${c.sizeKB.toFixed(1).padStart(8)} KB`);
  }
  console.log(`    ${'TOTAL'.padEnd(45)} ${initialLoad.toFixed(1).padStart(8)} KB`);
  
  if (initialLoad > 300) {
    console.log(`\n  ⚠️  Initial load > 300KB — consider code splitting or tree-shaking`);
  }
}

// ─── 6. API Client Efficiency ───
console.log('\n═══════════════════════════════════════════════');
console.log('  6. API CLIENT EFFICIENCY');
console.log('═══════════════════════════════════════════════');

const apiFiles = results.filter(r => r.file.includes('src/api/'));
for (const r of apiFiles) {
  const fetchCalls = (r.content.match(/fetch\s*\(/g) || []).length;
  const retries = (r.content.match(/retry|Retry|RETRY/g) || []).length;
  const abortSignals = (r.content.match(/AbortSignal|AbortController/g) || []).length;
  const timeouts = (r.content.match(/timeout|Timeout|setTimeout/g) || []).length;
  
  if (fetchCalls > 0) {
    console.log(`\n  ${r.file}`);
    console.log(`    fetch calls:    ${fetchCalls}`);
    console.log(`    retry logic:    ${retries > 0 ? '✅' : '❌ none'}`);
    console.log(`    abort signals:  ${abortSignals > 0 ? '✅' : '❌ none'}`);
    console.log(`    timeouts:       ${timeouts}`);
  }
}

// ─── 7. TypeScript Compilation Metrics ───
console.log('\n═══════════════════════════════════════════════');
console.log('  7. TYPE COMPLEXITY');
console.log('═══════════════════════════════════════════════');

let totalTypes = 0, totalInterfaces = 0, totalEnums = 0, totalGenerics = 0;
for (const r of results) {
  totalTypes += (r.content.match(/^export\s+type\s+/gm) || []).length;
  totalTypes += (r.content.match(/^type\s+/gm) || []).length;
  totalInterfaces += (r.content.match(/^export\s+interface\s+/gm) || []).length;
  totalInterfaces += (r.content.match(/^interface\s+/gm) || []).length;
  totalEnums += (r.content.match(/enum\s+\w+/g) || []).length;
  totalGenerics += (r.content.match(/<\w+(?:\s*,\s*\w+)*>/g) || []).length;
}

console.log(`  Type aliases:    ${totalTypes}`);
console.log(`  Interfaces:      ${totalInterfaces}`);
console.log(`  Enums:           ${totalEnums}`);
console.log(`  Generic usages:  ${totalGenerics}`);
console.log(`  Total TS files:  ${results.length}`);

// ─── Final Summary ───
console.log('\n═══════════════════════════════════════════════');
console.log('  ANALYSIS COMPLETE');
console.log('═══════════════════════════════════════════════');
