/**
 * Layer 1: Surface Scan
 * Fast, deterministic scanning using entropy, patterns, config auditing,
 * file flags, comment analysis, URL detection, and weak crypto detection
 */

import type { Vulnerability, ScanFile, CancellationToken } from '../../shared/types'
import type { ProgressCallback } from '../../shared/types'
import { detectHighEntropyStrings } from './entropy'
import { detectKnownPatterns } from './patterns'
import { auditConfiguration } from './config-audit'
import { detectDangerousFiles } from '../config/file-flags'
import { detectAICommentPatterns } from '../config/comments'
import { detectSensitiveURLs } from '../config/urls'
import { detectWeakCrypto } from './weak-crypto'
import { detectMCPConfigIssues } from './config-mcp-audit'
import { detectAgentSkillInjection } from '../config/agent-skill-injection'
// Tier system removed in Phase 2B — confidence scoring handles routing
import {
  filterFindingsByPath,
  type ExclusionConfig,
} from '../../parse/path-exclusions'
import { severityRank } from '../../shared/parsed-file'
import { ParsedFile } from '../../shared/parsed-file'

/**
 * Layer 1 detector stats for raw finding counts before deduplication
 */
export interface Layer1Stats {
  /** Raw finding counts per detector (before dedupe) */
  raw: Record<string, number>
  /** Deduped finding counts per category */
  deduped: Record<string, number>
  /** Number of findings suppressed by path exclusions */
  suppressedByPath: number
}

export interface Layer1Result {
  vulnerabilities: Vulnerability[]
  filesScanned: number
  duration: number
  /** Heuristic breakdown stats for noise analysis */
  stats: Layer1Stats
}

// Layer 1 detector stat keys
type Layer1StatsRecord = {
  known_secrets: number
  weak_crypto: number
  sensitive_urls: number
  entropy: number
  config_audit: number
  file_flags: number
  ai_comments: number
  mcp_config: number
  agent_skill: number
}

// Process a single file through all Layer 1 detectors
function processFileLayer1(file: ScanFile): {
  findings: Vulnerability[],
  stats: Layer1StatsRecord
} {
  const stats: Layer1StatsRecord = {
    known_secrets: 0,
    weak_crypto: 0,
    sensitive_urls: 0,
    entropy: 0,
    config_audit: 0,
    file_flags: 0,
    ai_comments: 0,
    mcp_config: 0,
    agent_skill: 0,
  }

  // Create ParsedFile once for all detectors to share
  const parsed = ParsedFile.from(file)

  const entropyFindings = detectHighEntropyStrings(file.content, file.path, { parsed })
  const patternFindings = detectKnownPatterns(file.content, file.path, { parsed })
  const configFindings = auditConfiguration(file.content, file.path, { parsed })
  const fileFlags = detectDangerousFiles(file.content, file.path, { parsed })
  const commentFindings = detectAICommentPatterns(file.content, file.path, { parsed })
  const urlFindings = detectSensitiveURLs(file.content, file.path, { parsed })
  const cryptoFindings = detectWeakCrypto(file.content, file.path, { parsed })
  const mcpConfigFindings = detectMCPConfigIssues(file.content, file.path, { parsed })
  const agentSkillFindings = detectAgentSkillInjection(file.content, file.path, { parsed })

  stats.entropy = entropyFindings.length
  stats.known_secrets = patternFindings.length
  stats.config_audit = configFindings.length
  stats.file_flags = fileFlags.length
  stats.ai_comments = commentFindings.length
  stats.sensitive_urls = urlFindings.length
  stats.weak_crypto = cryptoFindings.length
  stats.mcp_config = mcpConfigFindings.length
  stats.agent_skill = agentSkillFindings.length

  return {
    findings: [
      ...entropyFindings,
      ...patternFindings,
      ...configFindings,
      ...fileFlags,
      ...commentFindings,
      ...urlFindings,
      ...cryptoFindings,
      ...mcpConfigFindings,
      ...agentSkillFindings,
    ],
    stats,
  }
}

// Parallel batch size for Layer 1 processing (larger batches for performance)
const LAYER1_PARALLEL_BATCH_SIZE = 50
// Progress update interval (report every N files for better UX)
const PROGRESS_UPDATE_INTERVAL = 10

