// FlexiMotion // https://kybernetik.com.au/flexi-motion // Copyright 2023-2025 Kybernetik //

#pragma warning disable CS0649 // Field is never assigned to, and will always have its default value.

using UnityEngine;

namespace FlexiMotion.Samples
{
    /// <summary>Allows the user to drag an object with a collider around on screen with the mouse.</summary>
    /// <example><see href="https://kybernetik.com.au/animancer/docs/examples/ik/puppet">Puppet</see></example>
    /// https://kybernetik.com.au/flexi-motion/api/FlexiMotion.Samples/MouseDraggable
    /// 
    [AddComponentMenu(FMStrings.SamplesMenuPrefix + "Mouse Draggable")]
    [HelpURL(FMStrings.DocsURLs.SamplesAPIDocumentation + "/" + nameof(MouseDraggable))]
    public class MouseDraggable : MonoBehaviour
    {
        /************************************************************************************************************************/

        [SerializeField] private Transform _Target;

        private Transform _Dragging;
        private float _Distance;

        /************************************************************************************************************************/

        protected virtual void Update()
        {
            // On click, do a raycast from the mouse, grab whatever it hits, and calculate how far away it is.
            if (SampleInput.LeftMouseDown)
            {
                var ray = Camera.main.ScreenPointToRay(SampleInput.MousePosition);
                if (Physics.Raycast(ray, out var hit, float.MaxValue, Physics.DefaultRaycastLayers, QueryTriggerInteraction.Collide))
                {
                    var target = hit.transform;
                    if (target != transform)
                        return;

                    _Dragging = target;

                    var cameraTransform = Camera.main.transform;
                    _Distance = Vector3.Dot(_Dragging.position - cameraTransform.position, cameraTransform.forward);
                }

                return;
            }
            // While holding the button, move the object in line with the mouse ray.
            else if (_Dragging == transform && SampleInput.LeftMouseHold)
            {
                var ray = Camera.main.ScreenPointToRay(SampleInput.MousePosition);

                var cameraTransform = Camera.main.transform;
                var forward = cameraTransform.forward;

                var dot = Vector3.Dot(ray.direction, forward);
                if (dot > 0)
                {
                    var planeCenter = cameraTransform.position + forward * _Distance;
                    var intersection = ray.origin + ray.direction * Vector3.Dot(planeCenter - ray.origin, forward) / dot;
                    _Dragging.position = intersection;
                    _Target.position = intersection;
                    return;
                }
            }

            _Dragging = null;
        }

        /************************************************************************************************************************/
    }
}
