import * as crypto from 'node:crypto'

import { hasOpenSSL } from '../../common/crypto.js'

const boringSSL = process.features.openssl_is_boringssl;
const pqc = hasOpenSSL(3, 5) || boringSSL;
const argon2 = hasOpenSSL(3, 2);
const shake128 = crypto.getHashes().includes('shake128');
const shake256 = crypto.getHashes().includes('shake256');
const ocb = hasOpenSSL(3);
const kmac = hasOpenSSL(3);

const { subtle } = globalThis.crypto;
const X25519 = await subtle.generateKey('X25519', false, ['deriveBits', 'deriveKey']);

export const vectors = {
  'digest': [
    [false, 'cSHAKE128'],
    [shake128, { name: 'cSHAKE128', outputLength: 128 }],
    [shake128, { name: 'cSHAKE128', outputLength: 128, functionName: Buffer.alloc(0), customization: Buffer.alloc(0) }],
    [false, { name: 'cSHAKE128', outputLength: 128, functionName: Buffer.alloc(1) }],
    [false, { name: 'cSHAKE128', outputLength: 128, customization: Buffer.alloc(1) }],
    [false, { name: 'cSHAKE128', outputLength: 127 }],
    [false, 'cSHAKE256'],
    [shake256, { name: 'cSHAKE256', outputLength: 256 }],
    [shake256, { name: 'cSHAKE256', outputLength: 256, functionName: Buffer.alloc(0), customization: Buffer.alloc(0) }],
    [false, { name: 'cSHAKE256', outputLength: 256, functionName: Buffer.alloc(1) }],
    [false, { name: 'cSHAKE256', outputLength: 256, customization: Buffer.alloc(1) }],
    [false, { name: 'cSHAKE256', outputLength: 255 }],
    [false, 'TurboSHAKE128'],
    [true, { name: 'TurboSHAKE128', outputLength: 128 }],
    [true, { name: 'TurboSHAKE128', outputLength: 128, domainSeparation: 0x07 }],
    [false, { name: 'TurboSHAKE128', outputLength: 0 }],
    [false, { name: 'TurboSHAKE128', outputLength: 127 }],
    [false, { name: 'TurboSHAKE128', outputLength: 128, domainSeparation: 0x00 }],
    [false, { name: 'TurboSHAKE128', outputLength: 128, domainSeparation: 0x80 }],
    [false, 'TurboSHAKE256'],
    [true, { name: 'TurboSHAKE256', outputLength: 256 }],
    [true, { name: 'TurboSHAKE256', outputLength: 256, domainSeparation: 0x07 }],
    [false, { name: 'TurboSHAKE256', outputLength: 0 }],
    [false, { name: 'TurboSHAKE256', outputLength: 255 }],
    [false, { name: 'TurboSHAKE256', outputLength: 256, domainSeparation: 0x00 }],
    [false, { name: 'TurboSHAKE256', outputLength: 256, domainSeparation: 0x80 }],
    [false, 'KT128'],
    [true, { name: 'KT128', outputLength: 128 }],
    [true, { name: 'KT128', outputLength: 128, customization: Buffer.alloc(0) }],
    [false, { name: 'KT128', outputLength: 0 }],
    [false, { name: 'KT128', outputLength: 127 }],
    [false, 'KT256'],
    [true, { name: 'KT256', outputLength: 256 }],
    [true, { name: 'KT256', outputLength: 256, customization: Buffer.alloc(0) }],
    [false, { name: 'KT256', outputLength: 0 }],
    [false, { name: 'KT256', outputLength: 255 }],
  ],
  'sign': [
    [pqc, 'ML-DSA-44'],
    [pqc, 'ML-DSA-65'],
    [pqc, 'ML-DSA-87'],
    [pqc, { name: 'ML-DSA-44', context: Buffer.alloc(0) }],
    [pqc, { name: 'ML-DSA-65', context: Buffer.alloc(0) }],
    [pqc, { name: 'ML-DSA-87', context: Buffer.alloc(0) }],
    [pqc, { name: 'ML-DSA-44', context: Buffer.alloc(32) }],
    [pqc, { name: 'ML-DSA-65', context: Buffer.alloc(32) }],
    [pqc, { name: 'ML-DSA-87', context: Buffer.alloc(32) }],
    [false, 'Argon2d'],
    [false, 'Argon2i'],
    [false, 'Argon2id'],
    [false, 'KMAC128'],
    [false, 'KMAC256'],
    [kmac, { name: 'KMAC128', outputLength: 256 }],
    [kmac, { name: 'KMAC256', outputLength: 256 }],
  ],
  'generateKey': [
    [pqc, 'ML-DSA-44'],
    [pqc, 'ML-DSA-65'],
    [pqc, 'ML-DSA-87'],
    [pqc && !boringSSL, 'ML-KEM-512'],
    [pqc, 'ML-KEM-768'],
    [pqc, 'ML-KEM-1024'],
    [true, 'ChaCha20-Poly1305'],
    [ocb, { name: 'AES-OCB', length: 128 }],
    [false, 'Argon2d'],
    [false, 'Argon2i'],
    [false, 'Argon2id'],
    [kmac, 'KMAC128'],
    [kmac, 'KMAC256'],
    [kmac, { name: 'KMAC128', length: 256 }],
    [kmac, { name: 'KMAC256', length: 128 }],
    [false, { name: 'KMAC128', length: 0 }],
    [false, { name: 'KMAC256', length: 0 }],
    [false, { name: 'KMAC128', length: 1 }],
    [false, { name: 'KMAC256', length: 1 }],
  ],
  'importKey': [
    [pqc, 'ML-DSA-44'],
    [pqc, 'ML-DSA-65'],
    [pqc, 'ML-DSA-87'],
    [pqc && !boringSSL, 'ML-KEM-512'],
    [pqc, 'ML-KEM-768'],
    [pqc, 'ML-KEM-1024'],
    [true, 'ChaCha20-Poly1305'],
    [ocb, { name: 'AES-OCB', length: 128 }],
    [argon2, 'Argon2d'],
    [argon2, 'Argon2i'],
    [argon2, 'Argon2id'],
    [kmac, 'KMAC128'],
    [kmac, 'KMAC256'],
    [kmac, { name: 'KMAC128', length: 256 }],
    [kmac, { name: 'KMAC256', length: 128 }],
    [false, { name: 'KMAC128', length: 0 }],
    [false, { name: 'KMAC256', length: 0 }],
    [false, { name: 'KMAC128', length: 1 }],
    [false, { name: 'KMAC256', length: 1 }],
  ],
  'exportKey': [
    [pqc, 'ML-DSA-44'],
    [pqc, 'ML-DSA-65'],
    [pqc, 'ML-DSA-87'],
    [pqc && !boringSSL, 'ML-KEM-512'],
    [pqc, 'ML-KEM-768'],
    [pqc, 'ML-KEM-1024'],
    [true, 'ChaCha20-Poly1305'],
    [ocb, 'AES-OCB'],
    [false, 'Argon2d'],
    [false, 'Argon2i'],
    [false, 'Argon2id'],
    [kmac, 'KMAC128'],
    [kmac, 'KMAC256'],
  ],
  'getPublicKey': [
    [true, 'RSA-OAEP'],
    [true, 'RSA-PSS'],
    [true, 'RSASSA-PKCS1-v1_5'],
    [true, 'X25519'],
    [!boringSSL, 'X448'],
    [true, 'Ed25519'],
    [!boringSSL, 'Ed448'],
    [true, 'ECDH'],
    [true, 'ECDSA'],
    [pqc, 'ML-DSA-44'],
    [pqc, 'ML-DSA-65'],
    [pqc, 'ML-DSA-87'],
    [pqc && !boringSSL, 'ML-KEM-512'],
    [pqc, 'ML-KEM-768'],
    [pqc, 'ML-KEM-1024'],
    [false, 'AES-CTR'],
    [false, 'AES-CBC'],
    [false, 'AES-GCM'],
    [false, 'AES-OCB'],
    [false, 'AES-KW'],
    [false, 'ChaCha20-Poly1305'],
    [false, 'Argon2d'],
    [false, 'Argon2i'],
    [false, 'Argon2id'],
    [false, 'KMAC128'],
    [false, 'KMAC256'],
  ],
  'deriveKey': [
    [argon2,
     { name: 'X25519', public: X25519.publicKey },
     'Argon2d'],
    [argon2,
     { name: 'X25519', public: X25519.publicKey },
     'Argon2i'],
    [argon2,
     { name: 'X25519', public: X25519.publicKey },
     'Argon2id'],
  ],
  'deriveBits': [
    [argon2, { name: 'Argon2d', nonce: Buffer.alloc(8), parallelism: 1, memory: 8, passes: 1 }, 32],
    [false, { name: 'Argon2d', nonce: Buffer.alloc(8), parallelism: 1, memory: 8, passes: 0 }, 32],
    [false, { name: 'Argon2d', nonce: Buffer.alloc(7), parallelism: 1, memory: 8, passes: 1 }, 32],
    [argon2, { name: 'Argon2d', nonce: Buffer.alloc(8), parallelism: 1, memory: 8, passes: 1 }, 32],
    [argon2, { name: 'Argon2d', nonce: Buffer.alloc(8), parallelism: 2, memory: 16, passes: 1 }, 32],
    [argon2, { name: 'Argon2d', nonce: Buffer.alloc(8), parallelism: 1, memory: 8, passes: 1, secretValue: Buffer.alloc(0) }, 32],
    [argon2, { name: 'Argon2d', nonce: Buffer.alloc(8), parallelism: 1, memory: 8, passes: 1, associatedData: Buffer.alloc(0) }, 32],
    [argon2, { name: 'Argon2d', nonce: Buffer.alloc(8), parallelism: 1, memory: 8, passes: 1, version: 0x13 }, 32],
    [false, { name: 'Argon2d', nonce: Buffer.alloc(8), parallelism: 1, memory: 8, passes: 1, version: 0x14 }, 32],
    [false, { name: 'Argon2d', nonce: Buffer.alloc(8), parallelism: 1, memory: 7, passes: 1 }, 32],
    [false, { name: 'Argon2d', nonce: Buffer.alloc(8), parallelism: 2, memory: 15, passes: 1 }, 32],
    [false, { name: 'Argon2d', nonce: Buffer.alloc(8), parallelism: 1, memory: 8, passes: 1 }, null],
    [false, { name: 'Argon2d', nonce: Buffer.alloc(8), parallelism: 1, memory: 8, passes: 1 }, 24],
    [false, { name: 'Argon2d', nonce: Buffer.alloc(8), parallelism: 1, memory: 8, passes: 1 }, 31],
    [false, { name: 'Argon2d', nonce: Buffer.alloc(8), parallelism: 0, memory: 8, passes: 1 }, 32],
    [false, { name: 'Argon2d', nonce: Buffer.alloc(8), parallelism: 16777215, memory: 8, passes: 1 }, 32],
  ],
  'encrypt': [
    [true, { name: 'ChaCha20-Poly1305', iv: Buffer.alloc(12) }],
    [false, { name: 'ChaCha20-Poly1305', iv: Buffer.alloc(16) }],
    [true, { name: 'ChaCha20-Poly1305', iv: Buffer.alloc(12), tagLength: 128 }],
    [false, { name: 'ChaCha20-Poly1305', iv: Buffer.alloc(12), tagLength: 64 }],
    [false, 'ChaCha20-Poly1305'],
    [ocb, { name: 'AES-OCB', iv: Buffer.alloc(15) }],
    [false, { name: 'AES-OCB', iv: Buffer.alloc(16) }],
    [ocb, { name: 'AES-OCB', iv: Buffer.alloc(12), tagLength: 128 }],
    [ocb, { name: 'AES-OCB', iv: Buffer.alloc(12), tagLength: 96 }],
    [ocb, { name: 'AES-OCB', iv: Buffer.alloc(12), tagLength: 64 }],
    [false, { name: 'AES-OCB', iv: Buffer.alloc(12), tagLength: 32 }],
    [false, 'AES-OCB'],
  ],
  'encapsulateBits': [
    [pqc && !boringSSL, 'ML-KEM-512'],
    [pqc, 'ML-KEM-768'],
    [pqc, 'ML-KEM-1024'],
  ],
  'encapsulateKey': [
    [pqc && !boringSSL, 'ML-KEM-512', 'AES-KW'],
    [pqc, 'ML-KEM-768', 'AES-KW'],
    [pqc, 'ML-KEM-768', 'AES-GCM'],
    [pqc, 'ML-KEM-768', 'AES-CTR'],
    [pqc, 'ML-KEM-768', 'AES-CBC'],
    [pqc, 'ML-KEM-768', 'ChaCha20-Poly1305'],
    [pqc, 'ML-KEM-768', 'HKDF'],
    [pqc, 'ML-KEM-768', 'PBKDF2'],
    [pqc, 'ML-KEM-768', { name: 'HMAC', hash: 'SHA-256' }],
    [pqc, 'ML-KEM-768', { name: 'HMAC', hash: 'SHA-256', length: 256 }],
    [false, 'ML-KEM-768', { name: 'HMAC', hash: 'SHA-256', length: 128 }],
  ],
  'decapsulateBits': [
    [pqc && !boringSSL, 'ML-KEM-512'],
    [pqc, 'ML-KEM-768'],
    [pqc, 'ML-KEM-1024'],
  ],
  'decapsulateKey': [
    [pqc && !boringSSL, 'ML-KEM-512', 'AES-KW'],
    [pqc, 'ML-KEM-768', 'AES-KW'],
    [pqc, 'ML-KEM-768', 'AES-GCM'],
    [pqc, 'ML-KEM-768', 'AES-CTR'],
    [pqc, 'ML-KEM-768', 'AES-CBC'],
    [pqc, 'ML-KEM-768', 'ChaCha20-Poly1305'],
    [pqc, 'ML-KEM-768', 'HKDF'],
    [pqc, 'ML-KEM-768', 'PBKDF2'],
    [pqc, 'ML-KEM-768', { name: 'HMAC', hash: 'SHA-256' }],
    [pqc, 'ML-KEM-768', { name: 'HMAC', hash: 'SHA-256', length: 256 }],
    [false, 'ML-KEM-768', { name: 'HMAC', hash: 'SHA-256', length: 128 }],
  ],
};
