internal void RotateOnAxis(
            Transform target,
            float angle,
            float duration,
            RotateMode rotateMode,
            SpaceType spaceType,
            EaseType easeType,
            LoopType loopType,
            int loopCount,
            Action onStart,
            Action onComplete,
            bool useTweenHandle,
            out ITweenHandle tweenHandle)
        {
            Assert.IsTrue(rotateMode != RotateMode.XYZ, RuntimeConstants.INVALID_ROTATE_MODE);

            tweenHandle = null;

            _transforms.Add(target);
            _transformAccessArray.Add(target);

            var rotateType = JTweenTools.GetTweenSpaceTypeFromRotateMode(rotateMode);

            _tweenStates.Add(new TweenTransformState
            {
                state         = useTweenHandle ? HANDLE_START_PAUSED : NO_HANDLE_START,
                transformType = TweenTransformType.Rotation,
                spaceType     = spaceType == SpaceType.World
                                        ? TweenSpaceType.WorldRotation | rotateType
                                        : TweenSpaceType.LocalRotation | rotateType
            });
            _tweenPositions.Add(new TweenFloat3());

            var eulerAngles = spaceType == SpaceType.World
                                ? target.eulerAngles
                                : target.localEulerAngles;

            _tweenRotations.Add(new TweenRotation
            {
                from  = new quaternion(eulerAngles.x, eulerAngles.y, eulerAngles.z, 0),
                angle = angle
            });
            _tweenScales.Add(new TweenFloat3());
            _tweenPositionLifetimes.Add(new TweenLifetime());
            _tweenRotationLifetimes.Add(new TweenLifetime
            {
                duration          = Mathf.Max(0, duration),
                easeType          = easeType,
                loopType          = loopType,
                loopCount         = (short)Mathf.Clamp(loopCount, -1, short.MaxValue),
                originalLoopCount = (short)Mathf.Clamp(loopCount, -1, short.MaxValue)
            });
            _tweenScaleLifetimes.Add(new TweenLifetime());
            var hasEvents = onStart != null || onComplete != null;

            if (useTweenHandle || hasEvents)
            {
                var availableTweenHandle = GetNextAvailableTweenHandle();
                availableTweenHandle.state = useTweenHandle ? HANDLE_START_PAUSED : NO_HANDLE_START;
                if (onStart != null)
                {
                    availableTweenHandle.AddOnStartedListener(onStart);
                }

                if (onComplete != null)
                {
                    availableTweenHandle.AddOnCompletedListener(onComplete);
                }

                _tweenHandles.Add(availableTweenHandle);

                // Only populate the out parameter if explicitly called out for.
                if (useTweenHandle)
                {
                    tweenHandle = availableTweenHandle;
                }
            }
            else
            {
                _tweenHandles.Add(null);
            }
        }