using System;
using JetBrains.Annotations;
using LLM.Editor.Helper;
using UnityEditor;
using UnityEngine;

namespace LLM.Editor.Commands
{
    [Serializable]
    public class InstantiatePrefabParams
    {
        public string prefabIdentifier; // The logical name of the prefab asset
    }
    
    [UsedImplicitly]
    public class InstantiatePrefabCommand : ICommand
    {
        private readonly InstantiatePrefabParams _params;

        public InstantiatePrefabCommand(string jsonParams)
        {
            _params = jsonParams.FromJson<InstantiatePrefabParams>();
        }

        public CommandOutcome Execute(Data.CommandContext context)
        {
            if (_params == null || string.IsNullOrEmpty(_params.prefabIdentifier))
            {
                context.ErrorMessage = "Invalid parameters: prefabIdentifier is required.";
                return CommandOutcome.Error;
            }

            var resolvedObject = CommandUtility.ResolveIdentifier(context, _params.prefabIdentifier);
            if (resolvedObject is not GameObject prefab)
            {
                context.ErrorMessage = $"Could not resolve prefab with logical name '{_params.prefabIdentifier}'. It may not exist or is not a valid GameObject.";
                return CommandOutcome.Error;
            }

            var instance = (GameObject)PrefabUtility.InstantiatePrefab(prefab);
            if (instance == null)
            {
                context.ErrorMessage = $"Failed to instantiate prefab '{prefab.name}'. It may be empty or corrupted.";
                return CommandOutcome.Error;
            }
            
            Undo.RegisterCreatedObjectUndo(instance, "Instantiate " + instance.name);
            Selection.activeObject = instance;

            Debug.Log($"[InstantiatePrefabCommand] Instantiated '{prefab.name}' into the scene.");
            
            // Create a new logical name for the instance in the scene
            var logicalName = $"{instance.name}_{Guid.NewGuid():N}";
            var pId = new Data.PersistentIdentifier
            {
                logicalName = logicalName,
                instanceID = instance.GetInstanceID(),
                path = CommandUtility.GetGameObjectPath(instance)
            };
            context.IdentifierMap[logicalName] = pId;
            context.CurrentSubject = logicalName;
            
            return CommandOutcome.Success;
        }
        
        private static string GetGameObjectPath(GameObject obj)
        {
            var path = "/" + obj.name;
            while (obj.transform.parent != null)
            {
                obj = obj.transform.parent.gameObject;
                path = "/" + obj.name + path;
            }
            return path;
        }
    }
}