// Platform-agnostic crypto backend contract. Each host (desktop / mobile)
// registers its own implementation at boot via `setCryptoBackend`.
//
// Why an interface?
//   - Desktop: libsodium-wrappers (WASM, needs async ready-gate).
//   - Mobile:  react-native-libsodium (native bindings, different API shape).
//   - Tests:   deterministic backend with seeded RNG.
//
// Backends are expected to be *synchronous* after registration. Any async
// initialisation (e.g. libsodium's WASM warm-up) happens before the backend
// object is handed to `setCryptoBackend`.

export interface KeyPair {
  publicKey: Uint8Array;
  privateKey: Uint8Array;
}

export interface CryptoBackend {
  readonly name: string;
  readonly nonceLength: number; // crypto_box_NONCEBYTES — 24
  readonly publicKeyLength: number; // 32
  readonly privateKeyLength: number; // 32
  readonly secretboxKeyLength: number; // crypto_secretbox_KEYBYTES — 32
  readonly secretboxNonceLength: number; // crypto_secretbox_NONCEBYTES — 24

  randomBytes(n: number): Uint8Array;
  generateKeyPair(): KeyPair;

  // Authenticated encryption (X25519 + XSalsa20-Poly1305, AKA crypto_box).
  box(
    plaintext: Uint8Array,
    nonce: Uint8Array,
    recipientPublicKey: Uint8Array,
    senderPrivateKey: Uint8Array,
  ): Uint8Array;

  // Must throw on authentication failure.
  boxOpen(
    ciphertext: Uint8Array,
    nonce: Uint8Array,
    senderPublicKey: Uint8Array,
    recipientPrivateKey: Uint8Array,
  ): Uint8Array;

  // Symmetric authenticated encryption (XSalsa20-Poly1305, crypto_secretbox).
  // Used for large blobs (attachments) — one key per blob, key itself is
  // distributed per recipient via crypto_box envelopes.
  secretbox(plaintext: Uint8Array, nonce: Uint8Array, key: Uint8Array): Uint8Array;
  secretboxOpen(ciphertext: Uint8Array, nonce: Uint8Array, key: Uint8Array): Uint8Array;
}

let current: CryptoBackend | null = null;

export function setCryptoBackend(backend: CryptoBackend): void {
  current = backend;
}

export function getCryptoBackend(): CryptoBackend {
  if (!current) {
    throw new Error(
      'Crypto backend not configured. Call setCryptoBackend() at app boot before any crypto operation.',
    );
  }
  return current;
}

export function isCryptoBackendReady(): boolean {
  return current !== null;
}
