/**
 * Ergonomic TypeScript wrapper around the qpq WASM crypto primitives.
 *
 * Call `initCrypto()` once before using any other function.
 */

import init, * as wasm from "../pkg/qpq_wasm_crypto.js";
import type { Identity, HybridKeypair } from "./types.js";

let initialized = false;

/** Initialize the WASM module. Safe to call multiple times. */
export async function initCrypto(): Promise<void> {
  if (!initialized) {
    await init();
    initialized = true;
  }
}

/** Returns true if the WASM module has been initialized. */
export function isCryptoReady(): boolean {
  return initialized;
}

// ---------------------------------------------------------------------------
// Ed25519 identity
// ---------------------------------------------------------------------------

/** Generate a fresh Ed25519 identity (32-byte seed + 32-byte public key). */
export function generateIdentity(): Identity {
  const seed = wasm.generate_identity();
  const publicKey = wasm.identity_public_key(seed);
  return { seed, publicKey };
}

/** Derive the 32-byte Ed25519 public key from a 32-byte seed. */
export function identityPublicKey(seed: Uint8Array): Uint8Array {
  return wasm.identity_public_key(seed);
}

/** Sign a message with an Ed25519 seed. Returns the 64-byte signature. */
export function sign(seed: Uint8Array, message: Uint8Array): Uint8Array {
  return wasm.sign(seed, message);
}

/** Verify an Ed25519 signature. Returns true if valid. */
export function verify(
  publicKey: Uint8Array,
  message: Uint8Array,
  signature: Uint8Array,
): boolean {
  return wasm.verify(publicKey, message, signature);
}

// ---------------------------------------------------------------------------
// Hybrid KEM (X25519 + ML-KEM-768)
// ---------------------------------------------------------------------------

/** Generate a hybrid keypair. Private: 2432 bytes, public: 1216 bytes. */
export function hybridGenerateKeypair(): HybridKeypair {
  const blob = wasm.hybrid_generate_keypair();
  const publicKey = wasm.hybrid_public_key(blob);
  return { blob, publicKey };
}

/** Extract the 1216-byte public key from a hybrid keypair blob. */
export function hybridPublicKey(keypairBlob: Uint8Array): Uint8Array {
  return wasm.hybrid_public_key(keypairBlob);
}

/** Encrypt plaintext to a hybrid public key. */
export function hybridEncrypt(
  publicKey: Uint8Array,
  plaintext: Uint8Array,
): Uint8Array {
  return wasm.hybrid_encrypt(publicKey, plaintext);
}

/** Decrypt a hybrid envelope using the keypair blob. */
export function hybridDecrypt(
  keypairBlob: Uint8Array,
  envelope: Uint8Array,
): Uint8Array {
  return wasm.hybrid_decrypt(keypairBlob, envelope);
}

// ---------------------------------------------------------------------------
// Safety number
// ---------------------------------------------------------------------------

/**
 * Compute a 60-digit safety number from two 32-byte Ed25519 public keys.
 * Returns 12 space-separated 5-digit groups.
 * Symmetric: computeSafetyNumber(a, b) === computeSafetyNumber(b, a).
 */
export function computeSafetyNumber(
  keyA: Uint8Array,
  keyB: Uint8Array,
): string {
  return wasm.compute_safety_number(keyA, keyB);
}

// ---------------------------------------------------------------------------
// Sealed sender
// ---------------------------------------------------------------------------

/**
 * Wrap a payload in a sealed sender envelope.
 * (magic || sender public key || Ed25519 signature || payload)
 */
export function seal(seed: Uint8Array, payload: Uint8Array): Uint8Array {
  return wasm.seal(seed, payload);
}

/**
 * Unseal a sealed sender envelope.
 * Returns sender_public_key(32) || inner_payload.
 */
export function unseal(envelope: Uint8Array): Uint8Array {
  return wasm.unseal(envelope);
}

// ---------------------------------------------------------------------------
// Message padding
// ---------------------------------------------------------------------------

/** Pad a message to a fixed bucket size (256, 1024, 4096, or 16384 bytes). */
export function padMessage(data: Uint8Array): Uint8Array {
  return wasm.pad_message(data);
}

/** Remove padding and recover the original message. */
export function unpadMessage(data: Uint8Array): Uint8Array {
  return wasm.unpad_message(data);
}
