/**
 * Detector Tier System
 *
 * Provides a shared language for "how much we trust this detector" so we can:
 * - Filter findings in runScan by tier + depth
 * - Log tier breakdowns for tuning
 * - Route AI validation budget toward Tier B
 *
 * Security reasoning:
 * - Makes it explicit which detectors are safe to expose in cheap scans
 * - Avoids "accidental promotion" of an experimental heuristic to production output
 */

import type { VulnerabilityCategory } from './shared/types'

/**
 * Detector tiers control visibility and trust level:
 *
 * - core: High-precision SAST + core AI-safety detectors. Visible in all scan depths.
 * - ai_assisted: Context-heavy heuristics that need AI validation. Shown in validated/deep.
 * - experimental: High-noise signals used only for internal scoring/AI hints. Hidden from users.
 */
export type DetectorTier = 'core' | 'ai_assisted' | 'experimental'

/**
 * Tier statistics for logging and analysis
 */
export interface TierStats {
  core: number
  ai_assisted: number
  experimental: number
}

// ============================================================================
// Layer 1 Detector Tier Mappings
// ============================================================================

/**
 * Layer 1 detector names (internal identifiers matching detector function names)
 */
export type Layer1DetectorName =
  | 'known_secrets'      // patterns.ts - Known secret patterns (API keys, tokens)
  | 'weak_crypto'        // weak-crypto.ts - Weak hash/cipher usage
  | 'sensitive_urls'     // urls.ts - Webhook URLs, URLs with tokens, internal endpoints
  | 'entropy'            // entropy.ts - High-entropy string detection
  | 'config_audit'       // config-audit.ts - Risky .env/config and debug flags
  | 'file_flags'         // file-flags.ts - Dangerous file patterns
  | 'ai_comments'        // comments.ts - AI comment patterns ("Generated by...")

/**
 * Layer 1 tier assignments
 *
 * Tier A (core):
 *   - known_secrets: Hardcoded secrets are objectively bad and high-impact
 *   - weak_crypto: Weak crypto is a classic SAST finding with clear remediation
 *   - sensitive_urls: Hardcoded webhook URLs + tokens are real data exfil vectors
 *
 * Tier B (ai_assisted):
 *   - entropy: Great at finding candidates, needs AI to separate real secrets from noise
 *   - config_audit: Depends on project norms; better reviewed with AI + project context
 *   - file_flags: Subjective items should be AI-triaged (except committed .env = Tier A)
 *
 * Tier C (experimental):
 *   - ai_comments: Not directly a vuln; belongs in separate "AI hygiene" report
 */
export const LAYER1_DETECTOR_TIERS: Record<Layer1DetectorName, DetectorTier> = {
  known_secrets: 'core',
  weak_crypto: 'core',
  sensitive_urls: 'core',
  entropy: 'ai_assisted',
  config_audit: 'ai_assisted',
  file_flags: 'ai_assisted',  // Mixed: committed .env is effectively core
  ai_comments: 'experimental',
}

/**
 * Mapping from vulnerability category to Layer 1 detector name
 * Used for tier lookups when we only have the category
 */
export const LAYER1_CATEGORY_TO_DETECTOR: Partial<Record<VulnerabilityCategory, Layer1DetectorName>> = {
  hardcoded_secret: 'known_secrets',
  weak_crypto: 'weak_crypto',
  sensitive_url: 'sensitive_urls',
  high_entropy_string: 'entropy',
  insecure_config: 'config_audit',
  root_container: 'config_audit',
  dangerous_file: 'file_flags',
  ai_pattern: 'ai_comments',  // AI comment patterns detected in Layer 1
}

// ============================================================================
// Layer 2 Detector Tier Mappings
// ============================================================================

/**
 * Layer 2 detector names (internal identifiers matching detector function names)
 */
