using NUnit.Framework;
using UnityEngine;
using LLM.Editor.Commands;
using LLM.Editor.Data;
using LLM.Editor.Helper;

namespace LLM.Editor.Tests.Unit
{
    [TestFixture]
    public class SetHierarchyCommandTests
    {
        private GameObject _childObject;
        private GameObject _parentObject;
        private CommandContext _context;
        private string _childLogicalName;
        private string _parentLogicalName;

        [SetUp]
        public void SetUp()
        {
            _childObject = new GameObject("ChildObject");
            _parentObject = new GameObject("ParentObject");
            _context = new CommandContext();
            
            _childLogicalName = "child_1";
            _parentLogicalName = "parent_1";

            var childPid = new PersistentIdentifier
            {
                logicalName = _childLogicalName,
                instanceID = _childObject.GetInstanceID(),
                path = CommandUtility.GetGameObjectPath(_childObject)
            };
            _context.IdentifierMap[_childLogicalName] = childPid;

            var parentPid = new PersistentIdentifier
            {
                logicalName = _parentLogicalName,
                instanceID = _parentObject.GetInstanceID(),
                path = CommandUtility.GetGameObjectPath(_parentObject)
            };
            _context.IdentifierMap[_parentLogicalName] = parentPid;
        }

        [TearDown]
        public void TearDown()
        {
            if (_childObject != null) Object.DestroyImmediate(_childObject);
            if (_parentObject != null) Object.DestroyImmediate(_parentObject);
        }

        private SetHierarchyCommand CreateCommand(string childId, string parentId, int siblingIndex = -1)
        {
            var parameters = new SetHierarchyParams
            {
                childIdentifier = childId,
                parentIdentifier = parentId,
                siblingIndex = siblingIndex
            };
            return new SetHierarchyCommand(parameters.ToJson());
        }

        [Test]
        public void Execute_WithValidParent_SetsParentCorrectly()
        {
            // Arrange
            var command = CreateCommand(_childLogicalName, _parentLogicalName);

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

            // Assert
            Assert.AreEqual(CommandOutcome.Success, outcome);
            Assert.AreEqual(_parentObject.transform, _childObject.transform.parent);
        }

        [Test]
        public void Execute_WithNullParent_MovesToRoot()
        {
            // Arrange
            _childObject.transform.SetParent(_parentObject.transform); // Pre-condition
            var command = CreateCommand(_childLogicalName, null);

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

            // Assert
            Assert.AreEqual(CommandOutcome.Success, outcome);
            Assert.IsNull(_childObject.transform.parent);
        }

        [Test]
        public void Execute_WithSiblingIndex_SetsOrderCorrectly()
        {
            // Arrange
            // Create another child to verify sibling order
            var otherChild = new GameObject("OtherChild");
            otherChild.transform.SetParent(_parentObject.transform);
            
            var command = CreateCommand(_childLogicalName, _parentLogicalName, 0);

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

            // Assert
            Assert.AreEqual(CommandOutcome.Success, outcome);
            Assert.AreEqual(0, _childObject.transform.GetSiblingIndex());
            
            Object.DestroyImmediate(otherChild);
        }

        [Test]
        public void Execute_WithInvalidChildId_ReturnsError()
        {
            // Arrange
            var command = CreateCommand("invalid_id", _parentLogicalName);

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

            // Assert
            Assert.AreEqual(CommandOutcome.Error, outcome);
            Assert.IsNotNull(_context.ErrorMessage);
            Assert.IsTrue(_context.ErrorMessage.Contains("Could not find a valid child GameObject"));
        }
    }
}
