using UnityEngine.Events;
using UnityEngine.XR.Interaction.Toolkit;
namespace UnityEngine.XR.Content.Interaction
{
    /// 
    /// An interactable that can be pressed by a direct interactor
    /// 
    public class XRGripButton : XRBaseInteractable
    {
        [SerializeField]
        [Tooltip("The object that is visually pressed down")]
        Transform m_Button = null;
        [SerializeField]
        [Tooltip("The distance the button can be pressed")]
        float m_PressDistance = 0.1f;
        [SerializeField]
        [Tooltip("Treat this button like an on/off toggle")]
        bool m_ToggleButton = false;
        [SerializeField]
        [Tooltip("Events to trigger when the button is pressed")]
        UnityEvent m_OnPress;
        [SerializeField]
        [Tooltip("Events to trigger when the button is released")]
        UnityEvent m_OnRelease;
        bool m_Hovered = false;
        bool m_Selected = false;
        bool m_Toggled = false;
        /// 
        /// The object that is visually pressed down
        /// 
        public Transform button
        {
            get => m_Button;
            set => m_Button = value;
        }
        /// 
        /// The distance the button can be pressed
        /// 
        public float pressDistance
        {
            get => m_PressDistance;
            set => m_PressDistance = value;
        }
        /// 
        /// Events to trigger when the button is pressed
        /// 
        public UnityEvent onPress => m_OnPress;
        /// 
        /// Events to trigger when the button is released
        /// 
        public UnityEvent onRelease => m_OnRelease;
        void Start()
        {
            SetButtonHeight(0.0f);
        }
        protected override void OnEnable()
        {
            base.OnEnable();
            if (m_ToggleButton)
                selectEntered.AddListener(StartTogglePress);
            else
            {
                selectEntered.AddListener(StartPress);
                selectExited.AddListener(EndPress);
                hoverEntered.AddListener(StartHover);
                hoverExited.AddListener(EndHover);
            }
        }
        protected override void OnDisable()
        {
            if (m_ToggleButton)
                selectEntered.RemoveListener(StartTogglePress);
            else
            {
                selectEntered.RemoveListener(StartPress);
                selectExited.RemoveListener(EndPress);
                hoverEntered.RemoveListener(StartHover);
                hoverExited.RemoveListener(EndHover);
                base.OnDisable();
            }
        }
        void StartTogglePress(SelectEnterEventArgs args)
        {
            m_Toggled = !m_Toggled;
            if (m_Toggled)
            {
                SetButtonHeight(-m_PressDistance);
                m_OnPress.Invoke();
            }
            else
            {
                SetButtonHeight(0.0f);
                m_OnRelease.Invoke();
            }
        }
        void StartPress(SelectEnterEventArgs args)
        {
            SetButtonHeight(-m_PressDistance);
            m_OnPress.Invoke();
            m_Selected = true;
        }
        void EndPress(SelectExitEventArgs args)
        {
            if (m_Hovered)
                m_OnRelease.Invoke();
            SetButtonHeight(0.0f);
            m_Selected = false;
        }
        void StartHover(HoverEnterEventArgs args)
        {
            m_Hovered = true;
            if (m_Selected)
                SetButtonHeight(-m_PressDistance);
        }
        void EndHover(HoverExitEventArgs args)
        {
            m_Hovered = false;
            SetButtonHeight(0.0f);
        }
        void SetButtonHeight(float height)
        {
            if (m_Button == null)
                return;
            Vector3 newPosition = m_Button.localPosition;
            newPosition.y = height;
            m_Button.localPosition = newPosition;
        }
        void OnDrawGizmosSelected()
        {
            var pressStartPoint = transform.position;
            var pressDownDirection = -transform.up;
            if (m_Button != null)
            {
                pressStartPoint = m_Button.position;
                pressDownDirection = -m_Button.up;
            }
            Gizmos.color = Color.green;
            Gizmos.DrawLine(pressStartPoint, pressStartPoint + (pressDownDirection * m_PressDistance));
        }
        void OnValidate()
        {
            SetButtonHeight(0.0f);
        }
    }
}