/**
 * CSV export writer — financial-statements (wave-13).
 *
 * RFC-4180 compliant CSV; every cell value passes through neutralizeFormula().
 * Default encoding: UTF-8 with BOM so Excel opens Hebrew correctly.
 * Optional CP1255 encoding: for spec 171 (PCN874) reuse.
 */
import { neutralizeFormula } from './sanitize'
import type { CsvExportOptions } from './types'

/** RFC-4180 quoting: wrap in double-quotes, escape internal double-quotes. */
function csvCell(value: string | number | null | undefined): string {
  if (value === null || value === undefined) return ''
  const str = typeof value === 'number' ? String(value) : neutralizeFormula(String(value))
  if (/[",\r\n]/.test(str)) {
    return `"${str.replace(/"/g, '""')}"`
  }
  return str
}

/**
 * Encode a string to CP1255 (Windows-1255, Hebrew).
 * Maps Unicode Hebrew code-points U+05D0–U+05EA and punctuation to their
 * CP1255 byte values. Any char not in the mapping falls back to its
 * Latin-1 byte value (passthrough for ASCII range).
 */
function encodeCP1255(text: string): Uint8Array {
  // CP1255 Hebrew block: U+05D0 (alef) = 0xE0 ... U+05EA (tav) = 0xFA
  const bytes: number[] = []
  for (let i = 0; i < text.length; i++) {
    const cp = text.charCodeAt(i)
    if (cp >= 0x05d0 && cp <= 0x05ea) {
      bytes.push(cp - 0x05d0 + 0xe0)
    } else if (cp < 0x80) {
      bytes.push(cp)
    } else if (cp === 0x20ac) {
      bytes.push(0x80) // Euro sign
    } else if (cp < 0x100) {
      bytes.push(cp) // Latin-1 passthrough
    } else {
      bytes.push(0x3f) // '?' fallback for unmappable chars
    }
  }
  return new Uint8Array(bytes)
}

export function writeCsv(
  opts: CsvExportOptions,
  encoding: 'utf-8' | 'cp1255' = 'utf-8',
): Uint8Array {
  const { sheet } = opts
  const lines: string[] = []

  // Header row — neutralize formula on each header string
  lines.push(sheet.columns.map((col) => csvCell(col.header)).join(','))

  // Data rows
  for (const rowData of sheet.rows) {
    lines.push(sheet.columns.map((col) => csvCell(rowData[col.key])).join(','))
  }

  const csv = lines.join('\r\n')

  if (encoding === 'cp1255') {
    return encodeCP1255(csv)
  }

  // UTF-8 with BOM (EF BB BF) so Excel opens Hebrew correctly
  const bomBytes = new Uint8Array([0xef, 0xbb, 0xbf])
  const textBytes = new TextEncoder().encode(csv)
  const result = new Uint8Array(bomBytes.length + textBytes.length)
  result.set(bomBytes, 0)
  result.set(textBytes, bomBytes.length)
  return result
}
