import { describe, it, expect, beforeAll } from 'vitest';
import { createDefaults, getByUserId, updateLimits, getMonthlyTokens, getMonthlyCost } from './rateLimitRepo.js';
import { getAdapter } from '../driver.js';

describe('rateLimitRepo', () => {
  let testUserId;

  beforeAll(async () => {
    // Create a test user directly in the DB for FK reference
    const db = await getAdapter();
    const { v4: uuidv4 } = await import('uuid');
    testUserId = uuidv4();
    db.run(
      `INSERT INTO users(id, username, password_hash, role, is_active, is_approved, created_at) VALUES(?, ?, ?, 'user', 1, 1, ?)`,
      [testUserId, 'rl_test_user', 'hash', new Date().toISOString()]
    );
  });

  it('createDefaults creates row with correct default values', async () => {
    const limits = await createDefaults(testUserId);
    expect(limits).not.toBeNull();
    expect(limits.rtpMinute).toBe(100);
    expect(limits.rtpDay).toBe(100000);
    expect(limits.tokenLimitMonthly).toBe(1000000);
    expect(limits.creditLimit).toBe(5.0);
    expect(limits.maxConcurrent).toBe(5);
    expect(limits.userId).toBe(testUserId);
    expect(limits.id).toBeTypeOf('string');
  });

  it('getByUserId returns limits object for existing user', async () => {
    const limits = await getByUserId(testUserId);
    expect(limits).not.toBeNull();
    expect(limits.userId).toBe(testUserId);
    expect(limits.rtpMinute).toBe(100);
  });

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

  it('updateLimits partial update preserves other fields', async () => {
    await updateLimits(testUserId, { rtpMinute: 500, maxConcurrent: 10 });
    const limits = await getByUserId(testUserId);
    expect(limits.rtpMinute).toBe(500);
    expect(limits.maxConcurrent).toBe(10);
    expect(limits.rtpDay).toBe(100000);    // unchanged
    expect(limits.tokenLimitMonthly).toBe(1000000); // unchanged
    expect(limits.creditLimit).toBe(5.0);  // unchanged
  });

  it('updateLimits rejects invalid field names', async () => {
    await updateLimits(testUserId, { invalidField: 999 });
    const limits = await getByUserId(testUserId);
    // invalidField should not have been applied
    expect(limits).not.toHaveProperty('invalidField');
  });

  it('getMonthlyTokens returns 0 for user with no usage', async () => {
    const tokens = await getMonthlyTokens(testUserId);
    expect(tokens).toBe(0);
  });

  it('getMonthlyCost returns 0 for user with no usage', async () => {
    const cost = await getMonthlyCost(testUserId);
    expect(cost).toBe(0);
  });

  it('createDefaults throws on duplicate userId', async () => {
    await expect(createDefaults(testUserId)).rejects.toThrow();
  });
});
