import { expect, test } from "bun:test";
import * as wasm from "import-core";
import { slugifyTerm } from "../src/processor";

/**
 * Historical reference implementation — this is what `processor.ts#slugifyTerm`
 * used to do before it was unified onto `wasm.slugify` (crates/import-core/src/
 * normalize.rs). Kept here ONLY as a parity lock: if this ever diverges from
 * wasm.slugify on the corpus below, DO NOT touch processor.ts — that would
 * silently create duplicate `keywords.id = ${siteId}-${slug}` rows across
 * imports. Investigate the divergence first.
 */
function historicalSlugifyTerm(s: string): string {
  return s
    .toLowerCase()
    .normalize("NFD")
    .replace(/\p{Diacritic}/gu, "")
    .replace(/[^a-z0-9]+/g, "-")
    .replace(/(^-|-$)/g, "");
}

/** [label, input, expectedSlug] — realistic + adversarial corpus: French
 *  accents, typographic apostrophes, multi-word terms, existing hyphens,
 *  digits, German ß, Turkish dotted/dotless I, emoji (incl. ZWJ/flag/skin-tone
 *  sequences), multiple spaces/tabs/newlines/NBSP, empty string, CJK,
 *  fullwidth chars, Greek/Cyrillic/Arabic, astral-plane codepoints. */
const CASES: [string, string, string][] = [
  ["empty", "", ""],
  ["basic", "Foo Bar", "foo-bar"],
  ["digits", "123 ABC", "123-abc"],
  ["accent e-aigu", "éclairage", "eclairage"],
  ["accents multi-word", "électricité entreprise", "electricite-entreprise"],
  ["accents mixed", "café crème", "cafe-creme"],
  ["existing hyphen + accent", "déjà-vu", "deja-vu"],
  ["cedille", "façade", "facade"],
  ["accent tréma", "naïve", "naive"],
  ["accent e-aigu 2", "groupé", "groupe"],
  ["apostrophe droite", "L'énergie", "l-energie"],
  ["apostrophe typographique", "L’énergie", "l-energie"],
  ["cedille + accent grave", "Çà et là", "ca-et-la"],
  ["eszett", "Süßwaren", "su-waren"],
  ["oe ligature + apostrophe", "œuvre d'art", "uvre-d-art"],
  ["oe ligature alone", "cœur", "c-ur"],
  ["multiple spaces", "  spaced  out  ", "spaced-out"],
  ["existing multi-hyphen", "---trim---", "trim"],
  ["existing multi-hyphen + spaces", "already--hyphenated -- term", "already-hyphenated-term"],
  ["digits + hyphen", "seo 2024 top-10", "seo-2024-top-10"],
  ["only punctuation", "!!!@@@###", ""],
  ["emoji inline", "seo 🚀 rocket", "seo-rocket"],
  ["emoji only", "🔥🔥🔥", ""],
  ["CJK only", "关键词研究", ""],
  ["CJK mixed", "seo 关键词 tool", "seo-tool"],
  ["fullwidth alnum", "ＡＢＣ１２３", ""],
  ["fullwidth punctuation", "seo，工具", "seo"],
  ["polish + french accents", "Kraków naïveté", "krakow-naivete"],
  ["vietnamese", "Việt Nam", "viet-nam"],
  ["combining ring above", "ångström", "angstrom"],
  ["leading/trailing punctuation", "-- term --", "term"],
  ["tab and newline", "term\twith\nwhitespace", "term-with-whitespace"],
  ["nbsp", "term with nbsp", "term-with-nbsp"],
  ["zero width joiner", "zero​width​joiner", "zero-width-joiner"],
  ["no separators, long word", "supercalifragilisticexpialidocious", "supercalifragilisticexpialidocious"],
  ["capital sharp s", "GROẞ", "gro"],
  ["zwj family emoji", "team 👨‍👩‍👧‍👦 seo", "team-seo"],
  ["flag emoji (regional indicators)", "france 🇫🇷 seo", "france-seo"],
  ["skin tone modifier", "wave 👋🏽 hello", "wave-hello"],
  ["turkish dotted capital I", "İstanbul", "istanbul"],
  ["turkish dotless lowercase i", "ıstanbul", "stanbul"],
  ["turkish dotless uppercase I", "ISPARTA", "isparta"],
  ["greek", "καλημέρα κόσμε", ""],
  ["cyrillic", "привет мир", ""],
  ["arabic (RTL)", "مرحبا بالعالم", ""],
  ["astral plane CJK ext B", "𠀀𠀁 test", "test"],
  ["long diacritic chain", "éèàçœûîôäëïöü", "eeac-uioaeiou"],
  ["numbers only", "1234567890", "1234567890"],
  ["single char", "a", "a"],
  ["single hyphen", "-", ""],
  ["all hyphens", "-----", ""],
];

test("slugifyTerm (wasm.slugify) matches the golden corpus", () => {
  for (const [label, input, expected] of CASES) {
    expect(slugifyTerm(input), label).toBe(expected);
  }
});

test("wasm.slugify is byte-for-byte the exposed entrypoint (no local override)", () => {
  for (const [label, input] of CASES) {
    expect(slugifyTerm(input), label).toBe(wasm.slugify(input));
  }
});

test("parity lock: historical TS regex slugify vs wasm.slugify (do not remove)", () => {
  for (const [label, input] of CASES) {
    expect(historicalSlugifyTerm(input), label).toBe(wasm.slugify(input));
  }
});
