using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;

#if USING_MRTK2
using Microsoft.MixedReality.Toolkit.UI;
using Microsoft.MixedReality.Toolkit.UI.BoundsControl;
#endif

using System;

namespace SimplifyXR
{

    public class StandardAssetsBoundsControl : MonoBehaviour
    {

        public bool addBoundsViz = true;

        public UnityEvent<Vector3> OnManipulationEnded = new UnityEvent<Vector3>();

        BoxCollider collider;
        Bounds startBounds;
        BoxCollider startCollider;


#if USING_MRTK2

        ObjectManipulator manipulator;
        BoundsControl boundsControl;
        MinMaxScaleConstraint scaleConstraint;
        RotationAxisConstraint rotateConstraint;
        ConstraintManager constraintManager;
#endif

        public void OnDestroy()
        {
#if USING_MRTK2
            RemoveBoundsListeners();
            if (manipulator) Destroy(manipulator);
            if (boundsControl) Destroy(boundsControl);
            if (scaleConstraint) Destroy(scaleConstraint);
            if (rotateConstraint) Destroy(rotateConstraint);
            if (startCollider) Destroy(startCollider);
            if (constraintManager) Destroy(constraintManager);
#else
            this.gameObject.layer = LayerMask.NameToLayer("Default");
            Destroy(collider);
#endif
        }

        public void ResetBounds()
        {
#if USING_MRTK2
            if (boundsControl &&
                addBoundsViz)
            {
                Destroy(boundsControl);
                boundsControl = null;
                StartCoroutine(DelayRoutine(
                    () => {
                        boundsControl = this.gameObject.GetOrAddNewComponent<BoundsControl>();
                        SetupBoundsListeners();
                    }
                ));
            }
#endif
        }

        IEnumerator DelayRoutine(Action delayedAction)
        {
            yield return new WaitForSeconds(0.1f);
            delayedAction?.Invoke();
        }


#if USING_MRTK2
        public void HandleManipulation(ManipulationEventData data)
        {
            OnManipulationEnded?.Invoke(this.transform.position);
        }

        public void HandleBoundsUpdate()
        {
            OnManipulationEnded?.Invoke(this.transform.position);
        }

        void HandleRotateStarted()
        {
           if (rotateConstraint) rotateConstraint.enabled = false;
           if (manipulator) manipulator.enabled = false;
        }

        void HandleRotateEnded()
        {
            if (rotateConstraint) rotateConstraint.enabled = true;
            if (manipulator) manipulator.enabled = true;
        }


        void RemoveBoundsListeners()
        {
            if (boundsControl)
            {
                boundsControl.ScaleStopped.RemoveAllListeners();
                boundsControl.RotateStopped.RemoveAllListeners();
                boundsControl.TranslateStopped.RemoveAllListeners();
                boundsControl.RotateStarted.RemoveAllListeners();
            }
        }

        void SetupBoundsListeners()
        {
            if (boundsControl)
            {
                boundsControl.ScaleStopped.AddListener(HandleBoundsUpdate);
                boundsControl.RotateStopped.AddListener(HandleBoundsUpdate);
                boundsControl.TranslateStopped.AddListener(HandleBoundsUpdate);
                boundsControl.RotateStarted.AddListener(HandleRotateStarted);
                boundsControl.RotateStopped.AddListener(HandleRotateEnded);
            }
        }
#endif

        public void Awake()
        {
#if USING_MRTK2


            manipulator = this.gameObject.AddComponent<ObjectManipulator>();
            manipulator.OnManipulationEnded.AddListener(HandleManipulation);
            if (addBoundsViz) boundsControl = this.gameObject.GetOrAddNewComponent<BoundsControl>();
            SetupBoundsListeners();

            if (boundsControl) boundsControl.BoundsControlActivation = Microsoft.MixedReality.Toolkit.UI
                 .BoundsControlTypes.BoundsControlActivationType.ActivateByPointer;


            //for now we disable scaling
            scaleConstraint = this.gameObject.GetOrAddNewComponent<MinMaxScaleConstraint>();
            scaleConstraint.ScaleMinimum = 1f;
            scaleConstraint.ScaleMaximum = 1f;

            //we disable rot when using the manipulator, but enable for explicit bounds control, may want to have this be configurable
            rotateConstraint = this.gameObject.GetOrAddNewComponent<RotationAxisConstraint>();
            rotateConstraint.ConstraintOnRotation = Microsoft.MixedReality.Toolkit.Utilities.AxisFlags.XAxis | Microsoft.MixedReality.Toolkit.Utilities.AxisFlags.YAxis | Microsoft.MixedReality.Toolkit.Utilities.AxisFlags.ZAxis;

            constraintManager = this.gameObject.GetOrAddNewComponent<ConstraintManager>();

            SetupBoundsVisuals();

#else
            collider = this.gameObject.GetOrAddNewComponent<BoxCollider>();
        
#endif


            StartCoroutine(DelayRoutine(
               () => {
                   SetCurrentBounds();               }
           ));
        }

        private void SetCurrentBounds()
        {
#if USING_MRTK2
            if (boundsControl)
            {

                var currentCollider  = gameObject.GetComponent<BoxCollider>();
                startBounds = new Bounds(currentCollider.center, currentCollider.size);
                //add another collider we delete afterward, maybe this should be put on the model instance (if it doesn't have one)
                startCollider = gameObject.AddComponent<BoxCollider>();
                startCollider.size = startBounds.size;
                startCollider.center = startBounds.center;
                boundsControl.BoundsOverride = startCollider;
            }
#endif
        }

        private void SetupBoundsVisuals()
        {
#if USING_MRTK2
            if (boundsControl)
            {
                var visualLinkMat = Resources.Load("Utilities/Components/simpleAR Standard Assets/Materials/TransparentBlue_Highlight_StandardAssets") as Material;
                var visualRotMat = Resources.Load("Utilities/Components/simpleAR Standard Assets/Materials/DarkBlue_Highlight_StandardAssets") as Material;

                //add materials and remove scale 
                boundsControl.ScaleHandlesConfig.ShowScaleHandles = false;

                boundsControl.LinksConfig.WireframeMaterial = visualLinkMat;
                boundsControl.RotationHandlesConfig.HandleMaterial= visualRotMat;
            }
#endif
        }

        public void EnableManipulators(bool enable)
        {
#if USING_MRTK2
            manipulator.enabled = enable;
            if (boundsControl) boundsControl.enabled = enable;
#else
            collider = this.gameObject.GetOrAddNewComponent<BoxCollider>();
#endif
        }
        public void ValidateManipulatorSupport()
        {
            //EnableManipulators(supported);
        }

    }

}
