using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.EnhancedTouch;
using UnityEngine.InputSystem.OnScreen;
using UnityEngine.InputSystem.Layouts;
using EnhancedTouchSupport = UnityEngine.InputSystem.EnhancedTouch.EnhancedTouchSupport;

namespace DeviantMobile.Input
{
    // Drag-based on-screen stick that writes a Vector2 to the Input System.
    // Bind your Move action to the same control path (e.g. <Gamepad>/leftStick).
    [AddComponentMenu("Input/Mobile On-Screen Stick")]
    public class MobileOnScreenStick : OnScreenControl, IPointerDownHandler, IPointerUpHandler, IDragHandler
    {
        [Header("Platform / Visibility")]
        [Tooltip("If true, on-screen stick will be visible when running in the Editor (useful for testing). If false, controls are hidden in editor/desktop builds and only shown on mobile platforms.")]
        [SerializeField] private bool allowShowInEditor = false;

        // Helper to determine whether on-screen controls should be active for the current platform.
        private bool ShouldShowOnScreenControls()
        {
            if (Application.platform == RuntimePlatform.Android || Application.platform == RuntimePlatform.IPhonePlayer)
                return true;
            if (Application.isEditor && allowShowInEditor)
                return true;
            return false;
        }
        [Header("Control Path")]
        [Tooltip("Input System control path to write the Vector2 to. Commonly '<Gamepad>/leftStick'.")]
        [SerializeField, InputControl(layout = "Vector2")] private string m_ControlPath = "<Gamepad>/leftStick";

        protected override string controlPathInternal
        {
            get => m_ControlPath;
            set => m_ControlPath = value;
        }

        [Header("UI References")]
        [SerializeField] private RectTransform background; // Joystick background area
        [SerializeField] private RectTransform handle;     // Joystick handle/knob

        [Header("Behavior")] 
        [Tooltip("Max radius in pixels the handle can travel from center.")]
        [SerializeField] private float maxRadius = 100f;
        [Tooltip("Deadzone as a fraction of radius (0..1).")]
        [Range(0f, 0.5f)] [SerializeField] private float deadZone = 0.1f;
        [Tooltip("Return handle to center on pointer up.")]
        [SerializeField] private bool snapBackOnRelease = true;

        private bool _pressed;
        private Vector2 _centerLocal;

        void Awake()
        {
            if (background == null)
                background = GetComponent<RectTransform>();
            if (handle == null && background != null && background.childCount > 0)
                handle = background.GetChild(0) as RectTransform;

            // Disable the UI for non-mobile platforms by default.
            gameObject.SetActive(ShouldShowOnScreenControls());
        }

        void OnEnable()
        {
            // Ensure the Enhanced Touch pipeline is active so pointer/touch events map correctly to OnScreenControl.
            EnhancedTouchSupport.Enable();
        }

        void OnDisable()
        {
            EnhancedTouchSupport.Disable();
        }

        public void OnPointerDown(PointerEventData eventData)
        {
            _pressed = true;
            CacheCenter();
            OnDrag(eventData); // update immediately
        }

        public void OnDrag(PointerEventData eventData)
        {
            if (background == null)
                return;

            RectTransformUtility.ScreenPointToLocalPointInRectangle(background, eventData.position, eventData.pressEventCamera, out var localPoint);
            var delta = localPoint - _centerLocal;

            // Clamp to radius
            if (delta.magnitude > maxRadius)
                delta = delta.normalized * maxRadius;

            // Normalize to [-1,1]
            var norm = (maxRadius > 0f) ? (delta / maxRadius) : Vector2.zero;

            // Apply deadzone
            var mag = norm.magnitude;
            if (mag < deadZone)
                norm = Vector2.zero;
            else if (mag > 1f)
                norm = norm.normalized;

            // Move handle visually
            if (handle != null)
                handle.anchoredPosition = delta;

            // Send to Input System
            SendValueToControl(norm);
        }

        public void OnPointerUp(PointerEventData eventData)
        {
            _pressed = false;
            if (snapBackOnRelease)
            {
                ResetHandle();
            }
            SendValueToControl(Vector2.zero);
        }

        private void CacheCenter()
        {
            if (background != null)
            {
                // Center is the pivot point local position (0 if centered pivot). Use rect center for safety.
                _centerLocal = background.rect.center;
            }
            else
            {
                _centerLocal = Vector2.zero;
            }
        }

        private void ResetHandle()
        {
            if (handle != null)
                handle.anchoredPosition = Vector2.zero;
        }

#if UNITY_EDITOR
        void OnValidate()
        {
            if (background == null)
                background = GetComponent<RectTransform>();
            if (handle == null && background != null && background.childCount > 0)
                handle = background.GetChild(0) as RectTransform;
        }
#endif
    }
}