export type Layer2DetectorName =
  | 'dangerous_functions'  // dangerous-functions.ts
  | 'byok_patterns'        // byok-patterns.ts
  | 'ai_execution_sinks'   // ai-execution-sinks.ts
  | 'ai_agent_tools'       // ai-agent-tools.ts
  | 'auth_antipatterns'    // auth-antipatterns.ts
  | 'data_exposure'        // data-exposure.ts
  | 'ai_fingerprinting'    // ai-fingerprinting.ts
  | 'ai_prompt_hygiene'    // ai-prompt-hygiene.ts
  | 'logic_gates'          // logic-gates.ts
  | 'variables'            // variables.ts
  | 'risky_imports'        // risky-imports.ts
  | 'framework_checks'     // framework-checks.ts
  // M5: New AI-era detectors
  | 'ai_rag_safety'        // ai-rag-safety.ts - RAG data exfiltration
  | 'ai_endpoint_protection' // ai-endpoint-protection.ts - Unprotected AI endpoints
  | 'ai_schema_validation' // ai-schema-validation.ts - Schema mismatch
  // AI Detection Roadmap Phase 1
  | 'ai_package_hallucination' // ai-package-hallucination.ts - Hallucinated packages
  | 'ai_mcp_security'          // ai-mcp-security.ts - MCP tool security
  // AI Detection Roadmap Phase 2
  | 'model_supply_chain'       // model-supply-chain.ts - Model loading/finetuning risks
  // OWASP Workstream 1
  | 'security_headers'         // security-headers.ts - Missing HTTP security headers
  | 'ssrf_detection'           // ssrf-detection.ts - Server-Side Request Forgery
  | 'log_injection'            // log-injection.ts - Log injection / forging
  | 'xxe_detection'            // xxe-detection.ts - XML External Entity injection

/**
 * Layer 2 tier assignments
 *
 * Tier A (core) - High-precision, high-risk, clear remediation:
 *   - dangerous_functions: Classic injection footholds (eval, exec, unsafe SQL)
 *   - byok_patterns: Storing/logging BYOK is critical AI-era customer trust risk
 *   - ai_execution_sinks: Core to Oculum's AI story; LLM output as code/commands
 *   - ai_agent_tools: Over-permissive tools are central AI alignment problem
 *
 * Tier B (ai_assisted) - Context-heavy, need AI validation:
 *   - auth_antipatterns: Very context-dependent; needs middleware awareness
 *   - data_exposure: Logging queries/user IDs is often acceptable but context-specific
 *   - ai_fingerprinting: TypeScript 'any' at trust boundaries is risk indicator, not vuln
 *   - ai_prompt_hygiene: Needs semantic understanding of prompt design
 *
 * Tier C (experimental) - High-noise, internal use only:
 *   - logic_gates: Many hits with limited actionable signal
 *   - variables: Generic token/password variable names - too generic
 *   - risky_imports: Most imports are fine; keep tiny whitelist if proved valuable
 *   - framework_checks: Many findings are style/low-risk; prone to noisy lint
 */
export const LAYER2_DETECTOR_TIERS: Record<Layer2DetectorName, DetectorTier> = {
  // Tier A - Core SAST / AI-safety
  dangerous_functions: 'core',
  byok_patterns: 'core',
  ai_execution_sinks: 'core',
  ai_agent_tools: 'core',

  // Tier B - AI-assisted heuristics
  auth_antipatterns: 'ai_assisted',
  data_exposure: 'ai_assisted',
  ai_fingerprinting: 'ai_assisted',
  ai_prompt_hygiene: 'ai_assisted',

  // Tier C - Experimental / high-noise
  logic_gates: 'experimental',
  variables: 'experimental',
  risky_imports: 'experimental',
  framework_checks: 'experimental',

  // M5: New AI-era detectors
  ai_rag_safety: 'core',           // Tier A - Cross-tenant data access is critical
  ai_endpoint_protection: 'core',  // Tier A - Cost abuse / API exposure has clear signals
  ai_schema_validation: 'ai_assisted', // Tier B - Context-dependent, benefits from AI validation

  // AI Detection Roadmap Phase 1
  ai_package_hallucination: 'core',  // Tier A - Supply chain attacks are critical
  ai_mcp_security: 'core',           // Tier A - MCP tool security is critical for AI agents
  // AI Detection Roadmap Phase 2
  model_supply_chain: 'core',        // Tier A - Model supply chain risks are critical (RCE)

  // OWASP Workstream 1
  security_headers: 'ai_assisted',    // Tier B - Context-dependent (CDN/proxy may add headers)
  ssrf_detection: 'core',             // Tier A - SSRF is high-impact with clear signals
  log_injection: 'ai_assisted',       // Tier B - Context-dependent (structured logging may be fine)
  xxe_detection: 'core',              // Tier A - XXE is high-impact with clear signals
}

