import { describe, it, expect } from 'vitest';
import {
  hashPassword,
  verifyPassword,
  verifyPasswordOrDummy,
} from '@/lib/auth';

// Pure-function bits of lib/auth.ts (no Prisma, no cookies).

describe('hashPassword / verifyPassword', () => {
  it('verifies a correct password', async () => {
    const hash = await hashPassword('correct horse battery staple');
    expect(await verifyPassword('correct horse battery staple', hash)).toBe(true);
  });

  it('rejects an incorrect password', async () => {
    const hash = await hashPassword('correct horse battery staple');
    expect(await verifyPassword('wrong horse', hash)).toBe(false);
  });

  it('produces different hashes for the same password (salt-randomness)', async () => {
    const a = await hashPassword('same input');
    const b = await hashPassword('same input');
    expect(a).not.toBe(b);
    expect(await verifyPassword('same input', a)).toBe(true);
    expect(await verifyPassword('same input', b)).toBe(true);
  });

  it('produces a bcrypt-format hash starting with $2', async () => {
    const hash = await hashPassword('whatever');
    expect(hash.startsWith('$2')).toBe(true);
  });
});

describe('verifyPasswordOrDummy', () => {
  it('verifies a correct password against a real hash', async () => {
    const hash = await hashPassword('hunter2');
    expect(await verifyPasswordOrDummy('hunter2', hash)).toBe(true);
  });

  it('rejects a wrong password against a real hash', async () => {
    const hash = await hashPassword('hunter2');
    expect(await verifyPasswordOrDummy('wrong', hash)).toBe(false);
  });

  it('returns false without throwing when there is no user (null hash)', async () => {
    expect(await verifyPasswordOrDummy('anything', null)).toBe(false);
  });

  it('still spends bcrypt time on the null-hash path (timing-oracle guard)', async () => {
    // A real cost-10 bcrypt.compare is tens of ms; a path that skipped
    // bcrypt would return in well under 1ms. 5ms is a safe lower bound,
    // so this fails if someone removes the dummy compare.
    const start = Date.now();
    await verifyPasswordOrDummy('anything', null);
    expect(Date.now() - start).toBeGreaterThan(5);
  });
});
