#if VRC_SDK_VRCSDK3 && UNITY_EDITOR
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEditor.Animations;
using UnityEngine;
using VRC.SDK3.Avatars.Components;
using VRC.SDKBase;
using VRCExpressionSetupTool.Editor.Layout;

namespace VRCExpressionSetupTool.Editor
{
    public class ExpressionSetupWindow : EditorWindow
    {
        private VRC_AvatarDescriptor avatarDescriptor;
        private SerializedObject avatarDesctiptorSerializedObject;

        private LayerClipsEditView leftLayerClipsEditView;
        private LayerClipsEditView rightLayerClipsEditView;

        private bool isAnimatorControllerChanged;

        [MenuItem("Window/ExpressionSetup")]
        private static void ShowWindow()
        {
            var window = GetWindow<ExpressionSetupWindow>();
            window.titleContent = new GUIContent("Expression Setup", (Texture2D)EditorGUIUtility.Load("d_ViewToolOrbit"));
            window.Show();
        }

        private void OnGUI()
        {
            EditorGUICustomLayout.ObjectField("Avatar", this.avatarDescriptor, true, x =>
            {
                this.avatarDescriptor = x;
                if (this.avatarDescriptor == null) return;
                this.avatarDesctiptorSerializedObject = new SerializedObject(this.avatarDescriptor);
            });

            if (this.avatarDescriptor == null) return;
            // if (this.avatarDescriptor.IsPrefab())
            // {
            //     EditorUtility.DisplayDialog($"{this.avatarDescriptor.gameObject.name} is Prefab!", "Can't use Prefab.", "Close");
            //     this.avatarDescriptor = null;
            //     return;
            // }
            if (this.avatarDesctiptorSerializedObject == null) return;
            
            this.avatarDesctiptorSerializedObject.Update();
            
            this.EnableLayerEditing();

            var baseAnimLayers = this.avatarDesctiptorSerializedObject.FindProperty("baseAnimationLayers");

            const int fxLayerIndex = (int)VRCAvatarDescriptor.AnimLayerType.FX - 1;
            const int gestureLayerIndex = (int) VRCAvatarDescriptor.AnimLayerType.Gesture - 1;
            
            EnableLayer(baseAnimLayers, fxLayerIndex);
            EnableLayer(baseAnimLayers, gestureLayerIndex);

            this.LayerClipsEditGUI("Left Hand", baseAnimLayers, fxLayerIndex, gestureLayerIndex,
                ref this.leftLayerClipsEditView);
            this.LayerClipsEditGUI("Right Hand", baseAnimLayers, fxLayerIndex, gestureLayerIndex,
                ref this.rightLayerClipsEditView);

            this.avatarDesctiptorSerializedObject.ApplyModifiedProperties();
        }

        private void LayerClipsEditGUI(string layerName, SerializedProperty baseAnimLayers, int fxLayerIndex,
            int gestureLayerIndex, ref LayerClipsEditView view)
        {
            var fxStates = this.GetLayerAnimatorStates(baseAnimLayers, fxLayerIndex, layerName);
            var gestureStates = this.GetLayerAnimatorStates(baseAnimLayers, gestureLayerIndex, layerName);

            if (fxStates == null || gestureStates == null) return;

            var list = (from t in fxStates
                let i2 = gestureStates.FindIndex(x => x.state.name == t.state.name)
                where i2 != -1
                select new KeyValuePair<string, List<ChildAnimatorState>>(t.state.name,
                    new List<ChildAnimatorState> {t, gestureStates[i2]})).ToList();

            view = new LayerClipsEditView(layerName, list);
            view.OnGUI();
        }

        private List<ChildAnimatorState> GetLayerAnimatorStates(SerializedProperty baseAnimLayers, int index, string layerName)
        {
            var layer = baseAnimLayers.GetArrayElementAtIndex(index);
            var controller = layer.FindPropertyRelative("animatorController");
            var runtimeAnimatorController = (RuntimeAnimatorController) controller.objectReferenceValue;
            var animatorController = runtimeAnimatorController as AnimatorController;
            if (animatorController == null) return null;
            var layers = animatorController.layers;
            var handLayer = layers.FirstOrDefault(x => x.name == layerName);

            return handLayer?.stateMachine.states.ToList();
        }

        /// <summary>
        /// PlayableLayerの変更可能状態を有効にする
        /// </summary>
        private void EnableLayerEditing()
        {
            var property = this.avatarDesctiptorSerializedObject.FindProperty("customizeAnimationLayers");
            property.boolValue = true;
        }

        /// <summary>
        /// 特定レイヤーにAnimationControllerをセット可能にする
        /// </summary>
        /// <param name="baseAnimLayers"></param>
        /// <param name="index"></param>
        private static void EnableLayer(SerializedProperty baseAnimLayers, int index)
        {
            var layer = baseAnimLayers.GetArrayElementAtIndex(index);
            var isDefault = layer.FindPropertyRelative("isDefault");
            isDefault.boolValue = false;
        }
    }
}
#endif