/**
 * Shared Context Helpers
 * Centralized utility functions for detecting file and code context
 * Used across Layer 1 and Layer 2 scanners to reduce false positives
 */

// ============================================================================
// File Path Context Detection
// ============================================================================

/**
 * Check if file is in a tooling/scripts directory
 * Files in these directories are typically build tools, CLI utilities, or dev scripts
 * and should have reduced severity for findings like file path patterns
 */
export function isToolingDirectory(filePath: string): boolean {
  return /\/(scripts?|cli|tools?|bin|devtools|build|tasks)\//i.test(filePath)
}

/**
 * Check if file is server-only (not bundled to client)
 * Server-only files can safely use service role keys and other admin secrets
 */
export function isServerOnlyFile(filePath: string): boolean {
  const serverPatterns = [
    /lib\/supabase\/(server|admin|middleware)\.(ts|js)$/i,
    /\/api\//i,                    // Next.js API routes
    /\/server\//i,                 // Server directories
    /\.server\.(ts|js|tsx|jsx)$/i, // .server.ts files
    /\/actions\//i,                // Server actions
    /middleware\.(ts|js)$/i,       // Middleware files
    /\/cron\//i,                   // Cron jobs
    /\/workers?\//i,               // Worker files
    /\/scripts?\//i,               // Scripts
    /\/seed\//i,                   // Database seeds
    /\/migrations?\//i,            // Database migrations
    /\/lib\/[^/]+\/server/i,       // lib/*/server patterns
    /\/utils\/server/i,            // utils/server
    /\/helpers\/server/i,          // helpers/server
    /\.action\.(ts|js)$/i,         // .action.ts files
    /route\.(ts|js)$/i,            // Next.js route handlers
  ]
  return serverPatterns.some(pattern => pattern.test(filePath))
}

/**
 * Check if file is a test, mock, or fixture file
 * These files often contain fake secrets and should have lower severity
 */
export function isTestOrMockFile(filePath: string): boolean {
  const testPatterns = [
    /\.(test|spec)\.(ts|tsx|js|jsx)$/i,
    /\/__tests__\//i,
    /\/test\//i,
    /\/tests\//i,
    /\/testing\//i,                           // testing directories (e.g., docker/testing/)
    /\/mock/i,
    /\/mocks\//i,
    /\/fixtures?\//i,
    /\.mock\.(ts|tsx|js|jsx)$/i,
    /\.stub\.(ts|tsx|js|jsx)$/i,
    /\.(stories|story)\.(ts|tsx|js|jsx)$/i,  // Storybook
    /\/e2e\//i,                               // E2E tests
    /\/cypress\//i,                           // Cypress tests
    /\/playwright\//i,                        // Playwright tests
    /\/vitest\//i,                            // Vitest
    /\/jest\//i,                              // Jest
  ]
  return testPatterns.some(pattern => pattern.test(filePath))
}

/**
 * Check if file is an example/sample/template file
 * These files should be skipped or have significantly reduced severity
 */
export function isExampleFile(filePath: string): boolean {
  return (
    filePath.includes('.example') ||
    filePath.includes('.sample') ||
    filePath.includes('.template') ||
    filePath.includes('README') ||
    filePath.includes('/examples/') ||
    filePath.includes('/example/') ||
    filePath.includes('/demo/') ||
    filePath.includes('/demos/')
  )
}

/**
 * Check if file is in an examples/demo directory
 * Stronger check than isExampleFile - specifically for directories
 * These are typically tutorial/demo code, not production patterns
 */
export function isExampleDirectory(filePath: string): boolean {
  const examplePatterns = [
    /\/examples?\//i,
    /\/demos?\//i,
    /\/templates?\//i,
    /\/samples?\//i,
    /\/tutorials?\//i,
    /\/cookbook\//i,
    /\/quickstart\//i,
    /\/getting-started\//i,
  ]
  return examplePatterns.some(pattern => pattern.test(filePath))
}

/**
 * Check if file is library/framework code (base classes, utilities)
 * Library code is intentionally generic - consumers add security
 * This applies to: langchain, vercel/ai, llamaindex, etc.
 */
