/**
 * Real-World Testing Utility
 * Tests the scanner on actual code patterns and measures performance
 */

import * as fs from 'fs'
import * as path from 'path'
import { runLayer1Scan } from '../../detect/secrets'
import { runLayer2Scan } from '../../detect/structural'
import { formatTierStats, computeTierStats } from '../../tiers'
import { formatTerminalOutput } from '../../report/formatters/cli-terminal'
import type { ScanFile, Vulnerability, ScanResult } from '../../shared/types'

/**
 * Test result for a directory scan
 */
interface RealWorldTestResult {
  directory: string
  filesScanned: number
  totalFindings: number
  bySeverity: Record<string, number>
  byCategory: Record<string, number>
  scanDuration: number
  filesPerSecond: number
  topFindings: Vulnerability[]
  potentialFalsePositives: Vulnerability[]
}

/**
 * Scan a local directory and analyze results
 */
async function scanDirectory(dirPath: string, maxFiles: number = 100): Promise<RealWorldTestResult> {
  const startTime = Date.now()

  // Collect files
  const files: ScanFile[] = []
  const extensions = new Set(['.ts', '.tsx', '.js', '.jsx', '.py', '.go', '.java', '.rb', '.php'])

  function collectFiles(dir: string, depth: number = 0) {
    if (depth > 10 || files.length >= maxFiles) return

    try {
      const entries = fs.readdirSync(dir, { withFileTypes: true })

      for (const entry of entries) {
        if (files.length >= maxFiles) break

        const fullPath = path.join(dir, entry.name)

        // Skip common non-source directories
        if (entry.isDirectory()) {
          if (['node_modules', '.git', 'dist', 'build', '.next', '__pycache__', 'venv'].includes(entry.name)) {
            continue
          }
          collectFiles(fullPath, depth + 1)
        } else if (entry.isFile()) {
          const ext = path.extname(entry.name).toLowerCase()
          if (extensions.has(ext)) {
            try {
              const content = fs.readFileSync(fullPath, 'utf-8')
              if (content.length < 50000) { // Skip very large files
                files.push({
                  path: fullPath.replace(dirPath + '/', ''),
                  content,
                  language: ext.slice(1),
                  size: content.length,
                })
              }
            } catch {
              // Skip unreadable files
            }
          }
        }
      }
    } catch {
      // Skip unreadable directories
    }
  }

  collectFiles(dirPath)

  if (files.length === 0) {
    console.log(`No scannable files found in ${dirPath}`)
    return {
      directory: dirPath,
      filesScanned: 0,
      totalFindings: 0,
      bySeverity: {},
      byCategory: {},
      scanDuration: 0,
      filesPerSecond: 0,
      topFindings: [],
      potentialFalsePositives: [],
    }
  }

  console.log(`Scanning ${files.length} files from ${dirPath}...`)

  // Run scans
  const layer1Result = await runLayer1Scan(files)
  const layer2Result = await runLayer2Scan(files)

  const scanDuration = Date.now() - startTime
  const allFindings = [...layer1Result.vulnerabilities, ...layer2Result.vulnerabilities]

  // Analyze results
  const bySeverity: Record<string, number> = {
    critical: 0,
    high: 0,
    medium: 0,
    low: 0,
    info: 0,
  }

  const byCategory: Record<string, number> = {}

  for (const finding of allFindings) {
    bySeverity[finding.severity] = (bySeverity[finding.severity] || 0) + 1
    byCategory[finding.category] = (byCategory[finding.category] || 0) + 1
  }

  // Identify potential false positives (info/low in test files, or common patterns)
  const potentialFalsePositives = allFindings.filter(f => {
    // Test files with any findings
    if (f.filePath.includes('test') || f.filePath.includes('spec')) return true
    // Example/fixture files
    if (f.filePath.includes('example') || f.filePath.includes('fixture')) return true
    // Mock files
    if (f.filePath.includes('mock') || f.filePath.includes('__mocks__')) return true
    return false
  })

  // Sort findings by severity for top findings
  const severityOrder = { critical: 5, high: 4, medium: 3, low: 2, info: 1 }
  const sortedFindings = [...allFindings].sort(
    (a, b) => severityOrder[b.severity] - severityOrder[a.severity]
  )

  return {
    directory: dirPath,
    filesScanned: files.length,
    totalFindings: allFindings.length,
    bySeverity,
    byCategory,
    scanDuration,
    filesPerSecond: Math.round((files.length * 1000) / scanDuration),
    topFindings: sortedFindings.slice(0, 10),
    potentialFalsePositives,
  }
}

