using UnityEngine;
using NUnit.Framework;
using LLM.Editor.Commands;
using LLM.Editor.Data;
using LLM.Editor.Helper;
using UnityEngine.TestTools; // Required for LogAssert

namespace LLM.Editor.Tests.Unit
{
    [TestFixture]
    public class RenameGameObjectCommandTests
    {
        private GameObject _testObject;
        private CommandContext _context;

        [SetUp]
        public void SetUp()
        {
            // Create a new GameObject before each test
            _testObject = new GameObject("TestObject");
            // Create a fresh context for each test
            _context = new CommandContext();
        }

        [TearDown]
        public void TearDown()
        {
            // Clean up the GameObject after each test
            if (_testObject != null)
            {
                Object.DestroyImmediate(_testObject);
            }
        }

        [Test]
        public void Execute_WithValidParams_RenamesObjectSuccessfully()
        {
            // Arrange
            var parameters = new RenameGameObjectParams
            {
                targetIdentifier = _testObject.GetInstanceID(),
                newName = "RenamedObject"
            };
            var command = new RenameGameObjectCommand(parameters.ToJson());

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

            // Assert
            Assert.AreEqual(CommandOutcome.Success, outcome, "Command should execute successfully.");
            Assert.AreEqual("RenamedObject", _testObject.name, "GameObject name should be updated.");
            Assert.IsNull(_context.ErrorMessage, "Error message should be null on success.");
        }

        [Test]
        public void Execute_WithNonExistentTarget_ReturnsError()
        {
            // Arrange
            var nonExistentId = -12345;
            var parameters = new RenameGameObjectParams
            {
                targetIdentifier = nonExistentId,
                newName = "WontBeUsed"
            };
            var command = new RenameGameObjectCommand(parameters.ToJson());

            // We expect a specific error log message. This tells the test runner that the log is part of the test.
            LogAssert.Expect(LogType.Error, $"[RenameGameObjectCommand] Could not find GameObject with ID: {nonExistentId}");

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

            // Assert
            Assert.AreEqual(CommandOutcome.Error, outcome, "Command should return an error.");
            Assert.IsNotNull(_context.ErrorMessage, "Error message should be set on failure.");
            Assert.IsTrue(_context.ErrorMessage.Contains($"Could not find GameObject with ID: {nonExistentId}"));
        }

        [Test]
        public void Execute_WithEmptyNewName_ReturnsError()
        {
            // Arrange
            var parameters = new RenameGameObjectParams
            {
                targetIdentifier = _testObject.GetInstanceID(),
                newName = "" // Invalid empty name
            };
            var command = new RenameGameObjectCommand(parameters.ToJson());

            // We expect a specific error log message.
            LogAssert.Expect(LogType.Error, "[RenameGameObjectCommand] Invalid parameters: targetIdentifier and newName are required.");

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



            // Assert
            Assert.AreEqual(CommandOutcome.Error, outcome, "Command should return an error for empty name.");
            Assert.AreEqual("TestObject", _testObject.name, "GameObject name should not be changed.");
            Assert.IsNotNull(_context.ErrorMessage, "Error message should be set for invalid parameters.");
            Assert.IsTrue(_context.ErrorMessage.Contains("Invalid parameters"));
        }
        
        [Test]
        public void Execute_WithNullJson_ReturnsError()
        {
            // Arrange
            var command = new RenameGameObjectCommand(null);
            
            // We expect a specific error log message.
            LogAssert.Expect(LogType.Error, "[RenameGameObjectCommand] Invalid parameters: targetIdentifier and newName are required.");

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

            // Assert
            Assert.AreEqual(CommandOutcome.Error, outcome, "Command should return an error for null JSON.");
            Assert.IsNotNull(_context.ErrorMessage, "Error message should be set for invalid parameters.");
            Assert.IsTrue(_context.ErrorMessage.Contains("Invalid parameters"));
        }
    }
}