export function isLibraryCode(filePath: string): boolean {
  const libraryPatterns = [
    // Package source directories in monorepos
    /\/libs\/[^/]+\/src\//i,
    /\/packages\/[^/]+\/src\//i,
    // Common library patterns
    /\/langchain-/i,
    /\/llamaindex/i,
    // Source files that aren't examples or tests
    /\/src\/(?!.*(?:examples?|demos?|tests?)\/).*\.(ts|js)$/i,
  ]

  // Must match library pattern AND not be example/test
  return (
    libraryPatterns.some(pattern => pattern.test(filePath)) &&
    !isExampleDirectory(filePath) &&
    !isTestOrMockFile(filePath)
  )
}

/**
 * Check if file is a fixture file (test data, mock responses)
 * Fixtures contain fake data and should have reduced severity
 */
export function isFixtureFile(filePath: string): boolean {
  const fixturePatterns = [
    /__fixtures__\//i,
    /\.fixture\./i,
    /fixtures?\//i,
    /testdata\//i,
    /test-data\//i,
    /test_data\//i,
    /mock-data\//i,
    /mockdata\//i,
    /\.mock\./i,
    /\.stub\./i,
  ]
  return fixturePatterns.some(pattern => pattern.test(filePath))
}

/**
 * Check if file is documentation (README, CHANGELOG, etc.)
 * These files should typically be skipped for security scanning
 */
export function isDocumentationFile(filePath: string): boolean {
  const docPatterns = [
    /README/i,
    /CHANGELOG/i,
    /CONTRIBUTING/i,
    /LICENSE/i,
    /\.md$/i,
    /\.mdx$/i,
    /\/docs\//i,
    /\/documentation\//i,
  ]
  return docPatterns.some(pattern => pattern.test(filePath))
}

/**
 * Check if file is a locale/i18n/translation file
 * These files contain natural language translations, not code, and should be skipped entirely
 * They often contain placeholder URLs (http://localhost) and other patterns that trigger false positives
 */
export function isLocaleFile(filePath: string): boolean {
  const lowerPath = filePath.toLowerCase()

  // Directory-based detection
  if (
    lowerPath.includes('/locales/') ||
    lowerPath.includes('/locale/') ||
    lowerPath.includes('/i18n/') ||
    lowerPath.includes('/translations/') ||
    lowerPath.includes('/translation/') ||
    lowerPath.includes('/lang/') ||
    lowerPath.includes('/languages/') ||
    lowerPath.includes('/messages/') ||
    lowerPath.includes('/intl/')
  ) {
    return true
  }

  // File naming patterns (language codes)
  // e.g., en.json, zh-CN.json, pt-BR.json, messages.en.json
  const localeFilePatterns = [
    // Direct language code files: en.json, zh-CN.json, pt-BR.json
    /\/(en|fr|de|es|it|pt|ja|ko|zh|ru|ar|nl|pl|tr|vi|th|id|ms|hi|bn|uk|el|he|fa|sv|no|da|fi|cs|sk|hu|ro|bg|sr|hr|sl|ca|eu|gl|et|lv|lt|mk|sq|is|mt|ga|cy|af|sw|zu|xh|am|ne|si|km|lo|my|ka|hy|az|uz|kk|ky|tg|tk|mn|bo|dz)(-[a-z]{2,4})?\.json$/i,
    // Prefixed language files: messages.en.json, strings.zh-CN.json
    /\/(messages|strings|labels|text|content|copy)\.[a-z]{2}(-[a-z]{2,4})?\.json$/i,
    // Common locale file names
    /\/translation\.json$/i,
    /\/translations\.json$/i,
    /\/messages\.json$/i,
    /\/strings\.json$/i,
  ]

  return localeFilePatterns.some(pattern => pattern.test(lowerPath))
}

/**
 * Check if file is scanner code, fixture, or rule definition
 * Avoid flagging the scanner's own code/test cases
 *
 * Note: Uses (?:^|\/) to match both:
 * - paths with leading segments: packages/scanner/src/...
 * - paths starting with the pattern: scanner/src/...
 */
