using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using System.Linq;
using System.IO;

namespace VRCDeveloperTool
{
    public class ShapeKeyDeleter : EditorWindow
    {
        private SkinnedMeshRenderer renderer;

        private List<string> shapeKeyNames;
        private bool[] selectedShapeKeys;
        private bool isOpenedBlendShape = true;
        private Vector2 shapeKeyScrollPos = Vector2.zero;

        private int lastSelectedIndex = -1;  // 마지막 선택된 인덱스 저장

        [MenuItem("VRCDeveloperTool/Mesh/ShapeKey Deleter")]
        private static void Open()
        {
            GetWindow<ShapeKeyDeleter>("ShapeKey Deleter");
        }

        private void OnEnable()
        {
            renderer = null;
            shapeKeyNames = null;
            selectedShapeKeys = null;
            isOpenedBlendShape = true;
            shapeKeyScrollPos = Vector2.zero;
        }

        private void OnGUI()
        {
            using (var check = new EditorGUI.ChangeCheckScope())
            {
                renderer = EditorGUILayout.ObjectField(
                                "SkinnedMeshRenderer",
                                renderer,
                                typeof(SkinnedMeshRenderer),
                                true
                            ) as SkinnedMeshRenderer;

                if (check.changed)
                {
                    if (renderer != null)
                    {
                        shapeKeyNames = GetBlendShapeListFromRenderer(renderer);
                        selectedShapeKeys = new bool[shapeKeyNames.Count()];
                    }
                }
            }

            if (shapeKeyNames != null)
            {
                isOpenedBlendShape = EditorGUILayout.Foldout(isOpenedBlendShape, "Shape Keys");
                if (isOpenedBlendShape)
                {
                    using (new EditorGUI.IndentLevelScope())
                    using (var scroll = new EditorGUILayout.ScrollViewScope(shapeKeyScrollPos, GUI.skin.box))
                    {
                        shapeKeyScrollPos = scroll.scrollPosition;

                        Event e = Event.current;

                        for (int i = 0; i < shapeKeyNames.Count(); i++)
                        {
                            bool originalValue = selectedShapeKeys[i];
                            bool newValue = EditorGUILayout.ToggleLeft(shapeKeyNames[i], selectedShapeKeys[i]);

                            // Shift 클릭 처리
                            if (e.shift && lastSelectedIndex != -1 && newValue != originalValue)
                            {
                                int startIndex = Mathf.Min(lastSelectedIndex, i);
                                int endIndex = Mathf.Max(lastSelectedIndex, i);
                                for (int j = startIndex; j <= endIndex; j++)
                                {
                                    selectedShapeKeys[j] = true;
                                }
                            }

                            // 마지막 선택된 인덱스 갱신
                            if (newValue != originalValue)
                            {
                                lastSelectedIndex = i;
                            }

                            selectedShapeKeys[i] = newValue;
                        }
                    }
                }
            }

            using (new EditorGUI.DisabledScope(renderer == null || (selectedShapeKeys != null && selectedShapeKeys.All(x => !x))))
            {
                if (GUILayout.Button("Delete ShapeKeys"))
                {
                    var selectedBlendShapeIndexs = selectedShapeKeys
                        .Select((isSelect, index) => new { Index = index, Value = isSelect })
                        .Where(x => x.Value)
                        .Select(x => x.Index)
                        .ToArray();

                    DeleteShapeKey(renderer, selectedBlendShapeIndexs);

                    shapeKeyNames = GetBlendShapeListFromRenderer(renderer);
                    selectedShapeKeys = new bool[shapeKeyNames.Count()];
                }
            }
        }

        private bool DeleteShapeKey(SkinnedMeshRenderer renderer, int[] selectedShapeKeyIndexs)
        {
            var mesh = renderer.sharedMesh;
            if (mesh == null) return false;

            var mesh_custom = Instantiate(mesh);

            mesh_custom.ClearBlendShapes();

            int frameIndex = 0;
            string shapeKeyName;
            float weight;
            Vector3[] deltaVertices, deltaNormals, deltaTangents;

            for (int blendShapeIndex = 0; blendShapeIndex < mesh.blendShapeCount; blendShapeIndex++)
            {
                deltaVertices = new Vector3[mesh.vertexCount];
                deltaNormals = new Vector3[mesh.vertexCount];
                deltaTangents = new Vector3[mesh.vertexCount];
                mesh.GetBlendShapeFrameVertices(blendShapeIndex, frameIndex, deltaVertices, deltaNormals, deltaTangents);
                weight = mesh.GetBlendShapeFrameWeight(blendShapeIndex, frameIndex);

                if (!selectedShapeKeyIndexs.Contains(blendShapeIndex))
                {
                    shapeKeyName = mesh.GetBlendShapeName(blendShapeIndex);
                    mesh_custom.AddBlendShapeFrame(shapeKeyName, weight, deltaVertices, deltaNormals, deltaTangents);
                }
            }

            Undo.RecordObject(renderer, "Renderer " + renderer.name);
            renderer.sharedMesh = mesh_custom;

            var path = Path.GetDirectoryName(AssetDatabase.GetAssetPath(mesh)) + "/" + mesh.name + "_shapekeydeleted.asset";
            AssetDatabase.CreateAsset(mesh_custom, AssetDatabase.GenerateUniqueAssetPath(path));
            AssetDatabase.SaveAssets();

            return true;
        }

        private List<string> GetBlendShapeListFromRenderer(SkinnedMeshRenderer renderer)
        {
            List<string> shapeKeyNames = new List<string>();
            var mesh = renderer.sharedMesh;

            if (mesh != null)
                for (int i = 0; i < mesh.blendShapeCount; i++)
                    shapeKeyNames.Add(mesh.GetBlendShapeName(i));

            return shapeKeyNames;
        }
    }
}
