import { describe, it, expect, beforeEach } from 'vitest';
import type Database from 'better-sqlite3';
import { allocateMemberNumber, createUser, updateUserRole, deactivateUser } from '../src/lib/db.js';

const db = (globalThis as typeof globalThis & { __bifrost_db?: Database.Database }).__bifrost_db!;

function makeUser(name: string, role: 'pilot' | 'cab' | 'fenja' = 'pilot'): number {
  return createUser({ email: `${name}@x.test`, password_hash: 'x', name, organisation: 'TestOrg', role });
}

beforeEach(() => {
  db.exec(`
    DELETE FROM votes;
    DELETE FROM pulses;
    DELETE FROM activity;
    DELETE FROM dispatches;
    DELETE FROM users;
  `);
});

describe('allocateMemberNumber', () => {
  it('allocates 1 for the first cab user and sequential numbers thereafter', () => {
    const a = makeUser('alice', 'cab');
    const b = makeUser('bob',   'cab');
    const c = makeUser('cara',  'cab');
    expect(db.prepare('SELECT member_number FROM users WHERE id=?').get(a)).toEqual({ member_number: 1 });
    expect(db.prepare('SELECT member_number FROM users WHERE id=?').get(b)).toEqual({ member_number: 2 });
    expect(db.prepare('SELECT member_number FROM users WHERE id=?').get(c)).toEqual({ member_number: 3 });
  });

  it('is idempotent — calling allocate on a user who already has a number returns the same one', () => {
    const a = makeUser('alice', 'cab');
    const first = (db.prepare('SELECT member_number AS n FROM users WHERE id=?').get(a) as { n: number }).n;
    const reAllocated = allocateMemberNumber(a);
    expect(reAllocated).toBe(first);
  });

  it('never reuses: deactivating a holder does not free their number', () => {
    const a = makeUser('alice', 'cab'); // #1
    const b = makeUser('bob',   'cab'); // #2
    deactivateUser(a);
    const c = makeUser('cara',  'cab'); // expects #3, not #1
    expect((db.prepare('SELECT member_number AS n FROM users WHERE id=?').get(c) as { n: number }).n).toBe(3);
  });

  it('does not allocate when a non-cab user is created', () => {
    const a = makeUser('alice', 'pilot');
    expect(db.prepare('SELECT member_number FROM users WHERE id=?').get(a)).toEqual({ member_number: null });
  });

  it('allocates on role transition pilot → cab and only the first time', () => {
    const a = makeUser('alice', 'pilot');
    const r1 = updateUserRole(a, 'cab');
    expect(r1.allocated).toBe(1);
    // transition back and forth must not change the number
    updateUserRole(a, 'pilot');
    const r2 = updateUserRole(a, 'cab');
    expect(r2.allocated).toBeNull();
    expect((db.prepare('SELECT member_number AS n FROM users WHERE id=?').get(a) as { n: number }).n).toBe(1);
  });
});
