import { describe, expect, it } from 'vitest'
import { hashPassword, verifyPassword } from './password'

describe('hashPassword / verifyPassword', () => {
  it('verifies a freshly hashed password', async () => {
    const stored = await hashPassword('correct horse battery')
    await expect(verifyPassword('correct horse battery', stored)).resolves.toBe(true)
  })

  it('rejects a wrong password', async () => {
    const stored = await hashPassword('correct horse battery')
    await expect(verifyPassword('wrong password', stored)).resolves.toBe(false)
  })

  it('returns false for malformed stored strings without throwing', async () => {
    await expect(verifyPassword('pw', '')).resolves.toBe(false)
    await expect(verifyPassword('pw', 'nope')).resolves.toBe(false)
    await expect(verifyPassword('pw', 'pbkdf2sha512$100000$only')).resolves.toBe(false)
  })

  it('produces distinct salts for the same password', async () => {
    const plain = 'same-password'
    const a = await hashPassword(plain)
    const b = await hashPassword(plain)
    expect(a).not.toBe(b)
    await expect(verifyPassword(plain, a)).resolves.toBe(true)
    await expect(verifyPassword(plain, b)).resolves.toBe(true)
  })

  it('verifies a hash encoded with a lower iteration count from the stored string', async () => {
    const plain = 'legacy-iter-password'
    const salt = crypto.getRandomValues(new Uint8Array(16))
    const saltB64 = btoa(String.fromCharCode(...salt))
    const keyMaterial = await crypto.subtle.importKey(
      'raw',
      new TextEncoder().encode(plain),
      'PBKDF2',
      false,
      ['deriveBits'],
    )
    const bits = await crypto.subtle.deriveBits(
      { name: 'PBKDF2', salt, iterations: 10_000, hash: 'SHA-512' },
      keyMaterial,
      512,
    )
    const hashB64 = btoa(String.fromCharCode(...new Uint8Array(bits)))
    const stored = `pbkdf2sha512$10000$${saltB64}$${hashB64}`
    await expect(verifyPassword(plain, stored)).resolves.toBe(true)
  })
})