export function isScannerOrFixtureFile(filePath: string): boolean {
  const scannerPatterns = [
    /(?:^|\/)scanner\//i,
    /(?:^|\/)detector\//i,
    /(?:^|\/)security\//i,
    /(?:^|\/)rules?\//i,
    /(?:^|\/)patterns?\//i,
    /(?:^|\/)fixtures?\//i,
    /(?:^|\/)testdata\//i,
    /(?:^|\/)test-data\//i,
    /(?:^|\/)test_data\//i,
  ]
  return scannerPatterns.some(pattern => pattern.test(filePath))
}

/**
 * Check if file is likely client-bundled (exposed to browser)
 */
export function isClientBundledFile(filePath: string): boolean {
  // Files in these locations are typically client-bundled
  const clientPatterns = [
    /\/components\//i,
    /\/pages\//i,           // Next.js pages (can be SSR, but code visible)
    /\/app\/.*page\.(ts|tsx|js|jsx)$/i,  // Next.js app router pages
    /\/hooks\//i,
    /\/contexts?\//i,
    /\/providers?\//i,
    /\/stores?\//i,         // State management
    /\.client\.(ts|js|tsx|jsx)$/i,  // .client.ts files
  ]

  // But not if they're also server files
  if (isServerOnlyFile(filePath)) {
    return false
  }

  return clientPatterns.some(pattern => pattern.test(filePath))
}

/**
 * Check if file is a seed or data generation file
 * These files generate test/demo data and Math.random() usage is acceptable
 * Used to reduce false positives for Math.random() detection
 */
export function isSeedOrDataGenFile(filePath: string): boolean {
  const patterns = [
    /\/seed\//i,
    /\/seeds\//i,
    /seed-database\.(ts|js)$/i,
    /\/seeder\./i,
    /datacreator\.(ts|js)$/i,
    /\/data\/.*creator/i,
    /\/fixtures\//i,
    /\.fixture\./i,
    /\/generators?\//i,
    /\/factories\//i,
    /factory\.(ts|js)$/i,
  ]
  return patterns.some(p => p.test(filePath))
}

/**
 * Check if file is educational/intentional vulnerability code
 * These files (e.g., OWASP Juice Shop) contain intentional vulnerabilities for training
 * Should be skipped entirely to avoid false positives
 */
export function isEducationalVulnerabilityFile(filePath: string): boolean {
  const patterns = [
    /\/insecurity\.(ts|js)$/i,
    /\/vulnerable\.(ts|js)$/i,
    /\/intentionally-vulnerable/i,
    /\/security-examples?\//i,
    /\/vuln-examples?\//i,
    /\/challenge-\d+/i,  // OWASP Juice Shop challenges
    /\/exploit-examples?\//i,
  ]
  return patterns.some(p => p.test(filePath))
}

/**
 * Check if file is a test configuration file
 * These files (jest.config, vitest.config, etc.) are always dev/test contexts
 * Localhost URLs and similar patterns should not be flagged in these files
 */
export function isTestConfigFile(filePath: string): boolean {
  const testConfigPatterns = [
    /jest\.config\.[jt]s$/i,
    /jest\.config\.mjs$/i,
    /vitest\.config\.[jt]s$/i,
    /vitest\.config\.mts$/i,
    /cypress\.config\.[jt]s$/i,
    /cypress\.config\.mjs$/i,
    /playwright\.config\.[jt]s$/i,
    /playwright\.config\.mts$/i,
    /karma\.conf\.[jt]s$/i,
    /\.mocharc\.[jt]s$/i,
    /\.mocharc\.json$/i,
    /setupTests\.[jt]s$/i,
    /setupTests\.tsx?$/i,
    /test\.setup\.[jt]s$/i,
    /jest\.setup\.[jt]s$/i,
    /vitest\.setup\.[jt]s$/i,
    /testEnvironment\.[jt]s$/i,
    /globalSetup\.[jt]s$/i,
    /globalTeardown\.[jt]s$/i,
    /ava\.config\.[jt]s$/i,
    /nyc\.config\.js$/i,  // Code coverage config
  ]
  return testConfigPatterns.some(pattern => pattern.test(filePath))
}

/**
 * Check if file is a Python file
 */
export function isPythonFile(filePath: string): boolean {
  return /\.py$/i.test(filePath)
}

