import { bytesToHex } from '@/lib/encoding.js';

/**
 * normalize.ts — text normalization + SHA-256 hashing for Translation Memory keys.
 *
 * Runs in Cloudflare Workers: uses Web Crypto API (crypto.subtle), never node:crypto.
 */

/**
 * Unicode characters to strip before hashing:
 *   U+FEFF  BOM / zero-width no-break space
 *   U+200E  LEFT-TO-RIGHT MARK
 *   U+200F  RIGHT-TO-LEFT MARK
 *   U+202A  LEFT-TO-RIGHT EMBEDDING
 *   U+202B  RIGHT-TO-LEFT EMBEDDING
 *   U+202C  POP DIRECTIONAL FORMATTING
 *   U+202D  LEFT-TO-RIGHT OVERRIDE
 *   U+202E  RIGHT-TO-LEFT OVERRIDE
 *   U+2066  LEFT-TO-RIGHT ISOLATE
 *   U+2067  RIGHT-TO-LEFT ISOLATE
 *   U+2068  FIRST STRONG ISOLATE
 *   U+2069  POP DIRECTIONAL ISOLATE
 *
 * Uses \u{XXXX} unicode escapes in a /u regex to avoid literal invisible chars in source.
 */
const STRIP_RE = /[\u{FEFF}\u{200E}\u{200F}\u{202A}-\u{202E}\u{2066}-\u{2069}]/gu;

/**
 * Normalize `text` for use as a Translation Memory cache key.
 *
 * Steps (order matters):
 *   1. Strip BOM + Unicode bidi marks.
 *   2. Collapse all whitespace runs (space / tab / newline / etc.) to a single space.
 *   3. Trim leading/trailing whitespace.
 *   4. Lowercase — preserves Hebrew (no-op for RTL scripts) while folding Latin.
 *
 * Proper-noun preservation note: lowercasing is intentional for hashing purposes.
 * The stored source text is never lowercased — only the hash key is derived from
 * the lowercase form so that "Hello" and "hello" share a TM entry.
 */
export function normalizeForHash(text: string): string {
  return text.replace(STRIP_RE, '').replace(/\s+/g, ' ').trim().toLowerCase();
}

/**
 * `normalize` — locale-aware alias for `normalizeForHash`.
 *
 * The `locale` parameter is accepted for API symmetry with `hashUnit` but
 * normalization itself is locale-agnostic (lowercasing is safe for all supported
 * locales: `he` has no case, `en` folds cleanly).
 */
export function normalize(text: string, _locale: string): string {
  return normalizeForHash(text);
}

/**
 * Encode a string as UTF-8 bytes for Web Crypto.
 */
function encode(s: string): ArrayBuffer {
  return new TextEncoder().encode(s).buffer as ArrayBuffer;
}

/**
 * Convert an ArrayBuffer of bytes to a lowercase hex string.
 */
function bufToHex(buf: ArrayBuffer): string {
  return bytesToHex(buf);
}

/**
 * Hash `text` under `locale` using SHA-256 (Web Crypto).
 *
 * The key fed to the hash is `${locale}:${normalizeForHash(text)}` so that
 * identical text in different locales produces different hashes.
 *
 * Returns a lowercase 64-character hex string.
 */
export async function hashUnit(text: string, locale: string): Promise<string> {
  const key = `${locale}:${normalizeForHash(text)}`;
  const buf = await crypto.subtle.digest('SHA-256', encode(key));
  return bufToHex(buf);
}
