using System.Collections;
using System.Collections.Generic;
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
{
    // Variant that targets actions directly instead of raw control paths.
    [RequireComponent(typeof(RectTransform))]
    public class MobileControlManagerAction : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
    {
        [Header("Platform / Visibility")]
        [Tooltip("If true, on-screen controls 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;
        }
        [System.Serializable]
        public class ActionBinding
        {
            [Tooltip("InputActionReference to trigger for this tap count. Leave empty to ignore.")]
            public InputActionReference action;

            [Tooltip("Optional label for clarity only (not used at runtime)")]
            public string label;
        }

        [Header("Tap to Action Bindings (index 0=single, 1=double, 2=triple, 3=quad)")]
        public ActionBinding[] actions = new ActionBinding[4];

        [Header("Tap Settings")] 
        [Tooltip("Max delay between taps to register as a multi-tap (seconds)")]
        [Range(0.1f, 0.6f)] public float multiTapWindow = 0.3f;
        [Tooltip("How long to hold the virtual press (seconds)")]
        [Range(0.01f, 0.2f)] public float pressDuration = 0.05f;

        private int tapCount = 0;
        private float lastTapTime = -1f;
        private Coroutine finalizeCoroutine;

        // Internally we build OnScreenPulseControl(s) that point at the bound actions' control paths.
        private readonly List<OnScreenPulseControl> _pulsers = new List<OnScreenPulseControl>(4);

        void Awake()
        {
            BuildOrRefreshPulsers();
            // Ensure visibility matches platform (do this early so UI is correct in hierarchy)
            gameObject.SetActive(ShouldShowOnScreenControls());
        }

        void OnEnable()
        {
            // Ensure EnhancedTouch is available so Unity's UI and On-Screen controls receive multi-touch data.
            EnhancedTouchSupport.Enable();
            BuildOrRefreshPulsers();
            gameObject.SetActive(ShouldShowOnScreenControls());
        }

        void OnDisable()
        {
            // Balance the Enable call; safe to invoke even if already disabled elsewhere.
            EnhancedTouchSupport.Disable();
        }

        public void OnPointerDown(PointerEventData eventData) { }

        public void OnPointerUp(PointerEventData eventData)
        {
            var now = Time.unscaledTime;
            if (lastTapTime > 0 && (now - lastTapTime) <= multiTapWindow)
                tapCount++;
            else
                tapCount = 1;

            lastTapTime = now;
            if (finalizeCoroutine != null)
                StopCoroutine(finalizeCoroutine);
            finalizeCoroutine = StartCoroutine(FinalizeTapAfterWindow());
        }

        private IEnumerator FinalizeTapAfterWindow()
        {
            yield return new WaitForSecondsRealtime(multiTapWindow);
            TriggerForTapCount(tapCount);
            tapCount = 0;
            lastTapTime = -1f;
            finalizeCoroutine = null;
        }

        private void TriggerForTapCount(int taps)
        {
            int index = Mathf.Clamp(taps, 1, 4) - 1;
            if (index >= _pulsers.Count) return;
            var pulser = _pulsers[index];
            if (pulser == null) return;
            pulser.Pulse(1f, pressDuration);
        }

        private void BuildOrRefreshPulsers()
        {
            _pulsers.Clear();

            foreach (var existing in GetComponents<OnScreenPulseControl>())
            {
                if (Application.isPlaying)
                    Destroy(existing);
                else
                    DestroyImmediate(existing);
            }

            // If actions not set, nothing to do.
            if (actions == null) return;

            // We resolve each InputActionReference to a suitable control path.
            for (int i = 0; i < Mathf.Min(4, actions.Length); i++)
            {
                var binding = actions[i];
                if (binding == null || binding.action == null || binding.action.action == null)
                {
                    _pulsers.Add(null);
                    continue;
                }

                // Determine a control path. Prefer the first non-empty binding path.
                string path = ResolvePreferredControlPath(binding.action.action);
                if (string.IsNullOrWhiteSpace(path))
                {
                    _pulsers.Add(null);
                    continue;
                }

                var pulser = gameObject.AddComponent<OnScreenPulseControl>();
                // Set the control path resolved from the InputAction.
                // In the InputAction asset, ensure the action is bound to a control that matches this path
                // (for example a Button control on a touch/gamepad). The OnScreenPulseControl will send
                // press/release values to that control path, which the InputSystem action can receive.
                pulser.controlPath = path;
                _pulsers.Add(pulser);
            }
        }

        private static string ResolvePreferredControlPath(InputAction action)
        {
            // Try active controls if the action is enabled
            if (action.enabled && action.controls.Count > 0)
            {
                // Use the first control's path
                return action.controls[0].path;
            }

            // Fallback to the first binding that has a path
            foreach (var b in action.bindings)
            {
                if (!string.IsNullOrWhiteSpace(b.effectivePath))
                    return b.effectivePath;
                if (!string.IsNullOrWhiteSpace(b.path))
                    return b.path;
            }

            return null;
        }

#if UNITY_EDITOR
        void OnValidate()
        {
            if (actions == null || actions.Length != 4)
            {
                var old = actions;
                actions = new ActionBinding[4];
                if (old != null)
                {
                    for (int i = 0; i < Mathf.Min(4, old.Length); i++)
                        actions[i] = old[i];
                }
            }

            if (Application.isPlaying == false)
                UnityEditor.EditorApplication.delayCall += () => {
                    if (this != null)
                        BuildOrRefreshPulsers();
                };
        }
#endif
    }
}
