/**
 * CP1255 (Windows-Hebrew) encoding module — uniform-format-export (wave-13, spec 180).
 *
 * The Israeli Tax Authority (ITA) uniform-structure export requires files
 * encoded in Windows-1255 (CP1255). The Worker runtime is UTF-16/UTF-8 native
 * and has no built-in CP1255 support, so we ship a bundled mapping table.
 *
 * Rules:
 * - ASCII 0x00–0x7F: identity mapping
 * - Hebrew block (U+05D0–U+05EA) + punctuation: mapped per Windows-1255 codepage
 * - Characters outside CP1255: transliterate where possible, else strip + log
 * - TextEncoder is NEVER used for final output bytes (it emits UTF-8)
 */

// ── CP1255 mapping table (Unicode code-point → CP1255 byte) ──────────────────
// Only non-identity entries (codepoint !== byte value) are listed.
// ASCII 0x00–0x7F map to themselves (handled inline).

const CP1255_TABLE: ReadonlyMap<number, number> = new Map([
  // Windows-1255 0x80–0x9F block (printable extensions)
  [0x20AC, 0x80], // €  EURO SIGN
  [0x201A, 0x82], // ‚  SINGLE LOW-9 QUOTATION MARK
  [0x0192, 0x83], // ƒ  LATIN SMALL LETTER F WITH HOOK
  [0x201E, 0x84], // „  DOUBLE LOW-9 QUOTATION MARK
  [0x2026, 0x85], // …  HORIZONTAL ELLIPSIS
  [0x2020, 0x86], // †  DAGGER
  [0x2021, 0x87], // ‡  DOUBLE DAGGER
  [0x02C6, 0x88], // ˆ  MODIFIER LETTER CIRCUMFLEX ACCENT
  [0x2030, 0x89], // ‰  PER MILLE SIGN
  [0x2039, 0x8B], // ‹  SINGLE LEFT-POINTING ANGLE QUOTATION MARK
  [0x2018, 0x91], // '  LEFT SINGLE QUOTATION MARK
  [0x2019, 0x92], // '  RIGHT SINGLE QUOTATION MARK
  [0x201C, 0x93], // "  LEFT DOUBLE QUOTATION MARK
  [0x201D, 0x94], // "  RIGHT DOUBLE QUOTATION MARK
  [0x2022, 0x95], // •  BULLET
  [0x2013, 0x96], // –  EN DASH
  [0x2014, 0x97], // —  EM DASH
  [0x02DC, 0x98], // ˜  SMALL TILDE
  [0x2122, 0x99], // ™  TRADE MARK SIGN
  [0x203A, 0x9B], // ›  SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
  // 0xA0: NO-BREAK SPACE → 0xA0 (same codepoint, identity in 0xA0–0xBF range for CP1255)
  [0x00A0, 0xA0], // NO-BREAK SPACE
  [0x00A2, 0xA2], // ¢ CENT SIGN
  [0x00A3, 0xA3], // £ POUND SIGN
  [0x00A4, 0xA4], // ¤ CURRENCY SIGN
  [0x00A5, 0xA5], // ¥ YEN SIGN
  [0x00A6, 0xA6], // ¦ BROKEN BAR
  [0x00A7, 0xA7], // § SECTION SIGN
  [0x00A8, 0xA8], // ¨ DIAERESIS
  [0x00A9, 0xA9], // © COPYRIGHT SIGN
  [0x00D7, 0xAA], // × MULTIPLICATION SIGN (Hebrew block: used at 0xAA in CP1255)
  [0x00AB, 0xAB], // « LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
  [0x00AC, 0xAC], // ¬ NOT SIGN
  [0x00AD, 0xAD], // ­ SOFT HYPHEN
  [0x00AE, 0xAE], // ® REGISTERED SIGN
  [0x00AF, 0xAF], // ¯ MACRON
  [0x00B0, 0xB0], // ° DEGREE SIGN
  [0x00B1, 0xB1], // ± PLUS-MINUS SIGN
  [0x00B2, 0xB2], // ² SUPERSCRIPT TWO
  [0x00B3, 0xB3], // ³ SUPERSCRIPT THREE
  [0x00B4, 0xB4], // ´ ACUTE ACCENT
  [0x00B5, 0xB5], // µ MICRO SIGN
  [0x00B6, 0xB6], // ¶ PILCROW SIGN
  [0x00B7, 0xB7], // · MIDDLE DOT
  [0x00B8, 0xB8], // ¸ CEDILLA
  [0x00B9, 0xB9], // ¹ SUPERSCRIPT ONE
  [0x00F7, 0xBA], // ÷ DIVISION SIGN
  [0x00BB, 0xBB], // » RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
  [0x00BC, 0xBC], // ¼ VULGAR FRACTION ONE QUARTER
  [0x00BD, 0xBD], // ½ VULGAR FRACTION ONE HALF
  [0x00BE, 0xBE], // ¾ VULGAR FRACTION THREE QUARTERS
  [0x00BF, 0xBF], // ¿ INVERTED QUESTION MARK
  // Nikud (Hebrew points) 0xC0–0xCF
  [0x05B0, 0xC0], // ְ HEBREW POINT SHEVA
  [0x05B1, 0xC1], // ֱ HEBREW POINT HATAF SEGOL
  [0x05B2, 0xC2], // ֲ HEBREW POINT HATAF PATAH
  [0x05B3, 0xC3], // ֳ HEBREW POINT HATAF QAMATS
  [0x05B4, 0xC4], // ִ HEBREW POINT HIRIQ
  [0x05B5, 0xC5], // ֵ HEBREW POINT TSERE
  [0x05B6, 0xC6], // ֶ HEBREW POINT SEGOL
  [0x05B7, 0xC7], // ַ HEBREW POINT PATAH
  [0x05B8, 0xC8], // ָ HEBREW POINT QAMATS
  [0x05B9, 0xC9], // ֹ HEBREW POINT HOLAM
  [0x05BB, 0xCB], // ּ HEBREW POINT QUBUTS
  [0x05BC, 0xCC], // ּ HEBREW POINT DAGESH OR MAPIQ
  [0x05BD, 0xCD], // ֽ HEBREW POINT METEG
  [0x05BE, 0xCE], // ־ HEBREW PUNCTUATION MAQAF
  [0x05BF, 0xCF], // ֿ HEBREW POINT RAFE
  [0x05C0, 0xD0], // ׀ HEBREW PUNCTUATION PASEQ
  [0x05C1, 0xD1], // ׁ HEBREW POINT SHIN DOT
  [0x05C2, 0xD2], // ׂ HEBREW POINT SIN DOT
  [0x05C3, 0xD3], // ׃ HEBREW PUNCTUATION SOF PASUQ
  [0x05F0, 0xD4], // װ HEBREW LIGATURE YIDDISH DOUBLE VAV
  [0x05F1, 0xD5], // ױ HEBREW LIGATURE YIDDISH VAV YOD
  [0x05F2, 0xD6], // ײ HEBREW LIGATURE YIDDISH DOUBLE YOD
  [0x05F3, 0xD7], // ׳ HEBREW PUNCTUATION GERESH
  [0x05F4, 0xD8], // ״ HEBREW PUNCTUATION GERSHAYIM
  // Hebrew alphabet 0xE0–0xFA
  [0x05D0, 0xE0], // א HEBREW LETTER ALEF
  [0x05D1, 0xE1], // ב HEBREW LETTER BET
  [0x05D2, 0xE2], // ג HEBREW LETTER GIMEL
  [0x05D3, 0xE3], // ד HEBREW LETTER DALET
  [0x05D4, 0xE4], // ה HEBREW LETTER HE
  [0x05D5, 0xE5], // ו HEBREW LETTER VAV
  [0x05D6, 0xE6], // ז HEBREW LETTER ZAYIN
  [0x05D7, 0xE7], // ח HEBREW LETTER HET
  [0x05D8, 0xE8], // ט HEBREW LETTER TET
  [0x05D9, 0xE9], // י HEBREW LETTER YOD
  [0x05DA, 0xEA], // ך HEBREW LETTER FINAL KAF
  [0x05DB, 0xEB], // כ HEBREW LETTER KAF
  [0x05DC, 0xEC], // ל HEBREW LETTER LAMED
  [0x05DD, 0xED], // ם HEBREW LETTER FINAL MEM
  [0x05DE, 0xEE], // מ HEBREW LETTER MEM
  [0x05DF, 0xEF], // ן HEBREW LETTER FINAL NUN
  [0x05E0, 0xF0], // נ HEBREW LETTER NUN
  [0x05E1, 0xF1], // ס HEBREW LETTER SAMEKH
  [0x05E2, 0xF2], // ע HEBREW LETTER AYIN
  [0x05E3, 0xF3], // ף HEBREW LETTER FINAL PE
  [0x05E4, 0xF4], // פ HEBREW LETTER PE
  [0x05E5, 0xF5], // ץ HEBREW LETTER FINAL TSADI
  [0x05E6, 0xF6], // צ HEBREW LETTER TSADI
  [0x05E7, 0xF7], // ק HEBREW LETTER QOF
  [0x05E8, 0xF8], // ר HEBREW LETTER RESH
  [0x05E9, 0xF9], // ש HEBREW LETTER SHIN
  [0x05EA, 0xFA], // ת HEBREW LETTER TAV
])