/**
 * Print test result summary
 */
function printResult(result: RealWorldTestResult) {
  console.log('\n' + '='.repeat(70))
  console.log(`REAL-WORLD TEST: ${result.directory}`)
  console.log('='.repeat(70))

  console.log(`\n📁 Files scanned: ${result.filesScanned}`)
  console.log(`⏱️  Scan duration: ${result.scanDuration}ms`)
  console.log(`🚀 Performance: ${result.filesPerSecond} files/sec`)

  console.log(`\n📊 Total findings: ${result.totalFindings}`)
  console.log('By severity:')
  for (const [severity, count] of Object.entries(result.bySeverity)) {
    if (count > 0) console.log(`  ${severity}: ${count}`)
  }

  console.log('\nBy category:')
  const sortedCategories = Object.entries(result.byCategory)
    .sort((a, b) => b[1] - a[1])
    .slice(0, 10)
  for (const [category, count] of sortedCategories) {
    console.log(`  ${category}: ${count}`)
  }

  if (result.potentialFalsePositives.length > 0) {
    console.log(`\n⚠️  Potential false positives: ${result.potentialFalsePositives.length}`)
    console.log('(Findings in test/example/mock files)')
  }

  if (result.topFindings.length > 0) {
    console.log('\n🔝 Top findings:')
    for (const finding of result.topFindings.slice(0, 5)) {
      console.log(`  [${finding.severity.toUpperCase()}] ${finding.category}: ${finding.title}`)
      console.log(`    ${finding.filePath}:${finding.lineNumber}`)
    }
  }

  // Assessment
  console.log('\n' + '-'.repeat(70))
  console.log('ASSESSMENT')
  console.log('-'.repeat(70))

  const fpRate = result.totalFindings > 0
    ? (result.potentialFalsePositives.length / result.totalFindings * 100).toFixed(1)
    : '0'

  console.log(`False positive rate (test/mock files): ${fpRate}%`)
  console.log(`Performance target (<5s for 100 files): ${result.scanDuration < 5000 ? '✅ PASS' : '❌ FAIL'}`)

  const blockingCount = result.bySeverity.critical + result.bySeverity.high
  if (blockingCount > 0) {
    console.log(`\n⚠️  ${blockingCount} blocking issues found - review recommended`)
  } else {
    console.log('\n✅ No blocking issues found')
  }
}

/**
 * Run real-world tests
 */
async function main() {
  console.log('=' .repeat(70))
  console.log('OCULUM REAL-WORLD TESTING')
  console.log('=' .repeat(70))

  // Test on the scanner's own codebase
  const scannerPath = path.resolve(__dirname, '../..')

  console.log('\n📂 Testing on scanner codebase itself...')
  const result = await scanDirectory(scannerPath, 50)
  printResult(result)

  // Summary
  console.log('\n' + '='.repeat(70))
  console.log('TESTING COMPLETE')
  console.log('='.repeat(70))

  console.log('\nTo test on other directories:')
  console.log('  npx tsx src/lib/scanner/__tests__/benchmark/run-real-world-test.ts /path/to/repo')
}

// Allow testing specific directories via command line
const targetDir = process.argv[2]
if (targetDir) {
  scanDirectory(path.resolve(targetDir), 100)
    .then(printResult)
    .catch(console.error)
} else {
  main().catch(console.error)
}