/**
 * Check if a line is inside a Python docstring
 * Python docstrings are delimited by triple quotes (''' or """)
 * Content inside docstrings (like example URLs, connection strings) should be ignored
 *
 * @param lines - Array of all lines in the file
 * @param lineIndex - The 0-indexed line number to check
 * @returns true if the line is inside a docstring
 */
export function isInsidePythonDocstring(
  lines: string[],
  lineIndex: number
): boolean {
  let inDocstring = false
  let docstringChar: '"""' | "'''" | null = null

  for (let i = 0; i <= lineIndex; i++) {
    const line = lines[i]

    // Count triple quote occurrences in this line
    // We need to track both """ and '''
    const tripleDoubleCount = (line.match(/"""/g) || []).length
    const tripleSingleCount = (line.match(/'''/g) || []).length

    // Process triple double quotes
    for (let j = 0; j < tripleDoubleCount; j++) {
      if (!inDocstring) {
        inDocstring = true
        docstringChar = '"""'
      } else if (docstringChar === '"""') {
        inDocstring = false
        docstringChar = null
      }
    }

    // Process triple single quotes
    for (let j = 0; j < tripleSingleCount; j++) {
      if (!inDocstring) {
        inDocstring = true
        docstringChar = "'''"
      } else if (docstringChar === "'''") {
        inDocstring = false
        docstringChar = null
      }
    }
  }

  return inDocstring
}

// ============================================================================
// Desktop/Electron App Context Detection
// ============================================================================

/**
 * Check if file is in a desktop app context (Electron, Tauri, etc.)
 * Desktop apps legitimately access filesystem and spawn processes,
 * so findings in these contexts should have reduced severity.
 *
 * Used by:
 * - Dynamic file path detection (downgrade to INFO)
 * - child_process detection (downgrade to MEDIUM)
 */
export function isDesktopAppContext(filePath: string): boolean {
  const desktopPatterns = [
    // Directory patterns
    /\/apps\/desktop\//i,
    /\/electron\//i,
    /\/tauri\//i,
    /\/src-electron\//i,
    /\/src-tauri\//i,
    /\/desktop-app\//i,
    /\/desktop\//i,

    // File patterns (Electron conventions)
    /\/main\.(ts|js)$/i, // Main process
    /\/preload\.(ts|js)$/i, // Preload scripts
    /\/ipc[A-Z]\w*\.(ts|js)$/i, // IPC handlers
    /Ctr\.(ts|js)$/i, // Controller pattern

    // Package patterns
    /packages\/.*electron/i,
    /packages\/.*desktop/i,
  ]
  return desktopPatterns.some(p => p.test(filePath))
}

/**
 * Check if file is an MCP (Model Context Protocol) server
 * MCP servers legitimately spawn processes to provide tool capabilities
 */
export function isMcpServerContext(filePath: string): boolean {
  const mcpPatterns = [
    /mcp/i,
    /model-context-protocol/i,
    /\/servers?\//i, // Common MCP server directory structure
  ]
  return mcpPatterns.some(p => p.test(filePath))
}

/**
 * Check if file is a file loader/processor
 * File loaders legitimately access filesystem to process files
 */
export function isFileLoaderContext(filePath: string): boolean {
  const loaderPatterns = [
    /file-loaders?\//i,
    /loaders?\/(pdf|docx|excel|text|csv|xml|json)/i,
    /document-loaders?\//i,
    /parsers?\//i,
  ]
  return loaderPatterns.some(p => p.test(filePath))
}

// ============================================================================
// Agent Skill File Detection
// ============================================================================

/**
 * Check if file is an AI agent skill/configuration file
 * These files define agent behavior and are targets for prompt injection,
 * data exfiltration, and hidden execution attacks.
 *
 * Note: Root CLAUDE.md is NOT matched. Only .claude/commands/, .claude/skills/,
 * .claude/tools/ subdirectories are flagged.
 */
