// Web Worker — runs XSalsa20-Poly1305 decrypt + utf8 decode off the main
// thread. The conv-key lookup (which is network-bound) stays in the main
// thread; only the CPU-heavy AEAD + UTF-8 step runs here.
//
// Message protocol:
//   request:  { id: string, items: Array<{ id, ciphertext, nonce, key }> }
//   response: { id: string, results: Array<{ id, plaintext: string | null }> }

/// <reference lib="webworker" />

import sodium from 'libsodium-wrappers-sumo';

interface DecryptItem {
  id: string;
  ciphertext: Uint8Array;
  nonce: Uint8Array;
  key: Uint8Array;
}

interface DecryptRequest {
  id: string;
  items: DecryptItem[];
}

interface DecryptResult {
  id: string;
  plaintext: string | null;
}

interface DecryptResponse {
  id: string;
  results: DecryptResult[];
}

let sodiumReady: Promise<typeof sodium> | null = null;

async function ensureSodium(): Promise<typeof sodium> {
  if (!sodiumReady) sodiumReady = sodium.ready.then(() => sodium);
  return sodiumReady;
}

function decodeOne(s: typeof sodium, item: DecryptItem): string | null {
  try {
    const plain = s.crypto_secretbox_open_easy(item.ciphertext, item.nonce, item.key);
    return new TextDecoder('utf-8', { fatal: false }).decode(plain);
  } catch {
    return null;
  }
}

self.addEventListener('message', (ev: MessageEvent<DecryptRequest>) => {
  const req = ev.data;
  void (async () => {
    const s = await ensureSodium();
    const results: DecryptResult[] = req.items.map((item) => ({
      id: item.id,
      plaintext: decodeOne(s, item),
    }));
    const resp: DecryptResponse = { id: req.id, results };
    (self as unknown as Worker).postMessage(resp);
  })();
});
