const WIN_ANSI_EXTRA = new Set(
  Array.from("€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ"),
);

function isWinAnsiCharacter(character: string) {
  const codePoint = character.codePointAt(0) || 0;
  return (
    (codePoint >= 0x20 && codePoint <= 0x7e) ||
    (codePoint >= 0xa0 && codePoint <= 0xff) ||
    WIN_ANSI_EXTRA.has(character)
  );
}

function removeEmoji(value: string) {
  return value
    .replace(/[#*0-9]\uFE0F?\u20E3/gu, "")
    .replace(/\p{Regional_Indicator}{2}/gu, "")
    .replace(
      /\p{Extended_Pictographic}(?:\uFE0F|\uFE0E|\p{Emoji_Modifier})?(?:\u200D\p{Extended_Pictographic}(?:\uFE0F|\uFE0E|\p{Emoji_Modifier})?)*/gu,
      "",
    )
    .replace(/[\u200D\u20E3\uFE0E\uFE0F]/gu, "");
}

export function safePdfString(value?: string | null) {
  if (!value) return "";

  const normalized = removeEmoji(String(value).normalize("NFC"));
  let result = "";

  for (const character of normalized) {
    if (character === "\n" || character === "\r" || character === "\t") {
      result += " ";
      continue;
    }
    if (isWinAnsiCharacter(character)) {
      result += character;
      continue;
    }

    const fallback = character.normalize("NFKD").replace(/\p{Mark}/gu, "");
    result += Array.from(fallback).filter(isWinAnsiCharacter).join("");
  }

  return result.replace(/ {2,}/g, " ").trim();
}
