/*
    A simple little editor extension to copy and paste all components
    Help from http://answers.unity3d.com/questions/541045/copy-all-components-from-one-character-to-another.html
    license: WTFPL (http://www.wtfpl.net/)
    author: aeroson
    advise: ChessMax
    editor: frekons
*/

#if UNITY_EDITOR
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;

public class CopyMultipleComponents : EditorWindow
{
    // Use ScriptableObject to store data between editor sessions
    private class ComponentDataContainer : ScriptableObject
    {
        public List<string> componentData = new List<string>();
        public List<string> componentTypeNames = new List<string>();
    }

    private static ComponentDataContainer dataContainer;

    [MenuItem("Tools/Component Utilities/Copy All Components")]
    static void Copy()
    {
        if (Selection.activeGameObject == null)
        {
            Debug.LogError("No GameObject selected for copying!");
            return;
        }

        // Create or get the data container
        if (dataContainer == null)
            dataContainer = ScriptableObject.CreateInstance<ComponentDataContainer>();

        dataContainer.componentData.Clear();
        dataContainer.componentTypeNames.Clear();

        Component[] components = Selection.activeGameObject.GetComponents<Component>();
        
        foreach (Component component in components)
        {
            if (component == null)
                continue;
                
            // Skip Transform component as it often causes issues
            if (component is Transform)
                continue;
                
            // Store component data as JSON
            string json = EditorJsonUtility.ToJson(component);
            dataContainer.componentData.Add(json);
            dataContainer.componentTypeNames.Add(component.GetType().AssemblyQualifiedName);
        }
        
        if (dataContainer.componentData.Count > 0)
        {
            Debug.Log($"Copied {dataContainer.componentData.Count} components from {Selection.activeGameObject.name}");
        }
        else
        {
            Debug.LogWarning("No components found to copy!");
        }
    }

    [MenuItem("Tools/Component Utilities/Paste All Components")]
    static void Paste()
    {
        if (dataContainer == null || dataContainer.componentData.Count == 0)
        {
            Debug.LogError("Nothing is copied! Use 'Copy All Components' first.");
            return;
        }

        foreach (GameObject targetGameObject in Selection.gameObjects)
        {
            if (!targetGameObject)
                continue;

            Undo.RegisterCompleteObjectUndo(targetGameObject, targetGameObject.name + ": Paste All Components");

            int successCount = 0;
            int failCount = 0;

            for (int i = 0; i < dataContainer.componentTypeNames.Count; i++)
            {
                string typeString = dataContainer.componentTypeNames[i];
                string jsonData = dataContainer.componentData[i];
                
                System.Type componentType = System.Type.GetType(typeString);
                if (componentType == null)
                {
                    Debug.LogError($"Could not find type: {typeString}");
                    failCount++;
                    continue;
                }

                // Check if component already exists
                Component targetComponent = targetGameObject.GetComponent(componentType);
                
                if (targetComponent == null)
                {
                    // Add component if it doesn't exist
                    targetComponent = Undo.AddComponent(targetGameObject, componentType);
                }
                
                if (targetComponent != null)
                {
                    // Apply the JSON data to the component
                    EditorJsonUtility.FromJsonOverwrite(jsonData, targetComponent);
                    successCount++;
                }
                else
                {
                    Debug.LogError($"Failed to add component: {componentType}");
                    failCount++;
                }
            }

            Debug.Log($"Pasted to {targetGameObject.name}: {successCount} components successful, {failCount} failed");
        }
    }

    [MenuItem("Tools/Component Utilities/Delete All Components")]
    static void DeleteAllComponents()
    {
        if (Selection.gameObjects.Length == 0)
        {
            Debug.LogError("No GameObjects selected for component deletion!");
            return;
        }

        foreach (GameObject targetGameObject in Selection.gameObjects)
        {
            if (!targetGameObject)
                continue;

            Undo.RegisterCompleteObjectUndo(targetGameObject, targetGameObject.name + ": Delete All Components");

            Component[] components = targetGameObject.GetComponents<Component>();
            int deletedCount = 0;

            // Start from the end to avoid index issues when destroying components
            for (int i = components.Length - 1; i >= 0; i--)
            {
                Component component = components[i];
                
                // Skip null components
                if (component == null)
                    continue;
                    
                // Skip Transform component as it's required
                if (component is Transform)
                    continue;
                
                // Destroy the component with Undo support
                Undo.DestroyObjectImmediate(component);
                deletedCount++;
            }
            
            Debug.Log($"Deleted {deletedCount} components from {targetGameObject.name}");
        }
    }

    // Add menu items without keyboard shortcuts
    [MenuItem("GameObject/Component Utilities/Copy All Components")]
    static void CopyFromGameObjectMenu()
    {
        Copy();
    }

    [MenuItem("GameObject/Component Utilities/Paste All Components")]
    static void PasteFromGameObjectMenu()
    {
        Paste();
    }

    [MenuItem("GameObject/Component Utilities/Delete All Components")]
    static void DeleteAllComponentsFromGameObjectMenu()
    {
        DeleteAllComponents();
    }
}
#endif