export async function runLayer1Scan(
  files: ScanFile[],
  onProgress?: ProgressCallback,
  cancellationToken?: CancellationToken
): Promise<Layer1Result> {
  const startTime = Date.now()
  const vulnerabilities: Vulnerability[] = []

  // Track raw counts per detector (before dedupe)
  const rawStats: Layer1StatsRecord = {
    known_secrets: 0,
    weak_crypto: 0,
    sensitive_urls: 0,
    entropy: 0,
    config_audit: 0,
    file_flags: 0,
    ai_comments: 0,
    mcp_config: 0,
    agent_skill: 0,
  }

  // Track progress for frequent updates
  let filesProcessed = 0
  let lastProgressUpdate = 0

  // Process files in parallel batches for better performance on large codebases
  for (let i = 0; i < files.length; i += LAYER1_PARALLEL_BATCH_SIZE) {
    // Check for cancellation before processing batch
    if (cancellationToken?.cancelled) break

    const batch = files.slice(i, i + LAYER1_PARALLEL_BATCH_SIZE)
    const results = await Promise.all(batch.map(file => Promise.resolve(processFileLayer1(file))))

    for (const result of results) {
      vulnerabilities.push(...result.findings)
      // Accumulate stats
      for (const [key, value] of Object.entries(result.stats)) {
        rawStats[key as keyof Layer1StatsRecord] += value
      }
    }

    filesProcessed = Math.min(i + LAYER1_PARALLEL_BATCH_SIZE, files.length)

    // Report progress every PROGRESS_UPDATE_INTERVAL files for better UX
    if (onProgress && (filesProcessed - lastProgressUpdate >= PROGRESS_UPDATE_INTERVAL || filesProcessed === files.length)) {
      onProgress({
        status: 'layer1',
        message: 'Running surface scan (patterns, entropy, config)...',
        filesProcessed,
        totalFiles: files.length,
        vulnerabilitiesFound: vulnerabilities.length,
      })
      lastProgressUpdate = filesProcessed
    }
  }

  // Deduplicate findings (same line might be caught by multiple detectors)
  const dedupedVulnerabilities = deduplicateFindings(vulnerabilities)

  // Apply path exclusions to filter out findings in test/seed/example files
  const { kept: uniqueVulnerabilities, suppressed } = filterFindingsByPath(dedupedVulnerabilities)

  // Track suppressed findings (debug info available in stats)

  // Compute deduped counts per category
  const dedupedStats: Record<string, number> = {}
  for (const vuln of uniqueVulnerabilities) {
    const cat = vuln.category
    dedupedStats[cat] = (dedupedStats[cat] || 0) + 1
  }

  return {
    vulnerabilities: uniqueVulnerabilities,
    filesScanned: files.length,
    duration: Date.now() - startTime,
    stats: {
      raw: rawStats,
      deduped: dedupedStats,
      suppressedByPath: suppressed.length,
    },
  }
}

// Remove duplicate findings on the same line
function deduplicateFindings(vulnerabilities: Vulnerability[]): Vulnerability[] {
  const seen = new Map<string, Vulnerability>()

  for (const vuln of vulnerabilities) {
    const key = `${vuln.filePath}:${vuln.lineNumber}:${vuln.category}`
    const existing = seen.get(key)

    // Keep the higher severity finding
    if (!existing || severityRank(vuln.severity) > severityRank(existing.severity)) {
      seen.set(key, vuln)
    }
  }

  return Array.from(seen.values())
}

// severityRank imported from utils/parsed-file

export { detectHighEntropyStrings } from './entropy'
export { detectKnownPatterns } from './patterns'
export { auditConfiguration } from './config-audit'
export { detectDangerousFiles } from '../config/file-flags'
export { detectAICommentPatterns } from '../config/comments'
export { detectSensitiveURLs } from '../config/urls'
export { detectWeakCrypto } from './weak-crypto'
export { detectMCPConfigIssues } from './config-mcp-audit'
export { detectAgentSkillInjection } from '../config/agent-skill-injection'
