// Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2024 Kybernetik //

#if ! UNITY_EDITOR
#pragma warning disable CS0618 // Type or member is obsolete (for Animancer Events in Animancer Lite).
#endif
#pragma warning disable CS0649 // Field is never assigned to, and will always have its default value.

using Animancer.Units;
using UnityEngine;

namespace Animancer.Samples.Events
{
    /// <summary>Manages a character with the ability to hit a golf ball.</summary>
    /// 
    /// <remarks>
    /// <strong>Sample:</strong>
    /// <see href="https://kybernetik.com.au/animancer/docs/samples/events/golf">
    /// Golf Events</see>
    /// </remarks>
    /// 
    /// https://kybernetik.com.au/animancer/api/Animancer.Samples.Events/Golfer
    /// 
    [AddComponentMenu(Strings.SamplesMenuPrefix + "Golf Events - Golfer")]
    [AnimancerHelpUrl(typeof(Golfer))]
    public class Golfer : MonoBehaviour
    {
        /************************************************************************************************************************/

        private static readonly StringReference HitEventName = "Hit";

        [SerializeField] private AnimancerComponent _Animancer;
        [SerializeField] private ClipTransition _Ready;
        [SerializeField, EventNames] private ClipTransition _Swing;
        [SerializeField] private Rigidbody _Ball;
        [SerializeField] private Vector3 _HitVelocity = new(0, 10, 10);
        [SerializeField, Meters] private float _BallReturnHeight = -10;

        private Vector3 _BallStartPosition;

        /************************************************************************************************************************/

        protected virtual void Awake()
        {
            _BallStartPosition = _Ball.position;
            _Ball.isKinematic = true;

            _Swing.Events.SetCallback(HitEventName, HitBall);
            _Swing.Events.OnEnd = EndSwing;

            _Animancer.Play(_Ready);
        }

        /************************************************************************************************************************/

        private void ResetBall()
        {
            _Ball.isKinematic = true;
            _Ball.position = _BallStartPosition;
        }

        /************************************************************************************************************************/

        protected virtual void Update()
        {
            if (_Ball.isKinematic)
            {
                if (SampleInput.LeftMouseDown)
                {
                    _Animancer.Play(_Swing);
                }
            }
            else if (_Ball.position.y < _BallReturnHeight)
            {
                ResetBall();
            }
        }

        /************************************************************************************************************************/

        private void HitBall()
        {
            _Ball.isKinematic = false;

#if UNITY_6000_0_OR_NEWER
            _Ball.linearVelocity = _HitVelocity;
#else
            _Ball.velocity = _HitVelocity;
#endif
        }

        /************************************************************************************************************************/

        private void EndSwing()
        {
            // Since the swing animation is ending early, we want it to calculate the fade duration to fade out over
            // the remainder of that animation instead of just using the value specified by the _Ready transition.
            float fadeDuration = AnimancerEvent.GetFadeOutDuration();
            _Animancer.Play(_Ready, fadeDuration);
        }

        /************************************************************************************************************************/
    }
}
