import 'dart:typed_data';
import 'package:pointycastle/export.dart';

/// AES-256-CTR symmetric cipher wrapper.
///
/// AES-CTR is a stream cipher: encryption and decryption use the same
/// operation (XOR with key-stream), and there is no padding. The output
/// length always equals the input length, making it ideal for our fixed-size
/// 11-byte voice payload.
///
/// Security notes:
///   • Never reuse the same (key, nonce) pair.
///   • Nonce uniqueness is guaranteed by including the packet sequence
///     number in the nonce (see [KeyManager.buildNonce]).
///   • The key is zeroed from memory when the session ends.
abstract final class AesCipher {
  // ── Core cipher op (encrypt = decrypt for CTR mode) ───────────────

  /// Encrypt or decrypt [data] with [key] (32 bytes) and [nonce] (16 bytes).
  ///
  /// AES-256-CTR: keystream = AES_k(nonce ∥ counter), output = data ⊕ keystream.
  /// [forEncryption] = true → encrypt; false → decrypt (same operation in CTR).
  static Uint8List _ctr(Uint8List data, Uint8List key, Uint8List nonce,
      {required bool forEncryption}) {
    assert(key.length == 32,  'AES-256 requires a 32-byte key');
    assert(nonce.length == 16, 'CTR nonce must be 16 bytes (one AES block)');

    final cipher = StreamCipher('AES/CTR')
      ..init(forEncryption, ParametersWithIV(KeyParameter(key), nonce));

    final out = Uint8List(data.length);
    cipher.processBytes(data, 0, data.length, out, 0);
    return out;
  }

  /// Encrypt [plaintext] → ciphertext (same length as input).
  static Uint8List encrypt(Uint8List plaintext, Uint8List key, Uint8List nonce) =>
      _ctr(plaintext, key, nonce, forEncryption: true);

  /// Decrypt [ciphertext] → plaintext (same length as input).
  static Uint8List decrypt(Uint8List ciphertext, Uint8List key, Uint8List nonce) =>
      _ctr(ciphertext, key, nonce, forEncryption: false);
}