export function isAgentSkillFile(filePath: string): boolean {
  const skillPatterns = [
    // Skill definition files
    /\/SKILL\.md$/i,
    /\/AGENTS\.md$/i,
    /\/skills\.json$/i,
    /\/skills\.ya?ml$/i,
    /\/agent\.ya?ml$/i,
    /\/agent\.config\./i,
    /\/agent-skills\//i,
    /\/tools\.json$/i,

    // Cursor
    /\/\.cursor\/rules\//i,
    /\/\.cursorrules$/i,

    // Claude (skill-specific paths, NOT root CLAUDE.md)
    /\/\.claude\/commands\//i,
    /\/\.claude\/skills\//i,
    /\/\.claude\/tools\//i,

    // GitHub Copilot
    /\/\.github\/copilot-instructions\.md$/i,
    /\/\.github\/agents\//i,

    // Moltbot/OpenClaw
    /\/\.moltbot\//i,
    /\/moltbot\.config\./i,
    /\/\.openclaw\//i,

    // Aider
    /\/\.aider/i,

    // MCP configs (complements existing config-mcp-audit.ts)
    /\/mcp\.json$/i,
    /\/mcp-config\.json$/i,
    /\/\.mcp\//i,
    /\/claude[-_]desktop[-_]config\.json$/i,
  ]
  return skillPatterns.some(p => p.test(filePath))
}

// ============================================================================
// Code Line Context Detection
// ============================================================================

/**
 * Check if line uses environment variable reference (not hardcoded)
 */
