import { describe, expect, it } from 'vitest';
import { hashPin, newLock, newSalt, verifyPin } from './pin';

describe('hashPin', () => {
  it('is deterministic for the same pin and salt', async () => {
    const salt = 'fixedsalt';
    expect(await hashPin('1234', salt)).toBe(await hashPin('1234', salt));
  });

  it('differs when the salt differs', async () => {
    expect(await hashPin('1234', 'saltA')).not.toBe(await hashPin('1234', 'saltB'));
  });

  it('differs when the pin differs', async () => {
    const salt = 'fixedsalt';
    expect(await hashPin('1234', salt)).not.toBe(await hashPin('4321', salt));
  });
});

describe('newSalt', () => {
  it('returns a non-empty value', () => {
    expect(newSalt().length).toBeGreaterThan(0);
  });

  it('returns a fresh value each call', () => {
    expect(newSalt()).not.toBe(newSalt());
  });
});

describe('newLock / verifyPin', () => {
  it('produces a lock that verifies its own pin', async () => {
    const lock = await newLock('1234');
    expect(lock.hash.length).toBeGreaterThan(0);
    expect(lock.salt.length).toBeGreaterThan(0);
    expect(await verifyPin('1234', lock)).toBe(true);
  });

  it('rejects a wrong pin', async () => {
    const lock = await newLock('1234');
    expect(await verifyPin('0000', lock)).toBe(false);
  });

  it('salts each lock independently (same pin, different hashes)', async () => {
    const a = await newLock('1234');
    const b = await newLock('1234');
    expect(a.salt).not.toBe(b.salt);
    expect(a.hash).not.toBe(b.hash);
  });
});
