import { ErrorCode, ERROR_CODE_TO_STATUS, getStatusFromErrorCode, isOperationalError } from '../error-codes';

describe('Error Codes', () => {
  describe('ErrorCode Enum', () => {
    it('should contain all expected error codes', () => {
      expect(ErrorCode.UNAUTHORIZED).toBe('AUTH_001');
      expect(ErrorCode.NOT_FOUND).toBe('RESOURCE_001');
      expect(ErrorCode.VALIDATION_ERROR).toBe('VALIDATION_001');
      expect(ErrorCode.INTERNAL_ERROR).toBe('SYS_001');
      expect(ErrorCode.DATABASE_ERROR).toBe('DB_001');
    });
  });

  describe('ERROR_CODE_TO_STATUS mapping', () => {
    it('should map authentication errors correctly', () => {
      expect(ERROR_CODE_TO_STATUS[ErrorCode.UNAUTHORIZED]).toBe(401);
      expect(ERROR_CODE_TO_STATUS[ErrorCode.FORBIDDEN]).toBe(403);
      expect(ERROR_CODE_TO_STATUS[ErrorCode.INVALID_TOKEN]).toBe(401);
    });

    it('should map validation errors correctly', () => {
      expect(ERROR_CODE_TO_STATUS[ErrorCode.VALIDATION_ERROR]).toBe(422);
      expect(ERROR_CODE_TO_STATUS[ErrorCode.INVALID_FORMAT]).toBe(422);
      expect(ERROR_CODE_TO_STATUS[ErrorCode.REQUIRED_FIELD]).toBe(422);
    });

    it('should map resource errors correctly', () => {
      expect(ERROR_CODE_TO_STATUS[ErrorCode.NOT_FOUND]).toBe(404);
      expect(ERROR_CODE_TO_STATUS[ErrorCode.ALREADY_EXISTS]).toBe(409);
      expect(ERROR_CODE_TO_STATUS[ErrorCode.CONFLICT]).toBe(409);
    });

    it('should map system errors correctly', () => {
      expect(ERROR_CODE_TO_STATUS[ErrorCode.INTERNAL_ERROR]).toBe(500);
      expect(ERROR_CODE_TO_STATUS[ErrorCode.RATE_LIMIT_EXCEEDED]).toBe(429);
      expect(ERROR_CODE_TO_STATUS[ErrorCode.SERVICE_UNAVAILABLE]).toBe(503);
    });

    it('should map database errors correctly', () => {
      expect(ERROR_CODE_TO_STATUS[ErrorCode.DATABASE_ERROR]).toBe(500);
      expect(ERROR_CODE_TO_STATUS[ErrorCode.CONNECTION_ERROR]).toBe(503);
      expect(ERROR_CODE_TO_STATUS[ErrorCode.CONSTRAINT_VIOLATION]).toBe(422);
    });
  });

  describe('getStatusFromErrorCode', () => {
    it('should return correct status for known error codes', () => {
      expect(getStatusFromErrorCode(ErrorCode.NOT_FOUND)).toBe(404);
      expect(getStatusFromErrorCode(ErrorCode.UNAUTHORIZED)).toBe(401);
      expect(getStatusFromErrorCode(ErrorCode.VALIDATION_ERROR)).toBe(422);
      expect(getStatusFromErrorCode(ErrorCode.INTERNAL_ERROR)).toBe(500);
    });

    it('should return 500 for unknown error codes', () => {
      expect(getStatusFromErrorCode('UNKNOWN_ERROR' as ErrorCode)).toBe(500);
    });
  });

  describe('isOperationalError', () => {
    it('should identify operational errors correctly', () => {
      // These should be operational (true)
      expect(isOperationalError(ErrorCode.UNAUTHORIZED)).toBe(true);
      expect(isOperationalError(ErrorCode.NOT_FOUND)).toBe(true);
      expect(isOperationalError(ErrorCode.VALIDATION_ERROR)).toBe(true);
      expect(isOperationalError(ErrorCode.CONFLICT)).toBe(true);
      expect(isOperationalError(ErrorCode.RATE_LIMIT_EXCEEDED)).toBe(true);
    });

    it('should identify programming errors correctly', () => {
      // These should NOT be operational (false)
      expect(isOperationalError(ErrorCode.INTERNAL_ERROR)).toBe(false);
      expect(isOperationalError(ErrorCode.DATABASE_ERROR)).toBe(false);
      expect(isOperationalError(ErrorCode.CONFIGURATION_ERROR)).toBe(false);
      expect(isOperationalError(ErrorCode.FEATURE_CONFIG_INVALID)).toBe(false);
    });

    it('should handle edge cases', () => {
      expect(isOperationalError('UNKNOWN_ERROR' as ErrorCode)).toBe(false);
    });
  });

  describe('Error Code Coverage', () => {
    it('should have status mapping for all error codes', () => {
      const allErrorCodes = Object.values(ErrorCode);
      allErrorCodes.forEach(code => {
        expect(ERROR_CODE_TO_STATUS[code]).toBeDefined();
        expect(typeof ERROR_CODE_TO_STATUS[code]).toBe('number');
        expect(ERROR_CODE_TO_STATUS[code]).toBeGreaterThanOrEqual(100);
        expect(ERROR_CODE_TO_STATUS[code]).toBeLessThan(600);
      });
    });

    it('should have operational classification for all error codes', () => {
      const allErrorCodes = Object.values(ErrorCode);
      allErrorCodes.forEach(code => {
        expect(typeof isOperationalError(code)).toBe('boolean');
      });
    });
  });

  describe('Error Code Categories', () => {
    it('should have consistent naming patterns', () => {
      const allErrorCodes = Object.values(ErrorCode);

      // Check that all codes follow pattern: CATEGORY_XXX
      allErrorCodes.forEach(code => {
        expect(code).toMatch(/^[A-Z]+_\d{3}$/);
      });
    });

    it('should have unique error codes', () => {
      const allErrorCodes = Object.values(ErrorCode);
      const uniqueCodes = new Set(allErrorCodes);
      expect(uniqueCodes.size).toBe(allErrorCodes.length);
    });

    it('should have reasonable HTTP status codes', () => {
      const allStatuses = Object.values(ERROR_CODE_TO_STATUS);
      allStatuses.forEach(status => {
        expect(status).toBeGreaterThanOrEqual(200);
        expect(status).toBeLessThan(600);
      });
    });
  });
});