using JetBrains.Annotations;
using UnityEditor;
using UnityEngine;
using UnityEngine.Events;

namespace ABI.CCK.Components
{
    public class StateMachineCallbackSender : StateMachineBehaviour
    {
        #region UnityEvents

        [PublicAPI] public static readonly UnityEvent<Animator, StateMachineCallbackSender> OnInitialized = new();
        [PublicAPI] public static readonly UnityEvent<Animator, StateMachineCallbackSender> OnExecuteEnterTask = new();
        [PublicAPI] public static readonly UnityEvent<Animator, StateMachineCallbackSender> OnExecuteExitTask = new();

        #endregion
        
        public bool localOnly = true;
        
        private bool _initialized;

        #region Unity Events
        
        public override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
        {
            if (!_initialized) Initialize(animator);
            OnExecuteEnterTask.Invoke(animator, this);
        }

        public override void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
        {
            if (!_initialized) Initialize(animator);
            OnExecuteExitTask.Invoke(animator, this);
        }
        
        #endregion Unity Events
        
        #region Private Methods
        
        private void Initialize(Animator animator)
        {
            _initialized = true;
            OnInitialized.Invoke(animator, this);
        }
        
        #endregion Private Methods

#if UNITY_EDITOR
        [CustomEditor(typeof(StateMachineCallbackSender))]
        public class StateMachineCallbackSenderEditor : Editor
        {
            private StateMachineCallbackSender _sender;
            
            private bool _showLocalOnlyHelp;
            
            private SerializedProperty _localOnly;
            
            private void OnEnable()
            {
                _sender = (StateMachineCallbackSender)target;
                if (_sender == null)
                    return;
                
                _localOnly = serializedObject.FindProperty("localOnly");
            }

            public override void OnInspectorGUI()
            {
                if (_sender == null)
                    return;

                serializedObject.Update();
                
                using (new EditorGUILayout.VerticalScope(new GUIStyle() { padding = new RectOffset(10, 10, 10, 10) }))
                {
                    DrawLocalOnlyToggle();
                    EditorGUILayout.HelpBox(
                        "This behaviour will send the following state machine callbacks to any listening receviers: OnStateMachineEnter, OnStateMachineExit",
                        MessageType.Info);
                }
                
                serializedObject.ApplyModifiedProperties();
            }
            
            private void DrawLocalOnlyToggle()
            {
                using (new EditorGUILayout.HorizontalScope())
                {
                    EditorGUILayout.PropertyField(_localOnly);
                    if (GUILayout.Button("?", GUILayout.Width(25)))
                        _showLocalOnlyHelp = !_showLocalOnlyHelp;
                    GUILayout.Space(5);
                }
                if (_showLocalOnlyHelp)
                {
                    EditorGUILayout.HelpBox("When 'Local Only' is enabled, the animator driver is executed locally and not for remote users.", MessageType.Info);
                    EditorGUILayout.Space(5);
                    EditorGUILayout.HelpBox("Avatars: Only the wearer.\nSpawnables: Only the prop's owner.\nWorlds: This option is ignored.", MessageType.Info);
                }
                EditorGUILayout.Space();
            }
        }
#endif
    }
}