package no.zyon.shade.streams

import javax.crypto.Cipher
import javax.crypto.spec.GCMParameterSpec
import javax.crypto.spec.SecretKeySpec

/**
 * AES-256-GCM with caller-supplied nonce. Mirror @shade/streams/aead.ts.
 *
 * Unlike `CryptoProvider.aesGcmEncrypt` (which generates a random nonce
 * internally), streams require deterministic nonces derived from
 * `(laneId, seq)`. Returns the ciphertext concatenated with the 16-byte
 * authentication tag — same layout SubtleCrypto produces.
 */

const val AEAD_TAG_BYTES = 16

fun aesGcmEncryptWithNonce(
    key: ByteArray,
    nonce: ByteArray,
    plaintext: ByteArray,
    aad: ByteArray,
): ByteArray {
    require(nonce.size == StreamConstants.STREAM_NONCE_BYTES) {
        "AES-GCM nonce must be ${StreamConstants.STREAM_NONCE_BYTES} bytes"
    }
    val cipher = Cipher.getInstance("AES/GCM/NoPadding")
    val spec = GCMParameterSpec(128, nonce)
    cipher.init(Cipher.ENCRYPT_MODE, SecretKeySpec(key, "AES"), spec)
    cipher.updateAAD(aad)
    return cipher.doFinal(plaintext)
}

fun aesGcmDecryptWithNonce(
    key: ByteArray,
    nonce: ByteArray,
    ciphertext: ByteArray,
    aad: ByteArray,
): ByteArray {
    require(nonce.size == StreamConstants.STREAM_NONCE_BYTES) {
        "AES-GCM nonce must be ${StreamConstants.STREAM_NONCE_BYTES} bytes"
    }
    val cipher = Cipher.getInstance("AES/GCM/NoPadding")
    val spec = GCMParameterSpec(128, nonce)
    cipher.init(Cipher.DECRYPT_MODE, SecretKeySpec(key, "AES"), spec)
    cipher.updateAAD(aad)
    return cipher.doFinal(ciphertext)
}
