using System.Collections.Generic;
using System.Linq;
using AnimatorAsCode.V1;
using gay.lilyy.aaccore;
using gay.lilyy.aacshared.runtimecomponents;
using UnityEditor;
using UnityEngine;
using VRC.SDK3.Avatars.ScriptableObjects;
using AnimatorAsCode.V1.ModularAvatar;
using nadena.dev.modular_avatar.core;

namespace gay.lilyy.aacshared.layers {
    [InitializeOnLoad]
    public class ChildToggle : LayerGroup
    {
        // remove when ready for uploaded
        public override bool experimental => false;
        public override bool shouldWarnIfNotApplicable => false;
        private static readonly ChildToggle _instance = new();
        
        static ChildToggle() {}

        public override string DisplayName => "Child Toggle";
        public override string SystemName => "childtoggle";

        private static ChildToggleDefinition[] getDefinitions(AACAssets assets)
        {
            return assets.ctx.AvatarRootObject.GetComponentsInChildren<ChildToggleDefinition>();
        }

        public override bool IsApplicable(AACAssets assets)
        {
            return getDefinitions(assets).Length > 0;
        }

        private AacFlBoolParameter createLayer(AACAssets assets, ChildToggleDefinition definition, Transform transform)
        {
            var layer = assets.fx.NewLayer($"Child toggle {definition.name} {transform.name}");
            var toggle = layer.BoolParameter($"child_{definition.name}_{transform.name}");

            var idle = layer.NewState("Idle").WithAnimation(assets.emptyClip);
            var flipped = layer.NewState("Flipped").WithAnimation(assets.aac.NewClip().Toggling(transform.gameObject, !transform.gameObject.activeSelf));

            idle.TransitionsTo(flipped).When(toggle.IsEqualTo(true));
            flipped.TransitionsTo(idle).When(toggle.IsEqualTo(false));

            return toggle;
        }

        /**
            <summary>
                im gonna be so honest i got cursor to hack together my MusicPlayer's menu creator into this monstrosity. im so sorry.
            </summary>
            <param name="assets">The AACAssets instance.</param>
            <param name="definition">The ChildToggleDefinition instance.</param>
            <param name="childParameters">A dictionary of child transforms and their corresponding toggle parameters.</param>
            <param name="sharedFolderHierarchy">A shared dictionary of folder paths to GameObjects across all definitions.</param>
        */
        private GameObject FindOrCreateFolder(GameObject parent, string folderName, Dictionary<string, GameObject> sharedFolderHierarchy, string fullPath, Transform definitionTransform, HashSet<GameObject> allRootMenus)
        {
            // Check if folder already exists in shared hierarchy
            if (sharedFolderHierarchy.ContainsKey(fullPath))
            {
                var existingFolder = sharedFolderHierarchy[fullPath];
                // Verify it still exists and is accessible
                if (existingFolder != null)
                {
                    return existingFolder;
                }
                else
                {
                    // Remove stale entry
                    sharedFolderHierarchy.Remove(fullPath);
                }
            }
            
            // Check if a folder with the same name already exists as a sibling in current parent
            foreach (Transform child in parent.transform)
            {
                var existingMenuItem = child.GetComponent<ModularAvatarMenuItem>();
                if (existingMenuItem != null && existingMenuItem.label == folderName)
                {
                    // Found existing folder, add it to shared hierarchy and return it
                    sharedFolderHierarchy[fullPath] = child.gameObject;
                    return child.gameObject;
                }
            }
            
            // Check all other root menus for a folder with the same name at the same level
            // This prevents duplicate folders when multiple definitions share the same MenuPath prefix
            foreach (var rootMenu in allRootMenus)
            {
                if (rootMenu == parent) continue; // Skip current menu
                
                // If we're at root level (parent is a Menu_*), check root level of other menus
                // If we're in a nested folder, check the same nesting level
                if (parent.name.StartsWith("Menu_") && rootMenu.name.StartsWith("Menu_"))
                {
                    // Check root level folders
                    foreach (Transform child in rootMenu.transform)
                    {
                        var existingMenuItem = child.GetComponent<ModularAvatarMenuItem>();
                        if (existingMenuItem != null && existingMenuItem.label == folderName)
                        {
                            // Found existing folder in another root menu, reuse it
                            sharedFolderHierarchy[fullPath] = child.gameObject;
                            return child.gameObject;
                        }
                    }
                }
            }
            
            // Create new folder
            var folderGo = new GameObject($"Folder_{folderName}");
            folderGo.transform.SetParent(parent.transform);
            var folderMenuItem = folderGo.AddComponent<ModularAvatarMenuItem>();
            folderMenuItem.label = folderName;
            folderMenuItem.Control.type = VRCExpressionsMenu.Control.ControlType.SubMenu;
            folderMenuItem.MenuSource = SubmenuSource.Children;
            
            sharedFolderHierarchy[fullPath] = folderGo;
            return folderGo;
        }

