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

describe('HTTP Errors', () => {
  describe('HttpError', () => {
    it('should create error with default values', () => {
      const error = new HttpError('Test error');

      expect(error.message).toBe('Test error');
      expect(error.statusCode).toBe(500);
      expect(error.errorCode).toBe('INTERNAL_ERROR');
      expect(error.isOperational).toBe(true);
      expect(error.name).toBe('HttpError');
    });

    it('should create error with custom values', () => {
      const details = { field: 'email', reason: 'invalid' };
      const error = new HttpError('Custom error', 400, 'CUSTOM_ERROR', false, details);

      expect(error.message).toBe('Custom error');
      expect(error.statusCode).toBe(400);
      expect(error.errorCode).toBe('CUSTOM_ERROR');
      expect(error.isOperational).toBe(false);
      expect(error.details).toEqual(details);
    });

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

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

    it('should include details in API response when provided', () => {
      const details = { field: 'password', issue: 'too weak' };
      const error = new HttpError('Validation error', 400, 'VALIDATION_ERROR', true, details);
      const response = error.toApiResponse();

      expect(response).toEqual({
        success: false,
        error: {
          code: 'VALIDATION_ERROR',
          message: 'Validation error',
          details,
        },
        timestamp: expect.any(String),
      });
    });
  });

  describe('BadRequestError', () => {
    it('should create bad request error with default message', () => {
      const error = new BadRequestError();

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

    it('should create bad request error with custom message', () => {
      const error = new BadRequestError('Custom bad request');

      expect(error.message).toBe('Custom bad request');
      expect(error.statusCode).toBe(400);
      expect(error.errorCode).toBe('BAD_REQUEST');
    });

    it('should include details in bad request error', () => {
      const details = { validationErrors: ['email required'] };
      const error = new BadRequestError('Validation failed', details);

      expect(error.details).toEqual(details);
    });
  });

  describe('UnauthorizedError', () => {
    it('should create unauthorized error with default message', () => {
      const error = new UnauthorizedError();

      expect(error.message).toBe('Authentication required / Yêu cầu xác thực');
      expect(error.statusCode).toBe(401);
      expect(error.errorCode).toBe('UNAUTHORIZED');
      expect(error.isOperational).toBe(true);
    });

    it('should create unauthorized error with custom message', () => {
      const error = new UnauthorizedError('Token expired');

      expect(error.message).toBe('Token expired');
      expect(error.statusCode).toBe(401);
      expect(error.errorCode).toBe('UNAUTHORIZED');
    });
  });

  describe('ForbiddenError', () => {
    it('should create forbidden error with default message', () => {
      const error = new ForbiddenError();

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

    it('should create forbidden error with custom message', () => {
      const error = new ForbiddenError('Insufficient permissions');

      expect(error.message).toBe('Insufficient permissions');
      expect(error.statusCode).toBe(403);
      expect(error.errorCode).toBe('FORBIDDEN');
    });
  });

  describe('NotFoundError', () => {
    it('should create not found error with default resource', () => {
      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');
      expect(error.statusCode).toBe(404);
      expect(error.errorCode).toBe('NOT_FOUND');
      expect(error.isOperational).toBe(true);
    });

    it('should create not found error with custom resource', () => {
      const error = new NotFoundError('User');

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

  describe('ConflictError', () => {
    it('should create conflict error with default message', () => {
      const error = new ConflictError();

      expect(error.message).toBe('Resource conflict / Xung đột tài nguyên');
      expect(error.statusCode).toBe(409);
      expect(error.errorCode).toBe('CONFLICT');
      expect(error.isOperational).toBe(true);
    });

    it('should create conflict error with custom message', () => {
      const error = new ConflictError('Email already exists');

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

  describe('InternalServerError', () => {
    it('should create internal server error with default message', () => {
      const error = new InternalServerError();

      expect(error.message).toBe('Internal server error / Lỗi máy chủ nội bộ');
      expect(error.statusCode).toBe(500);
      expect(error.errorCode).toBe('INTERNAL_ERROR');
      expect(error.isOperational).toBe(false); // Internal errors are not operational
    });

    it('should create internal server error with custom message', () => {
      const error = new InternalServerError('Database connection failed');

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

  describe('Error inheritance', () => {
    it('should maintain instanceof relationship', () => {
      const badRequest = new BadRequestError();
      const unauthorized = new UnauthorizedError();
      const forbidden = new ForbiddenError();
      const notFound = new NotFoundError();
      const conflict = new ConflictError();
      const internal = new InternalServerError();

      expect(badRequest instanceof HttpError).toBe(true);
      expect(unauthorized instanceof HttpError).toBe(true);
      expect(forbidden instanceof HttpError).toBe(true);
      expect(notFound instanceof HttpError).toBe(true);
      expect(conflict instanceof HttpError).toBe(true);
      expect(internal instanceof HttpError).toBe(true);

      expect(badRequest instanceof Error).toBe(true);
      expect(unauthorized instanceof Error).toBe(true);
      expect(forbidden instanceof Error).toBe(true);
      expect(notFound instanceof Error).toBe(true);
      expect(conflict instanceof Error).toBe(true);
      expect(internal instanceof Error).toBe(true);
    });

    it('should have correct constructor names', () => {
      const badRequest = new BadRequestError();
      const unauthorized = new UnauthorizedError();
      const forbidden = new ForbiddenError();
      const notFound = new NotFoundError();
      const conflict = new ConflictError();
      const internal = new InternalServerError();

      expect(badRequest.name).toBe('BadRequestError');
      expect(unauthorized.name).toBe('UnauthorizedError');
      expect(forbidden.name).toBe('ForbiddenError');
      expect(notFound.name).toBe('NotFoundError');
      expect(conflict.name).toBe('ConflictError');
      expect(internal.name).toBe('InternalServerError');
    });
  });
});