import { describe, expect, it } from 'vitest'
import { getWebCrypto, randomBytes, timingSafeEqual } from '../src/crypto-provider.js'
import { CryptoUnavailableError } from '../src/errors.js'

describe('T1 crypto-provider', () => {
  it('getWebCrypto returns a SubtleCrypto in the node vitest environment', () => {
    const subtle = getWebCrypto()
    expect(typeof subtle.digest).toBe('function')
    expect(typeof subtle.generateKey).toBe('function')
  })

  it('randomBytes(32) has length 32, differs across calls, and is not all-zero', () => {
    const a = randomBytes(32)
    const b = randomBytes(32)
    expect(a.length).toBe(32)
    expect(bytesEqual(a, b)).toBe(false)
    expect(a.every((x) => x === 0)).toBe(false)
  })

  it('randomBytes rejects a non-integer / negative length (fail-fast)', () => {
    expect(() => randomBytes(-1)).toThrow(CryptoUnavailableError)
    expect(() => randomBytes(1.5)).toThrow(CryptoUnavailableError)
  })

  describe('timingSafeEqual', () => {
    it('equal buffers → true', () => {
      expect(timingSafeEqual(new Uint8Array([1, 2, 3]), new Uint8Array([1, 2, 3]))).toBe(true)
    })
    it('single-bit flip → false', () => {
      expect(timingSafeEqual(new Uint8Array([1, 2, 3]), new Uint8Array([1, 2, 2]))).toBe(false)
    })
    it('length mismatch → false (no short-circuit ordering)', () => {
      expect(timingSafeEqual(new Uint8Array([1, 2, 3]), new Uint8Array([1, 2]))).toBe(false)
      expect(timingSafeEqual(new Uint8Array([1, 2]), new Uint8Array([1, 2, 3]))).toBe(false)
    })
    it('empty buffers → true', () => {
      expect(timingSafeEqual(new Uint8Array(0), new Uint8Array(0))).toBe(true)
    })
  })
})

function bytesEqual(a: Uint8Array, b: Uint8Array): boolean {
  if (a.length !== b.length) return false
  return a.every((x, i) => x === b[i])
}