        private void CreateMenu(AACAssets assets, ChildToggleDefinition definition, Dictionary<Transform, AacFlBoolParameter> childParameters, Dictionary<string, GameObject> sharedFolderHierarchy, HashSet<GameObject> allRootMenus)
        {
            if (childParameters.Count == 0) return;

            var menuGo = new GameObject($"Menu_{definition.name}");
            menuGo.transform.SetParent(definition.transform);
            var menuItem = menuGo.AddComponent<ModularAvatarMenuItem>();
            menuItem.label = "Child Toggle";
            menuItem.Control.type = VRCExpressionsMenu.Control.ControlType.SubMenu;
            menuItem.MenuSource = SubmenuSource.Children;
            
            allRootMenus.Add(menuGo);

            GameObject firstFolder = null;

            foreach (var kvp in childParameters)
            {
                var childTransform = kvp.Key;
                var toggleParam = kvp.Value;
                GameObject currentParent = menuGo;
                
                // Create folder hierarchy if MenuPath is specified
                if (!string.IsNullOrEmpty(definition.MenuPath))
                {
                    string[] folderPath = definition.MenuPath.Split('/');
                    
                    // Create nested folder structure
                    for (int i = 0; i < folderPath.Length; i++)
                    {
                        string folderName = folderPath[i];
                        string fullPath = string.Join("/", folderPath, 0, i + 1);
                        
                        currentParent = FindOrCreateFolder(currentParent, folderName, sharedFolderHierarchy, fullPath, definition.transform, allRootMenus);
                        
                        // Store the first folder for MenuInstaller
                        if (firstFolder == null && i == 0)
                        {
                            firstFolder = currentParent;
                        }
                    }
                }
                
                // Create the toggle menu item
                var go = new GameObject($"Toggle_{childTransform.name}");
                go.transform.SetParent(currentParent.transform);
                assets.modularAvatar.EditMenuItem(go).Toggle(toggleParam).Name(childTransform.name);
            }
            
            // Place MenuInstaller on the first folder if it exists, otherwise on root menu
            if (firstFolder != null)
            {
                // Only add MenuInstaller if it doesn't already exist
                if (firstFolder.GetComponent<ModularAvatarMenuInstaller>() == null)
                {
                    firstFolder.AddComponent<ModularAvatarMenuInstaller>();
                }
            }
            else
            {
                menuGo.AddComponent<ModularAvatarMenuInstaller>();
            }
        }

        private void runDefinition(AACAssets assets, ChildToggleDefinition definition, Dictionary<string, GameObject> sharedFolderHierarchy, HashSet<GameObject> allRootMenus)
        {
            var childParameters = new Dictionary<Transform, AacFlBoolParameter>();
            
            foreach (Transform child in definition.transform)
            {
                var toggleParam = createLayer(assets, definition, child);
                childParameters[child] = toggleParam;
            }

            CreateMenu(assets, definition, childParameters, sharedFolderHierarchy, allRootMenus);
        }

        public override void Run(AACAssets assets)
        {
            var definitions = getDefinitions(assets);
            Logger.LogDebug($"Child Toggle system: Found {definitions.Length} child toggle definitions");

            // Shared folder hierarchy across all definitions to prevent duplicates
            var sharedFolderHierarchy = new Dictionary<string, GameObject>();
            // Track all root menus to check for duplicate folders
            var allRootMenus = new HashSet<GameObject>();

            foreach (var definition in definitions)
            {
                runDefinition(assets, definition, sharedFolderHierarchy, allRootMenus);
            }
        }
    }
}