import { describe, it, expect, beforeAll } from 'vitest';
import { createUser, findByUsername, findById, listUsers, updateApproval, updateRole, updateActive, getPasswordHash, deleteUser } from './usersRepo.js';
import { getAdapter } from '../driver.js';

describe('usersRepo', () => {
  let testUser;

  beforeAll(async () => {
    // Clean up stale test users from previous runs (shared persistent test DB)
    const db = await getAdapter();
    db.run("DELETE FROM users WHERE username IN ('testuser1', 'testuser2', 'todelete')");
  });

  it('createUser creates a user with correct defaults', async () => {
    testUser = await createUser('testuser1', 'hashed_pw_123');
    expect(testUser.id).toBeTypeOf('string');
    expect(testUser.id.length).toBeGreaterThan(10);
    expect(testUser.username).toBe('testuser1');
    expect(testUser.role).toBe('user');
    expect(testUser.is_active).toBe(true);
    expect(testUser.is_approved).toBe(false);
  });

  it('findByUsername finds existing user', async () => {
    const found = await findByUsername('testuser1');
    expect(found).not.toBeNull();
    expect(found.id).toBe(testUser.id);
    expect(found.username).toBe('testuser1');
  });

  it('findByUsername returns null for non-existent', async () => {
    const found = await findByUsername('nonexistent_user');
    expect(found).toBeNull();
  });

  it('findById finds existing user', async () => {
    const found = await findById(testUser.id);
    expect(found).not.toBeNull();
    expect(found.username).toBe('testuser1');
  });

  it('findById returns null for non-existent', async () => {
    const found = await findById('non-existent-id');
    expect(found).toBeNull();
  });

  it('listUsers returns all users', async () => {
    await createUser('testuser2', 'pw2');
    const users = await listUsers();
    expect(users.length).toBeGreaterThanOrEqual(2);
    expect(users.find(u => u.username === 'testuser1')).toBeTruthy();
    expect(users.find(u => u.username === 'testuser2')).toBeTruthy();
  });

  it('updateApproval changes is_approved', async () => {
    await updateApproval(testUser.id, true);
    const updated = await findById(testUser.id);
    expect(updated.is_approved).toBe(true);

    await updateApproval(testUser.id, false);
    const reverted = await findById(testUser.id);
    expect(reverted.is_approved).toBe(false);
  });

  it('updateRole changes role', async () => {
    await updateRole(testUser.id, 'admin');
    const updated = await findById(testUser.id);
    expect(updated.role).toBe('admin');

    await updateRole(testUser.id, 'user');
    const reverted = await findById(testUser.id);
    expect(reverted.role).toBe('user');
  });

  it('updateActive toggles active state', async () => {
    await updateActive(testUser.id, false);
    const updated = await findById(testUser.id);
    expect(updated.is_active).toBe(false);

    await updateActive(testUser.id, true);
    const reverted = await findById(testUser.id);
    expect(reverted.is_active).toBe(true);
  });

  it('duplicate username throws error', async () => {
    await expect(createUser('testuser1', 'another_hash')).rejects.toThrow();
  });

  it('deleteUser removes user', async () => {
    const tempUser = await createUser('todelete', 'pw');
    const result = await deleteUser(tempUser.id);
    expect(result).toBe(true);
    const found = await findById(tempUser.id);
    expect(found).toBeNull();
  });

  it('deleteUser returns false for non-existent', async () => {
    const result = await deleteUser('non-existent-id');
    expect(result).toBe(false);
  });

  it('getPasswordHash returns hash for existing user', async () => {
    const hash = await getPasswordHash('testuser1');
    expect(hash).toBe('hashed_pw_123');
  });

  it('getPasswordHash returns null for non-existent user', async () => {
    const hash = await getPasswordHash('nonexistent_user');
    expect(hash).toBeNull();
  });
});
