import { ValidationPipe } from '@nestjs/common';
import { AdminAuditQueryDto, MAX_LIMIT } from './audit-query.dto';

/**
 * Spec exercises the DTO through Nest's `ValidationPipe` with the
 * same options the BFF wires in `main.ts` (`whitelist`,
 * `forbidNonWhitelisted`, `transform`) — the test is therefore a
 * close stand-in for how the controller will see the parsed query
 * at runtime.
 */
const pipe = new ValidationPipe({
  whitelist: true,
  forbidNonWhitelisted: true,
  transform: true,
});

async function transform(input: unknown): Promise<AdminAuditQueryDto> {
  return (await pipe.transform(input, {
    type: 'query',
    metatype: AdminAuditQueryDto,
  })) as AdminAuditQueryDto;
}

describe('AdminAuditQueryDto', () => {
  it('accepts an empty query (every filter is optional)', async () => {
    await expect(transform({})).resolves.toEqual({});
  });

  it('coerces numeric strings (URL query format) into numbers', async () => {
    const out = await transform({ limit: '25', offset: '100' });
    expect(out.limit).toBe(25);
    expect(out.offset).toBe(100);
  });

  it('rejects a limit above MAX_LIMIT', async () => {
    await expect(transform({ limit: String(MAX_LIMIT + 1) })).rejects.toThrow();
  });

  it('rejects a negative offset', async () => {
    await expect(transform({ offset: '-1' })).rejects.toThrow();
  });

  it('rejects a non-integer limit', async () => {
    await expect(transform({ limit: '12.5' })).rejects.toThrow();
  });

  it('accepts each valid audience enum value', async () => {
    await expect(transform({ audience: 'workforce' })).resolves.toMatchObject({
      audience: 'workforce',
    });
    await expect(transform({ audience: 'customer' })).resolves.toMatchObject({
      audience: 'customer',
    });
  });

  it('rejects an unknown audience', async () => {
    await expect(transform({ audience: 'visitor' })).rejects.toThrow();
  });

  it('accepts each valid outcome enum value', async () => {
    for (const outcome of ['success', 'failure', 'denied']) {
      await expect(transform({ outcome })).resolves.toMatchObject({ outcome });
    }
  });

  it('rejects an ISO-8601 createdAtFrom that is not well-formed', async () => {
    await expect(transform({ createdAtFrom: 'not-a-date' })).rejects.toThrow();
  });

  it('rejects an unknown query key (forbidNonWhitelisted)', async () => {
    await expect(transform({ password: 'leak' })).rejects.toThrow();
  });

  it('rejects an over-long eventType (MaxLength guard)', async () => {
    await expect(transform({ eventType: 'a'.repeat(129) })).rejects.toThrow();
  });
});
