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

#if UNITY_EDITOR
using UnityEditor;
#endif

namespace Animrig.Unity
{
	// spine renderer for unity
	public class UnitySpineRenderer : SpineRenderer
	{
		public bool OverrideUpdate = false;
		public bool OverrideDefaultMixDuration = true;

		// common 
		public override void Update(double deltatime)
		{
			if (!OverrideUpdate) return;

			base.Update(deltatime);
		}
		// spine
		public override void SetMixDuration(float duration)
		{
			if (!OverrideDefaultMixDuration) return;

			base.SetMixDuration(duration);
		}
	}

    // Spine object component
    [AddComponentMenu("Animationrig/SpineRenderer")]
    public class AnimationrigSpineRendererComponent : MonoBehaviour, IUnityStateRenderer
    {
		// property
        protected UnitySpineRenderer fRenderer = new UnitySpineRenderer();
		protected bool Component3D = false;
        public StateRenderer StateRenderer
        {
            get
            {
                return fRenderer;
            }
        }
		[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:false. set SpineObject.Skeleton color.")]
		[SerializeField] public bool OverrideColor = false;
		[Tooltip("default:true. set SpineObject.DefaultMixDuration.")]
		[SerializeField] public bool OverrideDefaultMixDuration = true;
		[Tooltip("default:100.0. Scale ratio of Unity to AnimtionRigEditor.")]
		[SerializeField] public float PixelPerUnit = 100.0f;
		[Tooltip("default:1.0. transform scale ratio.")]
		[SerializeField] public float TransformScale = 1.0f;
		// public
        public void UpdateStateRenderer()
        {
			// override option
			fRenderer.OverrideDefaultMixDuration = OverrideDefaultMixDuration;
			fRenderer.OverrideUpdate = OverrideUpdate;
			var go = gameObject;

			// find SkeletonAnimation component
			{
				var spinecompo = go.GetComponent<Spine.Unity.SkeletonAnimation>();
				if (spinecompo != null)
				{
					fRenderer.state = spinecompo.AnimationState;
					fRenderer.skeleton = spinecompo.Skeleton;
					Component3D = true;
					return;
				}
			}
			// find skeletonGraphic component
			{
				var spinecompo = go.GetComponent<Spine.Unity.SkeletonGraphic>();
				if (spinecompo != null)
				{
					fRenderer.state = spinecompo.AnimationState;
					fRenderer.skeleton = spinecompo.Skeleton;
					Component3D = false;
					return;
				}
			}
			// nothing
			fRenderer.state = null;
			fRenderer.skeleton = null;
        }
		public void UpdateGameObject()
		{
			var go = gameObject;

			// transform
			if (OverrideTransform)
			{
				Matrix4 m = fRenderer.TransMatrix;
				// apply transscale
				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;
					*/
				}
			}

			// color
			if (OverrideColor && (fRenderer.skeleton != null))
			{
				fRenderer.skeleton.A = fRenderer.RendererInheritedVisible ? fRenderer.TransColor[0] : 0.0f;
				fRenderer.skeleton.R = fRenderer.TransColor[1];
				fRenderer.skeleton.G = fRenderer.TransColor[2];
				fRenderer.skeleton.B = fRenderer.TransColor[3];
			} 

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

    // inspector
#if UNITY_EDITOR

    [CustomEditor(typeof(AnimationrigSpineRendererComponent))]
    public class AnimationrigSpineRendererInspector : Editor
    {
        public void OnEnable()
        {

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

            var t = target as AnimationrigSpineRendererComponent;

			var go = t.gameObject;

			var skeletonanimation = go.GetComponent<Spine.Unity.SkeletonAnimation>();
			if (skeletonanimation == null)
            {
				var skeletongraphic = go.GetComponent<Spine.Unity.SkeletonGraphic>();
				if (skeletongraphic == null)
				{
					EditorGUILayout.HelpBox("Please attach SkeletonAnimation/Graphic component to the this GameObject.", MessageType.Error);
				}
            };

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

    }