/**
 * Mapping from vulnerability category to Layer 2 detector name
 * Used for tier lookups when we only have the category
 *
 * NOTE: Some categories are used by multiple detectors:
 * - ai_pattern: used by ai-fingerprinting (Tier B), byok-patterns (Tier A), dangerous-functions (Tier A)
 * - insecure_config: used by config-audit (L1 Tier B), framework-checks (L2 Tier C)
 *
 * For ambiguous categories, we use the most conservative (highest trust) tier mapping.
 * When category alone isn't sufficient, the orchestrator can use detector-specific tracking.
 */
export const LAYER2_CATEGORY_TO_DETECTOR: Partial<Record<VulnerabilityCategory, Layer2DetectorName>> = {
  // Tier A categories (unambiguous)
  dangerous_function: 'dangerous_functions',
  sql_injection: 'dangerous_functions',
  command_injection: 'dangerous_functions',
  ai_unsafe_execution: 'ai_execution_sinks',
  ai_overpermissive_tool: 'ai_agent_tools',

  // Tier B categories
  missing_auth: 'auth_antipatterns',
  data_exposure: 'data_exposure',
  ai_prompt_injection: 'ai_prompt_hygiene',

  // ai_pattern is ambiguous - used by multiple detectors with different tiers:
  // - ai-fingerprinting (Tier B): TypeScript 'any' at boundaries
  // - byok-patterns (Tier A): BYOK key handling
  // - dangerous-functions (Tier A): JSON.parse related AI patterns
  // Default to ai_fingerprinting (Tier B) since it's most common; byok/dangerous_functions
  // findings are usually categorized differently or handled explicitly
  ai_pattern: 'ai_fingerprinting',

  // Tier C categories
  security_bypass: 'logic_gates',
  sensitive_variable: 'variables',
  suspicious_package: 'risky_imports',
  cors_misconfiguration: 'framework_checks',
  // insecure_config from framework-checks is Tier C in Layer 2
  // (but same category from config-audit is Tier B in Layer 1 - handled by layer check)
  insecure_config: 'framework_checks',

  // M5: New AI-era categories
  ai_rag_exfiltration: 'ai_rag_safety',
  ai_endpoint_unprotected: 'ai_endpoint_protection',
  ai_schema_mismatch: 'ai_schema_validation',

  // AI Detection Roadmap Phase 1 categories
  ai_package_hallucination: 'ai_package_hallucination',
  ai_rag_corpus_poisoning: 'ai_rag_safety',    // Extended RAG detector
  ai_rag_pii_leakage: 'ai_rag_safety',         // Extended RAG detector
  ai_mcp_tool_poisoning: 'ai_mcp_security',
  ai_mcp_credential_issue: 'ai_mcp_security',
  ai_mcp_confused_deputy: 'ai_mcp_security',

  // Phase 1 Enhancement Backlog categories
  ai_mcp_description_injection: 'ai_mcp_security',
  ai_mcp_server_shadowing: 'ai_mcp_security',
  ai_mcp_config_secrets: 'ai_mcp_security',      // Note: Layer 1 detector, but core tier
  ai_mcp_config_permissions: 'ai_mcp_security',  // Note: Layer 1 detector
  ai_rag_query_injection: 'ai_rag_safety',
  ai_rag_embedding_poisoning: 'ai_rag_safety',
  ai_rag_chunk_injection: 'ai_rag_safety',
  ai_package_typosquat: 'ai_package_hallucination',
  ai_package_malicious: 'ai_package_hallucination',

  // AI Detection Roadmap Phase 2 categories
  ai_unsafe_model_load: 'model_supply_chain',
  ai_unverified_model: 'model_supply_chain',
  ai_unsafe_finetuning: 'model_supply_chain',
  ai_excessive_agency: 'ai_agent_tools',  // Extended in ai-agent-tools.ts

  // OWASP Workstream 1 categories
  missing_security_headers: 'security_headers',
  ssrf: 'ssrf_detection',
  log_injection: 'log_injection',
  xxe: 'xxe_detection',
}

