import { describe, expect, it } from 'vitest'
import { readFileSync } from 'node:fs'
import { join } from 'node:path'
import {
  computeEnrollFpr,
  generateIdentity,
  identityFromPrivatePem,
  verifySignature,
} from '../src/keys/identity.js'

describe('AgentIdentity (INV4)', () => {
  it('generates distinct keypairs', () => {
    const a = generateIdentity()
    const b = generateIdentity()
    expect(Buffer.from(a.publicKey).equals(Buffer.from(b.publicKey))).toBe(false)
    expect(a.publicKey.length).toBe(32)
  })

  it('sign/verify round-trips', () => {
    const id = generateIdentity()
    const msg = new TextEncoder().encode('transcript-bytes')
    const sig = id.sign(msg)
    expect(verifySignature(id.publicKey, msg, sig)).toBe(true)
    expect(verifySignature(id.publicKey, new TextEncoder().encode('tampered'), sig)).toBe(false)
  })

  it('enrollFpr is deterministic base64url(SHA-256(pubkey))', () => {
    const id = generateIdentity()
    expect(computeEnrollFpr(id.publicKey)).toBe(id.enrollFpr)
    expect(id.enrollFpr).not.toMatch(/[+/=]/) // base64url alphabet only
  })

  it('reloads the same identity from PEM', () => {
    const id = generateIdentity()
    const pem = id.exportPrivatePkcs8Pem()
    const reloaded = identityFromPrivatePem(pem)
    expect(Buffer.from(reloaded.publicKey).equals(Buffer.from(id.publicKey))).toBe(true)
    expect(reloaded.enrollFpr).toBe(id.enrollFpr)
  })

  it('security: no API returns raw private-key bytes', () => {
    const id = generateIdentity()
    // The only private-key surface is a PEM export for the 0600 keystore and an in-process
    // KeyObject; there is NO Uint8Array/raw-bytes getter for the private key.
    expect('privateKey' in id).toBe(false)
    const src = readFileSync(
      join(import.meta.dirname, '..', 'src', 'keys', 'identity.ts'),
      'utf8',
    )
    // No function exports raw private key bytes onto the network surface.
    expect(src).not.toMatch(/exportPrivateRaw|privateKeyBytes|toRawPrivate/)
  })
})
