using NUnit.Framework;
using UnityEngine;
using UnityEditor;
using System.IO;
using LLM.Editor.Commands;
using LLM.Editor.Data;
using LLM.Editor.Helper;

namespace LLM.Editor.Tests.Unit
{
    [TestFixture]
    public class InstantiatePrefabCommandTests
    {
        private const string TestPrefabName = "TempTestPrefab.prefab";
        private string _testPrefabPath;
        private GameObject _prefabObject;
        private CommandContext _context;
        private GameObject _instantiatedObject;

        [SetUp]
        public void SetUp()
        {
            _context = new CommandContext();
            
            // Create a dummy prefab asset
            _testPrefabPath = Path.Combine("Assets", TestPrefabName);
            var sourceObject = new GameObject("MyPrefab");
            _prefabObject = PrefabUtility.SaveAsPrefabAsset(sourceObject, _testPrefabPath);
            Object.DestroyImmediate(sourceObject);
            
            Assert.IsNotNull(_prefabObject, "Setup failed: Could not create test prefab.");
            
            // Register the prefab asset with the context
            var guid = AssetDatabase.AssetPathToGUID(_testPrefabPath);
            var pid = new PersistentIdentifier { logicalName = "my_prefab_1", guid = guid };
            _context.IdentifierMap["my_prefab_1"] = pid;
        }

        [TearDown]
        public void TearDown()
        {
            // Clean up the instantiated object and the prefab asset
            if (_instantiatedObject != null)
            {
                Object.DestroyImmediate(_instantiatedObject);
            }
            if (File.Exists(_testPrefabPath))
            {
                AssetDatabase.DeleteAsset(_testPrefabPath);
            }
        }

        [Test]
        public void Execute_WithValidPrefabId_InstantiatesObjectAndCreatesNewLogicalName()
        {
            // Arrange
            var parameters = new InstantiatePrefabParams { prefabIdentifier = "my_prefab_1" };
            var command = new InstantiatePrefabCommand(parameters.ToJson());

            // Act
            var outcome = command.Execute(_context);
            
            // Assert
            Assert.AreEqual(CommandOutcome.Success, outcome);
            
            // Check that a *new* logical name for the instance was created
            Assert.IsNotNull(_context.CurrentSubject);
            var newLogicalName = (string)_context.CurrentSubject;
            Assert.AreNotEqual("my_prefab_1", newLogicalName);
            Assert.IsTrue(newLogicalName.StartsWith(_prefabObject.name));
            Assert.IsTrue(_context.IdentifierMap.ContainsKey(newLogicalName));

            // Find the instantiated object using the path registered by the command itself
            var instancePid = _context.IdentifierMap[newLogicalName];
            _instantiatedObject = EditorUtility.InstanceIDToObject(instancePid.instanceID) as GameObject;
            Assert.IsNotNull(_instantiatedObject, "Prefab should be instantiated and found via its registered instance ID.");
        }

        [Test]
        public void Execute_WithInvalidPrefabId_ReturnsError()
        {
            // Arrange
            var parameters = new InstantiatePrefabParams { prefabIdentifier = "invalid_prefab_id" };
            var command = new InstantiatePrefabCommand(parameters.ToJson());

            // Act
            var outcome = command.Execute(_context);

            // Assert
            Assert.AreEqual(CommandOutcome.Error, outcome);
            Assert.IsNotNull(_context.ErrorMessage);
            Assert.IsTrue(_context.ErrorMessage.Contains("Could not resolve prefab"));
        }
    }
}
