export const MEMORY_LIMIT = 64 * 1024 * 1024;

export function safeName(name) {
  return String(name || 'fichier').split(/[\\/]/).pop().replace(/[\x00-\x1f<>:"|?*]/g, '_').replace(/[. ]+$/, '').slice(0, 180) || 'fichier';
}

export async function createSink(file) {
  if (!Number.isSafeInteger(file.size) || file.size < 0) throw new Error('Taille de fichier invalide.');
  const name = safeName(file.name);
  let written = 0;
  const count = (bytes) => {
    if (!(bytes instanceof Uint8Array)) throw new Error('Bloc de fichier invalide.');
    if (written + bytes.byteLength > file.size) throw new Error('Le fichier dépasse la taille annoncée.');
    written += bytes.byteLength;
  };
  const complete = () => {
    if (written !== file.size) throw new Error('Le fichier reçu est incomplet.');
  };
  if (window.desktop?.openSink) {
    const result = await window.desktop.openSink({ name, size: file.size });
    if (!result) throw new DOMException('Enregistrement annulé.', 'AbortError');
    return {
      mode: 'native',
      async write(bytes) { count(bytes); await window.desktop.writeSink(result.id, bytes); },
      async close() { complete(); await window.desktop.closeSink(result.id); },
      async abort() { await window.desktop.abortSink(result.id); },
    };
  }
  if ('showSaveFilePicker' in window) {
    const handle = await window.showSaveFilePicker({ suggestedName: name });
    const writable = await handle.createWritable();
    return {
      mode: 'disk',
      async write(bytes) { count(bytes); await writable.write(bytes); },
      async close() { complete(); await writable.close(); },
      async abort() { await writable.abort(); },
    };
  }
  if (file.size > MEMORY_LIMIT) {
    throw new Error('Ce navigateur ne permet pas l’écriture directe sur disque. Au-delà de 64 Mio, utilisez Chrome/Edge sur ordinateur ou l’application TransferWing.');
  }
  let chunks = [];
  return {
    mode: 'memory',
    async write(bytes) { count(bytes); chunks.push(bytes.slice()); },
    async close() {
      complete();
      const url = URL.createObjectURL(new Blob(chunks, { type: 'application/octet-stream' }));
      chunks = [];
      const a = document.createElement('a');
      a.href = url; a.download = name; a.hidden = true;
      document.body.append(a); a.click(); a.remove();
      setTimeout(() => URL.revokeObjectURL(url), 30_000);
    },
    async abort() { chunks = []; },
  };
}
