using System;
using UnityEngine;
using UnityEngine.TestTools;

#if pHUMANOID4
using NUnit.Framework;
using Passer;

namespace Passer {
    using Pawn;
    using Humanoid;

    public class GrabbingTest : IPrebuildSetup {

        public void Setup() {
            UnityEditor.SceneManagement.EditorSceneManager.OpenScene("[Test]GrabbingHumanoid.unity");
        }

        [Test]
        public void Rigidbody() {
            // Can be grabbed on any place on the mesh.
            try {
                HumanoidControl humanoid = UnityEngine.Object.FindObjectOfType<HumanoidControl>();

                GameObject obj = GameObject.Find("CubeRigidbody");
                Assert.IsFalse(obj == null);

                #region Grab
                GameObject grabbedObject = Grab(humanoid, obj);
                Assert.AreEqual(grabbedObject, obj, "Object is not grabbed");
                #endregion

                #region LetGo
                grabbedObject = LetGo(humanoid);
                Assert.IsTrue(grabbedObject == null, "Object is not released");
                #endregion
            }
            catch (Exception e) {
                Debug.LogError("Test failed");
                throw (e);
            }
        }

        [Test]
        public void RigidbodyHandle() {
            // Can be grabbed on the handle.
            // Snaps back into the socket when let go.
            try {
                Setup();

                HumanoidControl humanoid = UnityEngine.Object.FindObjectOfType<HumanoidControl>();

                GameObject obj = GameObject.Find("CubeWithHandle");
                Assert.IsFalse(obj == null);

                #region Grab

                GameObject grabbedObject = Grab(humanoid, obj);
                Assert.AreEqual(grabbedObject, obj);

                #endregion

                #region LetGo
                grabbedObject = LetGo(humanoid);
                Assert.IsTrue(grabbedObject == null);
                #endregion
            }
            catch (Exception e) {
                Debug.LogError("Test failed");
                throw (e);
            }
        }

        [Test]
        public void KinematicRigidbodyWithoutPhysics() {
            // the controller holds the Rigidbody.
            try {
                HumanoidControl humanoid = UnityEngine.Object.FindObjectOfType<HumanoidControl>();
                    humanoid.leftHandTarget.physics = false;

                GameObject obj = GameObject.Find("KinematicCube");
                Assert.IsFalse(obj == null);

                #region Grab
                GameObject grabbedObject = Grab(humanoid, obj);
                Assert.AreEqual(grabbedObject, obj);
                #endregion

                #region LetGo
                grabbedObject = LetGo(humanoid);
                Assert.IsTrue(grabbedObject == null);
                #endregion
            }
            catch (Exception e) {
                Debug.LogError("Test failed");
                throw (e);
            }
        }

        [Test]
        public void KinematicRigidbodyWithPhysics() {
            // the Rigidbody will move the controller.
            try {
                HumanoidControl humanoid = UnityEngine.Object.FindObjectOfType<HumanoidControl>();
                    humanoid.leftHandTarget.physics = true;

                GameObject obj = GameObject.Find("KinematicCube");
                Assert.IsFalse(obj == null);

                #region Grab
                GameObject grabbedObject = Grab(humanoid, obj);
                Assert.AreEqual(grabbedObject, obj);
                #endregion

                #region LetGo
                grabbedObject = LetGo(humanoid);
                Assert.IsTrue(grabbedObject == null);
                #endregion
            }
            catch (Exception e) {
                Debug.LogError("Test failed");
                throw (e);
            }
        }

        [Test]
        public void KinematicRigidbodyLimitations() {
            // the Rigidbody will move the controller.
            try {
                HumanoidControl humanoid = UnityEngine.Object.FindObjectOfType<HumanoidControl>();

                GameObject obj = GameObject.Find("KinematicCubeLimitations");
                Assert.IsFalse(obj == null);

                #region Grab
                GameObject grabbedObject = Grab(humanoid, obj);
                Assert.AreEqual(grabbedObject, obj);
                #endregion

                #region LetGo
                grabbedObject = LetGo(humanoid);
                Assert.IsTrue(grabbedObject == null);
                #endregion
            }
            catch (Exception e) {
                Debug.LogError("Test failed");
                throw (e);
            }
        }

        [Test]
        public void StaticObject() {
            // Static object can not be grabbed
            try {
                HumanoidControl humanoid = UnityEngine.Object.FindObjectOfType<HumanoidControl>();

                GameObject obj = GameObject.Find("StaticCube");
                Assert.IsFalse(obj == null);

                #region Grab
                GameObject grabbedObject = Grab(humanoid, obj);
                Assert.IsTrue(grabbedObject == null);
                #endregion

                #region LetGo
                grabbedObject = LetGo(humanoid);
                Assert.IsTrue(grabbedObject == null);
                #endregion
            }
            catch (Exception e) {
                Debug.LogError("Test failed");
                throw (e);
            }
        }

        [Test]
        public void StaticObjectHandle() {
            // Can be grabbed but cannot move.
            // When Body Pull is enabled, the position of the pawn will move.
            try {
                HumanoidControl humanoid = UnityEngine.Object.FindObjectOfType<HumanoidControl>();

                GameObject obj = GameObject.Find("StaticCubeWithHandle");
                Assert.IsFalse(obj == null);

                Handle handle = obj.GetComponentInChildren<Handle>();
                Assert.IsFalse(handle == null);

                #region Grab
                GameObject grabbedObject = Grab(humanoid, obj);
                Assert.AreEqual(grabbedObject, handle.gameObject);
                #endregion

                #region LetGo
                grabbedObject = LetGo(humanoid);
                Assert.IsTrue(grabbedObject == null);
                #endregion
            }
            catch (Exception e) {
                Debug.LogError("Test failed");
                throw (e);
            }
        }

        #region Utilities

        protected GameObject Grab(HumanoidControl humanoid, GameObject obj) {
                humanoid.leftHandTarget.Grab(obj);
                return humanoid.leftHandTarget.grabbedObject;
        }

        protected GameObject LetGo(HumanoidControl humanoid) {
                humanoid.leftHandTarget.LetGo();
                return humanoid.leftHandTarget.grabbedObject;
        }

        #endregion
    }

}

#endif