using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using UnityEngine;
using Animrig;

#if UNITY_EDITOR
using UnityEditor;
#endif

namespace Animrig.Unity
{
    // misc
    public class UnityMisc
    {

    }

    // Renderer
    public class EventFookRenderer : StateRenderer
    {
        public Action<double> OnUpdateEvent;
        public override void Update(double deltatime, double deltaphysics=-1)
        {
            OnUpdateEvent.Invoke(deltatime);
        }
    }
    // UnityEvent
    [System.Serializable]
    public class UnityEventDynamicDouble : UnityEngine.Events.UnityEvent<double> { };

    // GameObject
    [AddComponentMenu("Animationrig/GameObject Renderer")]
    public class AnimrigRendererGameObject : MonoBehaviour, Animrig.Unity.IUnityStateRenderer
    {
        // property
        protected EventFookRenderer fRenderer = new EventFookRenderer();

        [Tooltip("default:false. Call spine update & transform. If you control manually, set true.")]
        [SerializeField] public bool OverrideUpdate = false;
        [Tooltip("default:false. set GameObject.selfactive.")]
        [SerializeField] public bool OverrideEnable = false;
        [Tooltip("default:false. set GameObject.transform.")]
        [SerializeField] public bool OverrideTransform = false;
        [Tooltip("default:true. set Order in layer.")]
        [SerializeField] public bool OverridePriority = true;
        [Tooltip("default:true. Camera transform enable.")]
        [SerializeField] public bool EnableCameraTransform = true;
        [Tooltip("default:100.0. Object scale ratio of Spine.SkeletonJson Scale.")]
        [SerializeField] [Range(1, 100)] public float PixelPerUnit = 100.0f;
        [Tooltip("default:1.0. transform scale ratio. UI space = 1.0 , 3D space = 0.01")]
        [SerializeField] [Range(0.01f, 1)] public float TransformScale = 1.0f;

        [SerializeField] public UnityEventDynamicDouble OnUpdateEvents = new UnityEventDynamicDouble();
        
        // IUnityStateRenderer
        public StateRenderer StateRenderer { get { return fRenderer; } }
        public void UpdateStateRenderer(Animrig.AnimObject obj)
        {
            // not need it
        }
        public void UpdateGameObject()
        {
            var go = gameObject;

            // transform
            if (OverrideTransform)
            {
                Matrix4 m = fRenderer.TransMatrix;
                // camera
                if (fRenderer.StateInputObjectType != ObjectType.Camera)
                {
                    if (EnableCameraTransform) Animrig.Misc.m4PushMatrix(ref m, ref fRenderer.CameraMatrix);
                }
                // apply transscale
                Animrig.Misc.m4PushScale(ref m, TransformScale, TransformScale, TransformScale);

                // position
                {
                    UnityEngine.Vector3 v;
                    v.x = m._41;
                    v.y = m._42;
                    v.z = m._43;
                    // if (!Component3D) v.z = 0.0f;
                    go.transform.localPosition = v;
                }
                // scale
                {
                    UnityEngine.Vector3 v;
                    v.x = (float)Math.Sqrt(m._11 * m._11 + m._12 * m._12 + m._13 * m._13 + m._14 * m._14) * PixelPerUnit;
                    v.y = (float)Math.Sqrt(m._21 * m._21 + m._22 * m._22 + m._23 * m._23 + m._24 * m._24) * PixelPerUnit;
                    v.z = (float)Math.Sqrt(m._31 * m._31 + m._32 * m._32 + m._33 * m._33 + m._34 * m._34) * PixelPerUnit;
                    go.transform.localScale = v;
                }
                // rotate
                {
                    UnityEngine.Vector3 forward;
                    forward.x = m._31;
                    forward.y = m._32;
                    forward.z = m._33;

                    UnityEngine.Vector3 upwards;
                    upwards.x = m._21;
                    upwards.y = m._22;
                    upwards.z = m._23;

                    go.transform.localRotation = UnityEngine.Quaternion.LookRotation(forward, upwards);

                    /*
					var q = Misc.m4ExtractRotateQuaternion(ref m);
					UnityEngine.Quaternion uq;
					uq.x = q.x;
					uq.y = q.y;
					uq.z = q.z;
					uq.w = q.w;
					go.transform.localRotation = uq;
					*/
                }
            }

            // Override priority
            if (OverridePriority)
            {
                {
                    var mesh = go.GetComponent<MeshRenderer>();
                    if (mesh != null)
                    {
                        //mesh.sortingLayerID = "default";
                        mesh.sortingOrder = (int)Math.Floor(fRenderer.DrawPriorityDesign);
                    }
                }
            }

            // enable
            if (OverrideEnable)
            {
                if (go.activeSelf != fRenderer.RendererInheritedEnable) go.SetActive(fRenderer.RendererInheritedEnable);
            }
        }

        public AnimrigRendererGameObject()
        {
            void OnUpdateCallback(double deltatime)
            {
                OnUpdateEvents.Invoke(deltatime);
            }
            fRenderer.OnUpdateEvent += OnUpdateCallback;
        }
    }

    // inspector
#if UNITY_EDITOR

    [CustomEditor(typeof(AnimrigRendererGameObject))]
    public class AnimrigRendererGameObjectInspector : Editor
    {
        public void OnEnable()
        {

        }
        public override void OnInspectorGUI()
        {
            base.OnInspectorGUI();

            var t = target as AnimrigRendererGameObject;

            var go = t.gameObject;

            var trans = go.GetComponent<UnityEngine.Transform>();

            if (trans == null)
            {
                EditorGUILayout.HelpBox("Please attach Transform component.", MessageType.Error);
            }

            // serializedObject.Update();
            // serializedObject.ApplyModifiedProperties();
        }
    }
#endif


}
