import { describe, expect, it } from 'vitest';
import {
  BadRequestError,
  ConflictError,
  ForbiddenError,
  NotFoundError,
  ServiceError,
  TooManyRequestsError,
  UnauthorizedError,
} from '../index.js';

describe('ServiceError', () => {
  it('sets statusCode and message', () => {
    const err = new ServiceError(500, 'boom');
    expect(err.statusCode).toBe(500);
    expect(err.message).toBe('boom');
    expect(err).toBeInstanceOf(Error);
    expect(err).toBeInstanceOf(ServiceError);
  });

  it('supports optional details', () => {
    const err = new ServiceError(500, 'boom', { field: 'name' });
    expect(err.details).toEqual({ field: 'name' });
  });
});

describe('HTTP error classes', () => {
  const cases: [string, new () => ServiceError, number, string][] = [
    ['BadRequestError', BadRequestError, 400, 'Bad request'],
    ['UnauthorizedError', UnauthorizedError, 401, 'Unauthorized'],
    ['ForbiddenError', ForbiddenError, 403, 'Forbidden'],
    ['NotFoundError', NotFoundError, 404, 'Not found'],
    ['ConflictError', ConflictError, 409, 'Conflict'],
    ['TooManyRequestsError', TooManyRequestsError, 429, 'Too many requests'],
  ];

  for (const [name, Ctor, expectedStatus, expectedMessage] of cases) {
    it(`${name} has status ${expectedStatus}`, () => {
      const err = new Ctor();
      expect(err.statusCode).toBe(expectedStatus);
      expect(err.message).toBe(expectedMessage);
      expect(err).toBeInstanceOf(ServiceError);
    });
  }

  it('accepts custom message', () => {
    const err = new NotFoundError('User not found');
    expect(err.message).toBe('User not found');
    expect(err.statusCode).toBe(404);
  });

  it('accepts details', () => {
    const err = new TooManyRequestsError('Rate limited', { retryAfter: 60 });
    expect(err.details).toEqual({ retryAfter: 60 });
  });
});
