import { describe, expect, it } from 'vitest'
import { unwrapAeadKey } from '../src/aead-key.js'
import { deriveMaster, deriveSessionKeys } from '../src/hkdf.js'
import { bytesToHex, hexToBytes } from './helpers.js'
import hkdfVector from './vectors/hkdf.json' with { type: 'json' }

const shared = hexToBytes(hkdfVector.sharedSecret)
const cn = hexToBytes(hkdfVector.clientNonce)
const hn = hexToBytes(hkdfVector.hostNonce)

describe('T6 hkdf direction-split', () => {
  it('KAT: reproduces the frozen master + both direction subkeys', async () => {
    expect(bytesToHex(deriveMaster(shared, cn, hn))).toBe(hkdfVector.master)
    const dk = await deriveSessionKeys(shared, cn, hn, 'aes-256-gcm')
    expect(bytesToHex(unwrapAeadKey(dk.c2h).raw)).toBe(hkdfVector.c2h)
    expect(bytesToHex(unwrapAeadKey(dk.h2c).raw)).toBe(hkdfVector.h2c)
  })

  it('deterministic: same inputs → same keys', async () => {
    const a = await deriveSessionKeys(shared, cn, hn, 'aes-256-gcm')
    const b = await deriveSessionKeys(shared, cn, hn, 'aes-256-gcm')
    expect(bytesToHex(unwrapAeadKey(a.c2h).raw)).toBe(bytesToHex(unwrapAeadKey(b.c2h).raw))
  })

  it('changing EITHER nonce changes the keys (salt = both nonces)', async () => {
    const base = await deriveSessionKeys(shared, cn, hn, 'aes-256-gcm')
    const altC = await deriveSessionKeys(shared, hexToBytes(hkdfVector.hostNonce), hn, 'aes-256-gcm')
    const altH = await deriveSessionKeys(shared, cn, hexToBytes(hkdfVector.clientNonce), 'aes-256-gcm')
    expect(bytesToHex(unwrapAeadKey(base.c2h).raw)).not.toBe(bytesToHex(unwrapAeadKey(altC.c2h).raw))
    expect(bytesToHex(unwrapAeadKey(base.c2h).raw)).not.toBe(bytesToHex(unwrapAeadKey(altH.c2h).raw))
  })

  it('SECURITY direction disjointness: c2h !== h2c, each 32 bytes, neither equals the master', async () => {
    const dk = await deriveSessionKeys(shared, cn, hn, 'aes-256-gcm')
    const c2h = unwrapAeadKey(dk.c2h).raw
    const h2c = unwrapAeadKey(dk.h2c).raw
    const master = deriveMaster(shared, cn, hn)
    expect(c2h.length).toBe(32)
    expect(h2c.length).toBe(32)
    expect(bytesToHex(c2h)).not.toBe(bytesToHex(h2c))
    expect(bytesToHex(c2h)).not.toBe(bytesToHex(master))
    expect(bytesToHex(h2c)).not.toBe(bytesToHex(master))
  })

  it('subkeys carry their direction label so seal binds direction into aad', async () => {
    const dk = await deriveSessionKeys(shared, cn, hn, 'xchacha20-poly1305')
    expect(unwrapAeadKey(dk.c2h).aadLabel).toBe('c2h')
    expect(unwrapAeadKey(dk.h2c).aadLabel).toBe('h2c')
    expect(unwrapAeadKey(dk.c2h).alg).toBe('xchacha20-poly1305')
  })
})
