using UnityEngine;
#if ENABLE_INPUT_SYSTEM
using UnityEngine.InputSystem;
#endif

namespace NBF.TEST
{
    [RequireComponent(typeof(RopeController))]
    public class RopeConnectorTest : MonoBehaviour
    {
        [SerializeField] private Transform handTransform;
        [SerializeField] private Transform hitPoint;
        [Range(3,50)]
        [SerializeField] private int maxRopeNodeCount = 23;
        [Range(2,45)]
        [SerializeField] private int minRopeNodeCount = 4;

        private RopeController _ropeController;
        private VerletRope _activeRope = null;

        private void Awake()
        {
            _ropeController = GetComponent<RopeController>();
        }

        private void Update()
        {
            bool isMouseClicked;
            bool increaseRope;
            bool decreaseRope;
#if ENABLE_INPUT_SYSTEM
            isMouseClicked = Mouse.current.leftButton.wasPressedThisFrame;
            increaseRope = Keyboard.current.qKey.wasPressedThisFrame;
            decreaseRope = Keyboard.current.eKey.wasPressedThisFrame;
#else
            isMouseClicked = Input.GetMouseButtonDown(0);
            increaseRope = Input.GetKeyDown(KeyCode.Q);
            decreaseRope = Input.GetKeyDown(KeyCode.E);
#endif
            Vector3 mousePosition;
            
#if ENABLE_INPUT_SYSTEM
            mousePosition = Mouse.current.position.ReadValue();
#else
            mousePosition = Input.mousePosition;
#endif
            
            HandleRay(mousePosition, isMouseClicked);
            HandleIncreaseDecrease(increaseRope, decreaseRope);
        }

        private void HandleIncreaseDecrease(bool increase, bool decrease)
        {
            if(!_activeRope)
                return;
            if (increase)
            {
                RopeController.IncreaseRopeLength(_activeRope, maxRopeNodeCount);
                return;
            }
            if(decrease)
                RopeController.DecreaseRopeLength(_activeRope, minRopeNodeCount);
        }

        private void HandleRay(Vector3 mousePosition, bool isMouseClicked)
        {
            var ray = Camera.main.ScreenPointToRay(mousePosition);
            var physicsHit = Physics.Raycast(ray, out var hitInfo, 100f);
            var ropeHit = VerletPhysics.Raycast(ray, out var ropeHitInfo, 100f);
            if (physicsHit && ropeHit)
            {
                if (hitInfo.distance < ropeHitInfo.Distance)
                {
                    hitPoint.gameObject.SetActive(true);
                    HandleHitPointPosition(hitInfo.point);
                    if(isMouseClicked)
                        HandlePhysicsConnection(hitInfo);
                }
                else
                {
                    hitPoint.gameObject.SetActive(true);
                    HandleHitPointPosition(ropeHitInfo.NodePoint);
                    if(isMouseClicked)
                        HandleRopeConnection(ropeHitInfo);
                }
            }
            else if (physicsHit)
            {
                hitPoint.gameObject.SetActive(true);
                HandleHitPointPosition(hitInfo.point);
                if(isMouseClicked)
                    HandlePhysicsConnection(hitInfo);
            }
            else if (ropeHit)
            {
                hitPoint.gameObject.SetActive(true);
                HandleHitPointPosition(ropeHitInfo.NodePoint);
                if(isMouseClicked)
                    HandleRopeConnection(ropeHitInfo);
            }
            else
            {
                hitPoint.gameObject.SetActive(false);
            }
        }

        private void HandleHitPointPosition(Vector3 hitPosition)
        {
            hitPoint.position = hitPosition;
        }

        private void HandleRopeConnection(RopeHitInfo hitInfo)
        {
            if (!_activeRope)
            {
                _activeRope =
                    _ropeController.ConnectRope(handTransform, hitInfo.Rope, hitInfo.NodeIndex, Vector3.zero, Vector3.zero);
                return;
            }
            RopeController.ConnectRopeStart(_activeRope, hitInfo.Rope, hitInfo.NodeIndex, Vector3.zero);
            _activeRope = null;
        }
        private void HandlePhysicsConnection(RaycastHit hitInfo)
        {
            var attachedRb = hitInfo.collider.attachedRigidbody;
            if (!_activeRope)
            {
                if (attachedRb)
                {
                    _activeRope = _ropeController.ConnectRope(handTransform, attachedRb,
                        Vector3.zero, hitInfo.transform.InverseTransformPoint(hitInfo.point));
                    return;
                }

                _activeRope =
                    _ropeController.ConnectRope(handTransform, hitInfo.transform, Vector3.zero,
                        hitInfo.transform.InverseTransformPoint(hitInfo.point));
                return;
            }

            if (attachedRb)
            {
                RopeController.ConnectRopeStart(_activeRope, attachedRb, hitInfo.transform.InverseTransformPoint(hitInfo.point));
                _activeRope = null;
                return;
            }
            RopeController.ConnectRopeStart(_activeRope, hitInfo.transform, hitInfo.transform.InverseTransformPoint(hitInfo.point));
            _activeRope = null;
        }
    }
}