using System;
using System.Collections.Generic;
using nadena.dev.modular_avatar.animation;
using nadena.dev.ndmf;
using UnityEditor;
using UnityEditor.Animations;
using UnityEngine;

#if MA_VRCSDK3_AVATARS
using VRC.SDK3.Avatars.Components;
using VRC.SDK3.Avatars.ScriptableObjects;
#endif

using Object = UnityEngine.Object;

namespace nadena.dev.modular_avatar.core.editor
{
    internal class BuildContext
    {
        internal readonly nadena.dev.ndmf.BuildContext PluginBuildContext;

#if MA_VRCSDK3_AVATARS
        internal VRCAvatarDescriptor AvatarDescriptor => PluginBuildContext.AvatarDescriptor;
#endif
        internal GameObject AvatarRootObject => PluginBuildContext.AvatarRootObject;
        internal Transform AvatarRootTransform => PluginBuildContext.AvatarRootTransform;

        internal AnimationDatabase AnimationDatabase =>
            PluginBuildContext.Extension<AnimationServicesContext>().AnimationDatabase;

        internal PathMappings PathMappings =>
            PluginBuildContext.Extension<AnimationServicesContext>().PathMappings;

        internal UnityEngine.Object AssetContainer => PluginBuildContext.AssetContainer;

        private bool SaveImmediate = false;

#if MA_VRCSDK3_AVATARS
        internal readonly Dictionary<VRCExpressionsMenu, VRCExpressionsMenu> ClonedMenus
            = new Dictionary<VRCExpressionsMenu, VRCExpressionsMenu>();

        /// <summary>
        /// This dictionary overrides the _original contents_ of ModularAvatarMenuInstallers. Notably, this does not
        /// replace the source menu for the purposes of identifying any other MAMIs that might install to the same
        /// menu asset.
        /// </summary>
        internal readonly Dictionary<ModularAvatarMenuInstaller, Action<VRCExpressionsMenu.Control>> PostProcessControls
            = new Dictionary<ModularAvatarMenuInstaller, Action<VRCExpressionsMenu.Control>>();
#endif
        public static implicit operator BuildContext(ndmf.BuildContext ctx) =>
            ctx.Extension<ModularAvatarContext>().BuildContext;

        public BuildContext(nadena.dev.ndmf.BuildContext PluginBuildContext)
        {
            this.PluginBuildContext = PluginBuildContext;
        }

#if MA_VRCSDK3_AVATARS
        public BuildContext(VRCAvatarDescriptor avatarDescriptor)
            : this(new ndmf.BuildContext(avatarDescriptor, null))
        {
        }
#endif

        public BuildContext(GameObject avatarGameObject)
            : this(new ndmf.BuildContext(avatarGameObject, null))
        {
        }

        public void SaveAsset(Object obj)
        {
            if (!SaveImmediate || AssetDatabase.IsMainAsset(obj) || AssetDatabase.IsSubAsset(obj)) return;

            AssetDatabase.AddObjectToAsset(obj, AssetContainer);
        }

        public AnimatorController CreateAnimator(AnimatorController toClone = null)
        {
            AnimatorController controller;
            if (toClone != null)
            {
                controller = Object.Instantiate(toClone);
            }
            else
            {
                controller = new AnimatorController();
            }

            SaveAsset(controller);

            return controller;
        }

        public AnimatorController DeepCloneAnimator(RuntimeAnimatorController controller)
        {
            if (controller == null) return null;

            var merger = new AnimatorCombiner(PluginBuildContext, controller.name + " (clone)");
            switch (controller)
            {
                case AnimatorController ac:
                    merger.AddController("", ac, null);
                    break;
                case AnimatorOverrideController oac:
                    merger.AddOverrideController("", oac, null);
                    break;
                default:
                    throw new Exception("Unknown RuntimeAnimatorContoller type " + controller.GetType());
            }

            var result = merger.Finish();

            ObjectRegistry.RegisterReplacedObject(controller, result);

            return result;
        }

        public AnimatorController ConvertAnimatorController(RuntimeAnimatorController anyController)
        {
            switch (anyController)
            {
                case AnimatorController ac:
                    return ac;
                case AnimatorOverrideController aoc:
                    var merger = new AnimatorCombiner(PluginBuildContext, anyController.name + " (clone)");
                    merger.AddOverrideController("", aoc, null);
                    return merger.Finish();
                default:
                    throw new Exception("Unknown RuntimeAnimatorContoller type " + anyController.GetType());
            }
        }

#if MA_VRCSDK3_AVATARS
        public VRCExpressionsMenu CloneMenu(VRCExpressionsMenu menu)
        {
            if (menu == null) return null;
            if (ClonedMenus.TryGetValue(menu, out var newMenu)) return newMenu;
            newMenu = Object.Instantiate(menu);
            this.SaveAsset(newMenu);
            ClonedMenus[menu] = newMenu;

            foreach (var control in newMenu.controls)
            {
                if (control.type == VRCExpressionsMenu.Control.ControlType.SubMenu && control.subMenu != newMenu)
                {
                    control.subMenu = CloneMenu(control.subMenu);
                }
            }

            return newMenu;
        }
#endif
    }
}