// ============================================================================
// Tier Lookup Helpers
// ============================================================================

/**
 * Get the tier for a vulnerability based on its category and layer
 */
export function getTierForCategory(
  category: VulnerabilityCategory,
  layer: 1 | 2 | 3
): DetectorTier {
  if (layer === 1) {
    const detector = LAYER1_CATEGORY_TO_DETECTOR[category]
    if (detector) {
      return LAYER1_DETECTOR_TIERS[detector]
    }
  } else if (layer === 2) {
    const detector = LAYER2_CATEGORY_TO_DETECTOR[category]
    if (detector) {
      return LAYER2_DETECTOR_TIERS[detector]
    }
  }

  // Layer 3 findings are always core (AI semantic analysis)
  if (layer === 3) {
    return 'core'
  }

  // Default to ai_assisted if unmapped (safe default - will go through AI validation)
  return 'ai_assisted'
}

/**
 * Get tier for a Layer 1 detector by name
 */
export function getLayer1DetectorTier(detector: Layer1DetectorName): DetectorTier {
  return LAYER1_DETECTOR_TIERS[detector]
}

/**
 * Get tier for a Layer 2 detector by name
 */
export function getLayer2DetectorTier(detector: Layer2DetectorName): DetectorTier {
  return LAYER2_DETECTOR_TIERS[detector]
}

/**
 * Check if a tier should be visible at a given scan depth
 */
export function isTierVisibleAtDepth(
  tier: DetectorTier,
  depth: 'local' | 'verified' | 'deep'
): boolean {
  switch (depth) {
    case 'local':
      // Only Tier A (core) findings are visible in local scans
      return tier === 'core'
    case 'verified':
      // Tier A always visible, Tier B visible after AI validation
      return tier === 'core' || tier === 'ai_assisted'
    case 'deep':
      // Same as verified for visibility (deep adds Layer 3, not more tiers)
      return tier === 'core' || tier === 'ai_assisted'
  }
}

/**
 * Check if a tier should go through AI validation at a given scan depth
 */
export function shouldValidateWithAI(
  tier: DetectorTier,
  depth: 'local' | 'verified' | 'deep'
): boolean {
  // Local scans skip AI validation entirely
  if (depth === 'local') {
    return false
  }

  // In verified/deep, Tier B findings should go through AI validation
  // Tier A is high-precision and doesn't need AI validation
  // Tier C is hidden anyway
  return tier === 'ai_assisted'
}

/**
 * Compute tier statistics from an array of vulnerabilities
 */
export function computeTierStats(
  vulnerabilities: Array<{ category: VulnerabilityCategory; layer: 1 | 2 | 3 }>
): TierStats {
  const stats: TierStats = {
    core: 0,
    ai_assisted: 0,
    experimental: 0,
  }

  for (const vuln of vulnerabilities) {
    const tier = getTierForCategory(vuln.category, vuln.layer)
    stats[tier]++
  }

  return stats
}

/**
 * Format tier stats for logging
 */
export function formatTierStats(stats: TierStats): string {
  return `tiers={core:${stats.core},ai_assisted:${stats.ai_assisted},experimental:${stats.experimental}}`
}