// Characters with reasonable ASCII transliterations (for ITA fallback)
const TRANSLITERATION: ReadonlyMap<number, string> = new Map([
  [0x2018, "'"],  // ' → '
  [0x2019, "'"],  // ' → '
  [0x201C, '"'],  // " → "
  [0x201D, '"'],  // " → "
  [0x2013, '-'],  // – → -
  [0x2014, '-'],  // — → -
  [0x2026, '...'], // … → ...
  [0x00A0, ' '],  // NBSP → space
])

/**
 * Encode a string to CP1255 bytes.
 * Characters outside CP1255 are stripped (ITA fallback: drop unrepresentable chars).
 * Use encodeCP1255WithReport to learn which characters were stripped.
 */
export function encodeCP1255(line: string): Uint8Array {
  return encodeCP1255WithReport(line).bytes
}

/**
 * Encode a string to CP1255 bytes, reporting any characters that were
 * substituted or stripped.
 */
export function encodeCP1255WithReport(line: string): { bytes: Uint8Array; substitutions: string[] } {
  const substitutions: string[] = []
  // Pre-estimate: most lines are ASCII, so pre-allocate line.length bytes
  const buf = new Uint8Array(line.length * 2) // worst case with transliterations
  let pos = 0

  for (let i = 0; i < line.length; i++) {
    const cp = line.codePointAt(i)!
    // Advance past surrogate pairs
    if (cp > 0xFFFF) i++

    // ASCII identity range
    if (cp < 0x80) {
      buf[pos++] = cp
      continue
    }

    // Check the mapping table
    const byte = CP1255_TABLE.get(cp)
    if (byte !== undefined) {
      buf[pos++] = byte
      continue
    }

    // Check for ASCII transliteration
    const trans = TRANSLITERATION.get(cp)
    if (trans !== undefined) {
      substitutions.push(`U+${cp.toString(16).toUpperCase().padStart(4, '0')} → "${trans}"`)
      for (let j = 0; j < trans.length; j++) {
        buf[pos++] = trans.charCodeAt(j)
      }
      continue
    }

    // Unrepresentable — strip and log
    const char = String.fromCodePoint(cp)
    substitutions.push(`U+${cp.toString(16).toUpperCase().padStart(4, '0')} "${char}" stripped`)
    // byte not written → character dropped
  }

  return { bytes: buf.slice(0, pos), substitutions }
}