export function isEnvVarReference(line: string): boolean {
  return (
    /process\.env\.[A-Z_]+/.test(line) ||
    /\$\{?[A-Z_]+\}?/.test(line) ||
    /import\.meta\.env\.[A-Z_]+/.test(line) ||
    /Deno\.env\.get\(/.test(line) ||
    /os\.environ\[/.test(line) ||      // Python
    /os\.getenv\(/.test(line) ||       // Python
    /ENV\[['"]/.test(line) ||          // Ruby
    /env\(["']/.test(line)             // Laravel PHP
  )
}

/**
 * Check if line uses NEXT_PUBLIC_ prefix (client-exposed)
 */
export function isNextPublicEnvVar(line: string): boolean {
  return /NEXT_PUBLIC_[A-Z_]+/.test(line)
}

/**
 * Check if line is a comment (single-line check)
 */
export function isComment(lineContent: string): boolean {
  const trimmed = lineContent.trim()
  return (
    trimmed.startsWith('//') ||
    trimmed.startsWith('#') ||
    trimmed.startsWith('*') ||
    trimmed.startsWith('/*') ||
    trimmed.startsWith('"""') ||
    trimmed.startsWith("'''") ||
    trimmed.startsWith('<!--')
  )
}

/**
 * Check if a line is inside a multi-line comment block
 * Used to properly skip code that's been commented out
 *
 * @param lines - Array of all lines in the file
 * @param lineIndex - The 0-indexed line number to check
 * @returns true if the line is inside a multi-line comment
 */
export function isInsideMultiLineComment(
  lines: string[],
  lineIndex: number
): boolean {
  let inComment = false

  for (let i = 0; i <= lineIndex; i++) {
    const line = lines[i]

    // Check for comment start/end in this line
    // Handle multiple occurrences in same line
    let searchStart = 0
    while (searchStart < line.length) {
      const openIdx = line.indexOf('/*', searchStart)
      const closeIdx = line.indexOf('*/', searchStart)

      if (!inComment) {
        // Not in comment - look for opening
        if (openIdx !== -1 && (closeIdx === -1 || openIdx < closeIdx)) {
          inComment = true
          searchStart = openIdx + 2
          continue
        }
      } else {
        // In comment - look for closing
        if (closeIdx !== -1 && (openIdx === -1 || closeIdx < openIdx)) {
          inComment = false
          searchStart = closeIdx + 2
          continue
        }
      }
      break
    }
  }

  return inComment
}

/**
 * Check if a line is commented out code (either single-line or multi-line comment)
 * Combines single-line and multi-line comment detection
 *
 * @param lines - Array of all lines in the file
 * @param lineIndex - The 0-indexed line number to check
 * @returns true if the line is commented out
 */
export function isCommentedOutCode(
  lines: string[],
  lineIndex: number
): boolean {
  const line = lines[lineIndex]
  if (!line) return false

  // Check single-line comment
  if (isComment(line)) {
    return true
  }

  // Check if inside multi-line comment block
  if (isInsideMultiLineComment(lines, lineIndex)) {
    return true
  }

  return false
}

/**
 * Check if a line has a linter/security ignore comment
 * These comments indicate the developer has acknowledged and accepted the risk
 *
 * @param lines - Array of all lines in the file
 * @param lineIndex - The 0-indexed line number to check
 * @returns object with hasIgnore flag and the ignore type if found
 */
export function hasLinterIgnoreComment(
  lines: string[],
  lineIndex: number
): { hasIgnore: boolean; ignoreType?: string } {
  // Check current line and previous line for ignore comments
  const linesToCheck = [
    lines[lineIndex],
    lineIndex > 0 ? lines[lineIndex - 1] : '',
  ]

  const ignorePatterns = [
    // ESLint
    { pattern: /eslint-disable-next-line/i, type: 'eslint' },
    { pattern: /eslint-disable-line/i, type: 'eslint' },
    { pattern: /eslint-disable\s/i, type: 'eslint' },

    // Biome
    { pattern: /biome-ignore/i, type: 'biome' },

    // TypeScript
    { pattern: /@ts-ignore/i, type: 'typescript' },
    { pattern: /@ts-expect-error/i, type: 'typescript' },
    { pattern: /@ts-nocheck/i, type: 'typescript' },

    // Security scanners
    { pattern: /nosec/i, type: 'security' },
    { pattern: /nolint/i, type: 'security' },
    { pattern: /# noqa/i, type: 'security' },  // Python
    { pattern: /# type:\s*ignore/i, type: 'mypy' },
    { pattern: /NOSONAR/i, type: 'sonar' },
    { pattern: /SuppressWarnings/i, type: 'java' },
    { pattern: /pragma:\s*no cover/i, type: 'coverage' },

    // Prettier
    { pattern: /prettier-ignore/i, type: 'prettier' },

    // Stylelint
    { pattern: /stylelint-disable/i, type: 'stylelint' },
  ]

  for (const line of linesToCheck) {
    if (!line) continue
    for (const { pattern, type } of ignorePatterns) {
      if (pattern.test(line)) {
        return { hasIgnore: true, ignoreType: type }
      }
    }
  }

  return { hasIgnore: false }
}

/**
 * Check if value/line appears to be a placeholder
 */
export function isPlaceholderValue(value: string, line: string): boolean {
  const placeholderPatterns = [
    /xxx/i,
    /your[-_]?/i,
    /YOUR[-_]?/i,
    /placeholder/i,
    /example/i,
    /REPLACE[-_]?/i,
    /CHANGEME/i,
    /<[a-z_-]+>/i,           // <your-api-key>
    /\[\s*[a-z_-]+\s*\]/i,   // [API_KEY]
    /todo/i,
    /fixme/i,
  ]

  // Common test passwords that appear in connection strings
  // e.g., postgres://user:password@host:5432/db
  const testPasswordPatterns = [
    /:password@/i,           // user:password@ in connection strings
    /:secret@/i,             // user:secret@
    /:test@/i,               // user:test@
    /:admin@/i,              // user:admin@
    /:root@/i,               // user:root@
    /:123456@/i,             // user:123456@
    /:postgres@/i,           // postgres:postgres@
    /:mysql@/i,              // mysql:mysql@
    /:redis@/i,              // redis:redis@
  ]

  return placeholderPatterns.some(pattern =>
    pattern.test(value) || pattern.test(line)
  ) || testPasswordPatterns.some(pattern => pattern.test(value))
}

// ============================================================================
// Security Context Detection
// ============================================================================

/**
 * Check if line/path indicates a public endpoint (health, webhook, cron)
 * These don't need authentication
 */
export function isPublicEndpoint(lineContent: string, filePath: string): boolean {
  // Health check patterns
  const healthCheckPatterns = [
    /\/health\/?["'`]?/i,
    /\/healthz\/?["'`]?/i,
    /\/ready\/?["'`]?/i,
    /\/readyz\/?["'`]?/i,
    /\/live\/?["'`]?/i,
    /\/livez\/?["'`]?/i,
    /\/ping\/?["'`]?/i,
    /\/status\/?["'`]?/i,
    /\/api\/health/i,
    /\/api\/status/i,
    /\/_health/i,
  ]

  // Webhook patterns
  const webhookPatterns = [
    /\/webhook/i,
    /\/webhooks\//i,
    /\/callback/i,
    /\/stripe\/webhook/i,
    /\/github\/webhook/i,
    /\/clerk\/webhook/i,
  ]

  // Cron/scheduled job patterns
  const cronPatterns = [
    /\/cron\//i,
    /\/scheduled\//i,
    /\/tasks?\//i,
    /\/jobs?\//i,
  ]

  // Check line content
  const allPatterns = [...healthCheckPatterns, ...webhookPatterns, ...cronPatterns]
  if (allPatterns.some(pattern => pattern.test(lineContent))) {
    return true
  }

  // Check file path
  if (filePath.includes('/health') ||
      filePath.includes('/webhook') ||
      filePath.includes('/cron') ||
      filePath.includes('/scheduled')) {
    return true
  }

  return false
}

/**
 * Check if webhook has signature verification nearby
 */
export function hasWebhookSignatureVerification(lines: string[], lineIndex: number, windowSize: number = 15): boolean {
  const signaturePatterns = [
    /verifySignature/i,
    /validateSignature/i,
    /checkSignature/i,
    /signature.*verify/i,
    /verify.*signature/i,
    /hmac/i,
    /x-hub-signature/i,
    /stripe-signature/i,
    /svix-signature/i,
    /webhook.*secret/i,
    /constructEvent/i,      // Stripe webhook verification
    /Webhook\.verify/i,     // Generic webhook verify
  ]

  const start = Math.max(0, lineIndex - windowSize)
  const end = Math.min(lines.length, lineIndex + windowSize)

  for (let i = start; i < end; i++) {
    if (signaturePatterns.some(pattern => pattern.test(lines[i]))) {
      return true
    }
  }

  return false
}

/**
 * Check if there's an auth check nearby (bidirectional search)
 */
export function hasAuthCheckNearby(lines: string[], lineIndex: number, windowSize: number = 20): boolean {
  const authPatterns = [
    /authorization/i,
    /bearer\s+token/i,
    /req\.user/i,
    /request\.user/i,
    /\.user\s*[=!]/,
    /isAuthenticated/i,
    /requireAuth/i,
    /ensureAuth/i,
    /checkAuth/i,
    /verifyToken/i,
    /validateToken/i,
    /checkPermission/i,
    /getServerSession/i,
    /middleware.*auth/i,
    /session\.user/i,
    /currentUser/i,
    /getSession\(/i,
    /useSession\(/i,
    /auth\(\)/i,             // Next-Auth auth()
    /withAuth/i,
    /protected/i,
    /verifySignature/i,      // Webhook signature
    /checkApiKey/i,
    /validateApiKey/i,
    /requireRole/i,
    /hasRole/i,
    /isAdmin/i,
  ]

  // Search bidirectionally
  const start = Math.max(0, lineIndex - windowSize)
  const end = Math.min(lines.length, lineIndex + windowSize)

  for (let i = start; i < end; i++) {
    if (authPatterns.some(pattern => pattern.test(lines[i]))) {
      return true
    }
  }

  return false
}

// ============================================================================
// BYOK (Bring Your Own Key) Context Detection
// ============================================================================

/**
 * Check if this appears to be a BYOK (user-provided key) context
 * BYOK is a feature, not a vulnerability, unless improperly handled
 */
export function isBYOKContext(lineContent: string, filePath: string): boolean {
  // Common BYOK patterns
  const byokPatterns = [
    /user.*api.*key/i,
    /customer.*key/i,
    /your.*api.*key/i,
    /provide.*key/i,
    /enter.*key/i,
    /input.*key/i,
    /form.*key/i,
    /settings.*key/i,
    /config.*key.*user/i,
    /BYOK/i,
    /bring.*your.*own/i,
  ]

  // Form/input contexts
  const inputPatterns = [
    /input.*type/i,
    /onChange/i,
    /onSubmit/i,
    /handleSubmit/i,
    /useState.*key/i,
    /form.*data/i,
  ]

  // Settings/config UI patterns
  const settingsPatterns = [
    /\/settings\//i,
    /\/config\//i,
    /\/preferences\//i,
    /\/profile\//i,
  ]

  // Check line content
  if (byokPatterns.some(p => p.test(lineContent)) ||
      inputPatterns.some(p => p.test(lineContent))) {
    return true
  }

  // Check file path
  if (settingsPatterns.some(p => p.test(filePath))) {
    // In settings files, look for user input context
    if (inputPatterns.some(p => p.test(lineContent))) {
      return true
    }
  }

  return false
}

/**
 * Check if key is being stored/handled properly (not exposed)
 */
export function isKeyProperlyHandled(lineContent: string, lines: string[], lineIndex: number): boolean {
  // Proper handling patterns (encryption, secure storage, etc.)
  const properHandlingPatterns = [
    /encrypt/i,
    /hash/i,
    /secure.*storage/i,
    /keychain/i,
    /vault/i,
    /secretsManager/i,
    /kms/i,
    /\.env/i,
  ]

  // Check current line
  if (properHandlingPatterns.some(p => p.test(lineContent))) {
    return true
  }

  // Check nearby lines (5 lines before and after)
  const start = Math.max(0, lineIndex - 5)
  const end = Math.min(lines.length, lineIndex + 5)

  for (let i = start; i < end; i++) {
    if (properHandlingPatterns.some(p => p.test(lines[i]))) {
      return true
    }
  }

  return false
}

// ============================================================================
// Service Role Key Context
// ============================================================================

/**
 * Check if this is a service role key usage that's acceptable
 * Server-only + env var = acceptable
 * Client exposure = critical
 */
export function getServiceRoleKeyContext(
  lineContent: string,
  filePath: string
): 'safe_server' | 'needs_review' | 'client_exposure' {
  const isServer = isServerOnlyFile(filePath)
  const usesEnvVar = isEnvVarReference(lineContent)
  const isClientFile = isClientBundledFile(filePath)
  const isNextPublic = isNextPublicEnvVar(lineContent)

  // NEXT_PUBLIC_ service role key = always critical (client exposure)
  if (isNextPublic) {
    return 'client_exposure'
  }

  // Server-only file using env var = safe
  if (isServer && usesEnvVar) {
    return 'safe_server'
  }

  // Client-bundled file = exposure risk
  if (isClientFile) {
    return 'client_exposure'
  }

  // Hardcoded or ambiguous = needs review
  return 'needs_review'
}

// ============================================================================
// File Context for Layer 2 Detectors (Phase 2b)
// ============================================================================

/**
 * File-specific context for Layer 2 detectors
 * Provides per-file classification for context-aware detection
 */
export interface FileContext {
  /** Whether this file is server-only (not bundled to client) */
  isServerOnly: boolean
  /** Whether this file is client-bundled (exposed to browser) */
  isClientBundled: boolean
  /** Whether this file is a test/mock/fixture file */
  isTestFile: boolean
  /** Whether this file is a config file */
  isConfigFile: boolean
  /** Whether this file is in a tooling directory */
  isToolingDir: boolean
}

/**
 * Check if file is a configuration file
 */
export function isConfigFile(filePath: string): boolean {
  const configPatterns = [
    /config\.(ts|js|json|yaml|yml)$/i,
    /settings\.(ts|js|json)$/i,
    /constants\.(ts|js)$/i,
    /\.config\.(ts|js|mjs|cjs)$/i,
    /\.env/i,
    /tsconfig\.json$/i,
    /package\.json$/i,
    /jest\.config/i,
    /vitest\.config/i,
    /eslint/i,
    /prettier/i,
  ]
  return configPatterns.some(p => p.test(filePath))
}

/**
 * Build file-specific context for a single file
 * Used by Layer 2 detectors for context-aware detection
 */
export function buildFileContext(filePath: string): FileContext {
  return {
    isServerOnly: isServerOnlyFile(filePath),
    isClientBundled: isClientBundledFile(filePath),
    isTestFile: isTestOrMockFile(filePath),
    isConfigFile: isConfigFile(filePath),
    isToolingDir: isToolingDirectory(filePath),
  }
}
