/**
 * Finding Hash Computation
 * Creates stable, reproducible hashes for identifying specific findings
 */

import { createHash } from 'crypto'
import type { Vulnerability } from '../../shared/types'

/**
 * Normalize a file path for hashing
 * - Removes leading ./ or /
 * - Converts backslashes to forward slashes
 * - Lowercases (for case-insensitive matching)
 */
export function normalizePathForHash(filePath: string): string {
  return filePath
    .replace(/^\.\//, '') // Remove leading ./
    .replace(/^\//, '') // Remove leading /
    .replace(/\\/g, '/') // Normalize backslashes
    .toLowerCase()
}

/**
 * Normalize line content for hashing
 * - Trims whitespace
 * - Collapses multiple whitespace to single space
 * - Removes common noise (line numbers, etc.)
 */
export function normalizeContentForHash(content: string): string {
  return content
    .trim()
    .replace(/\s+/g, ' ') // Collapse whitespace
    .replace(/^\d+:\s*/, '') // Remove line number prefix if present
}

/**
 * Compute a stable hash for a vulnerability finding
 *
 * Hash = SHA256(normalizedPath:normalizedContent:category).slice(0,16)
 *
 * This creates a 16-character hex hash that:
 * - Stays stable across whitespace changes
 * - Changes when the actual code changes
 * - Changes when the finding category changes
 * - Is unique enough for practical use
 *
 * @param finding - The vulnerability to hash
 * @returns A 16-character hex hash string
 */
export function computeFindingHash(finding: Vulnerability): string {
  const normalizedPath = normalizePathForHash(finding.filePath)
  const normalizedContent = normalizeContentForHash(finding.lineContent)
  const category = finding.category

  const input = `${normalizedPath}:${normalizedContent}:${category}`
  const hash = createHash('sha256').update(input).digest('hex')

  // Return first 16 characters (64 bits of entropy - sufficient for uniqueness)
  return hash.slice(0, 16)
}

/**
 * Compute hash from raw components (for testing or manual construction)
 */
export function computeHashFromComponents(
  filePath: string,
  lineContent: string,
  category: string
): string {
  const normalizedPath = normalizePathForHash(filePath)
  const normalizedContent = normalizeContentForHash(lineContent)

  const input = `${normalizedPath}:${normalizedContent}:${category}`
  const hash = createHash('sha256').update(input).digest('hex')

  return hash.slice(0, 16)
}

/**
 * Validate a hash format
 * Must be 16 hexadecimal characters
 */
export function isValidHash(hash: string): boolean {
  return /^[0-9a-f]{16}$/i.test(hash)
}

/**
 * Format a hash for display (with truncation indicator)
 */
export function formatHashForDisplay(hash: string): string {
  if (hash.length <= 16) {
    return hash
  }
  return `${hash.slice(0, 12)}...`
}
