import {
  HttpError,
  BadRequestError,
  UnauthorizedError,
  ForbiddenError,
  NotFoundError,
  ConflictError,
  ValidationError,
  InternalServerError,
} from '../http-error';

describe('HttpError Classes', () => {
  describe('HttpError Base Class', () => {
    it('should create HttpError with custom properties', () => {
      const error = new HttpError('Test error', 400, 'TEST_ERROR', true, { field: 'test' });

      expect(error.message).toBe('Test error');
      expect(error.statusCode).toBe(400);
      expect(error.errorCode).toBe('TEST_ERROR');
      expect(error.isOperational).toBe(true);
      expect(error.details).toEqual({ field: 'test' });
    });

    it('should convert to API response format', () => {
      const error = new HttpError('Test error', 400, 'TEST_ERROR', true, { field: 'test' });
      const apiResponse = error.toApiResponse();

      expect(apiResponse).toEqual({
        success: false,
        error: {
          code: 'TEST_ERROR',
          message: 'Test error',
          details: { field: 'test' },
        },
        timestamp: expect.any(String),
      });
    });

    it('should have default values', () => {
      const error = new HttpError('Test error');

      expect(error.statusCode).toBe(500);
      expect(error.errorCode).toBe('INTERNAL_ERROR');
      expect(error.isOperational).toBe(true);
      expect(error.details).toBeUndefined();
    });
  });

  describe('BadRequestError', () => {
    it('should create BadRequestError with correct defaults', () => {
      const error = new BadRequestError('Invalid input');

      expect(error.statusCode).toBe(400);
      expect(error.errorCode).toBe('BAD_REQUEST');
      expect(error.message).toBe('Invalid input');
      expect(error.isOperational).toBe(true);
    });

    it('should use default message', () => {
      const error = new BadRequestError();

      expect(error.message).toBe('Bad Request / Yêu cầu không hợp lệ');
    });
  });

  describe('UnauthorizedError', () => {
    it('should create UnauthorizedError with correct defaults', () => {
      const error = new UnauthorizedError('Invalid credentials');

      expect(error.statusCode).toBe(401);
      expect(error.errorCode).toBe('UNAUTHORIZED');
      expect(error.message).toBe('Invalid credentials');
      expect(error.isOperational).toBe(true);
    });

    it('should use default message', () => {
      const error = new UnauthorizedError();

      expect(error.message).toBe('Authentication required / Yêu cầu xác thực');
    });
  });

  describe('ForbiddenError', () => {
    it('should create ForbiddenError with correct defaults', () => {
      const error = new ForbiddenError('Access denied');

      expect(error.statusCode).toBe(403);
      expect(error.errorCode).toBe('FORBIDDEN');
      expect(error.message).toBe('Access denied');
      expect(error.isOperational).toBe(true);
    });

    it('should use default message', () => {
      const error = new ForbiddenError();

      expect(error.message).toBe('Access denied / Truy cập bị từ chối');
    });
  });

  describe('NotFoundError', () => {
    it('should create NotFoundError with resource name', () => {
      const error = new NotFoundError('User');

      expect(error.statusCode).toBe(404);
      expect(error.errorCode).toBe('NOT_FOUND');
      expect(error.message).toBe('User not found / User không tìm thấy');
      expect(error.isOperational).toBe(true);
    });

    it('should use default resource name', () => {
      const error = new NotFoundError();

      expect(error.message).toBe('Resource / Tài nguyên not found / Resource / Tài nguyên không tìm thấy');
    });
  });

  describe('ConflictError', () => {
    it('should create ConflictError with correct defaults', () => {
      const error = new ConflictError('Resource already exists');

      expect(error.statusCode).toBe(409);
      expect(error.errorCode).toBe('CONFLICT');
      expect(error.message).toBe('Resource already exists');
      expect(error.isOperational).toBe(true);
    });

    it('should use default message', () => {
      const error = new ConflictError();

      expect(error.message).toBe('Resource conflict / Xung đột tài nguyên');
    });
  });

  describe('ValidationError', () => {
    it('should create ValidationError with correct defaults', () => {
      const error = new ValidationError('Invalid email format');

      expect(error.statusCode).toBe(422);
      expect(error.errorCode).toBe('VALIDATION_ERROR');
      expect(error.message).toBe('Invalid email format');
      expect(error.isOperational).toBe(true);
    });

    it('should use default message', () => {
      const error = new ValidationError();

      expect(error.message).toBe('Validation failed / Validation thất bại');
    });
  });

  describe('InternalServerError', () => {
    it('should create InternalServerError with correct defaults', () => {
      const error = new InternalServerError('Database connection failed');

      expect(error.statusCode).toBe(500);
      expect(error.errorCode).toBe('INTERNAL_ERROR');
      expect(error.message).toBe('Database connection failed');
      expect(error.isOperational).toBe(false); // Programming error
    });

    it('should use default message', () => {
      const error = new InternalServerError();

      expect(error.message).toBe('Internal server error / Lỗi máy chủ nội bộ');
    });
  });

  describe('Error Inheritance', () => {
    it('should maintain instanceof relationships', () => {
      const badRequest = new BadRequestError();
      const validation = new ValidationError();

      expect(badRequest instanceof HttpError).toBe(true);
      expect(badRequest instanceof BadRequestError).toBe(true);
      expect(badRequest instanceof Error).toBe(true);

      expect(validation instanceof HttpError).toBe(true);
      expect(validation instanceof ValidationError).toBe(true);
      expect(validation instanceof Error).toBe(true);
    });

    it('should have correct constructor names', () => {
      const badRequest = new BadRequestError();
      const notFound = new NotFoundError();

      expect(badRequest.constructor.name).toBe('BadRequestError');
      expect(notFound.constructor.name).toBe('NotFoundError');
    });
  });

  describe('Stack Traces', () => {
    it('should capture stack traces', () => {
      const error = new HttpError('Test error');

      expect(error.stack).toBeDefined();
      expect(error.stack).toContain('HttpError');
      expect(error.stack).toContain('Test error');
    });
  });
});