// Shared QAF upload constants (client + server actions). Lives outside the
// 'use server' module because server-action files may only export async
// functions. tdd-guard:skip — constants + one predicate, exercised via the
// action/client tests.

export const QAF_UPLOAD_BUCKET = 'qaf-uploads'

/** Per-file wire-size cap (compressed xlsx/xlsm) — see actions.ts DoS note. */
export const QAF_MAX_FILE_BYTES = 20 * 1024 * 1024

/** Batch cap: a G60 pair + a handful of summary QAFs; bounds signed-URL fanout. */
export const QAF_MAX_BATCH_FILES = 12

/** Single source for the accepted workbook extensions (checked on both ends).
 *
 * `.xls` (BIFF/OLE2) seit 27.07.2026 zugelassen: der Ingest liest es über
 * legacy-workbook-shim.ts. Vorher wurde es hier abgewiesen, bevor überhaupt ein
 * Puffer entstand — in einem realen Upload betraf das 1076 von 2475 Dateien. */
export function isAllowedQafFileName(name: string): boolean {
  const lower = name.toLowerCase()
  return lower.endsWith('.xlsx') || lower.endsWith('.xlsm') || lower.endsWith('.xls')
}

/**
 * Erkennt legacy binary Excel (.xls, pre-2007 BIFF, kein ZIP/OOXML-Container).
 *
 * ACHTUNG, die Aussage hat sich am 27.07.2026 umgekehrt: Unter KAR-961/P4 diente
 * dieses Prädikat dazu, `.xls` mit einer präzisen Meldung ABZULEHNEN, weil
 * ExcelJS das Format nicht öffnen kann. Seitdem liest der Ingest es über
 * `legacy-workbook-shim.ts`, und `isAllowedQafFileName` LÄSST `.xls` ZU.
 *
 * Das Prädikat sagt weiterhin korrekt "das ist eine Altformat-Datei" — nur die
 * Konsequenz daraus ist nicht mehr "ablehnen", sondern "über den BIFF-Lesepfad
 * einlesen". Produktive Konsumenten hat es derzeit keine (verifiziert per
 * repo-weitem Grep); es bleibt bestehen, weil die Unterscheidung für Meldungen
 * und Diagnose weiterhin nützlich ist.
 * Anchored so `.xlsx`/`.xlsm` never match (both end in a 4th character other
 * than 's' right after ".xl").
 */
export function isLegacyXlsFileName(name: string): boolean {
  return /\.xls$/i.test(name.trim())
}

/** DE message for a rejected legacy .xls upload (ActionResult.error /
 * fileErrors — both are plain, German-first user-facing strings in this
 * feature, see actions.ts). PR #328 review fix (finding [7]): the EN
 * counterpart that used to live here was removed — it had no production
 * consumer (both ActionResult call sites in actions.ts use only this DE
 * string, matching their existing German-only error text) and its own doc
 * comment's claim of a bilingual UI surface using it was aspirational, not
 * actual — dead code that risked misleading a future maintainer into
 * thinking it was wired in. */
export const LEGACY_XLS_UNSUPPORTED_MESSAGE_DE =
  'Dieses Datei-Format (.xls, altes binäres Excel-Format vor 2007) wird nicht unterstützt. Bitte die Datei in Excel oder LibreOffice als .xlsx neu speichern und erneut hochladen.'

/** Browsers often report an empty type for .xlsm — derive from extension. */
export function contentTypeFor(file: File): string {
  if (file.type) return file.type
  if (file.name.toLowerCase().endsWith('.xlsm')) return 'application/vnd.ms-excel.sheet.macroenabled.12'
  return 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
}

/** XHR PUT to a signed URL — fetch has no upload progress events. */
export function uploadWithProgress(url: string, file: File, onLoaded: (bytes: number) => void): Promise<void> {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest()
    xhr.open('PUT', url)
    xhr.setRequestHeader('Content-Type', contentTypeFor(file))
    xhr.upload.onprogress = (e) => onLoaded(e.loaded)
    xhr.onload = () => {
      if (xhr.status >= 200 && xhr.status < 300) return resolve()
      const detail = (xhr.responseText || '').slice(0, 160)
      reject(new Error(`HTTP ${xhr.status}${detail ? ` — ${detail}` : ''}`))
    }
    xhr.onerror = () => reject(new Error('Netzwerkfehler'))
    xhr.send(file)
  })
}
