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 CreateAssetCommandTests
    {
        private static string TestFolderName => TestConstants.TestPath;
        private CommandContext _context;

        [SetUp]
        public void SetUp()
        {
            _context = new CommandContext();
            // Create a temporary folder for test assets
            Directory.CreateDirectory(Path.Combine(Application.dataPath, TestFolderName));
            AssetDatabase.Refresh();
        }

        [TearDown]
        public void TearDown()
        {
            // Clean up the temporary folder and its meta file
            var testFolderPath = Path.Combine(Application.dataPath, TestFolderName);
            if (!Directory.Exists(testFolderPath)) return;
            Directory.Delete(testFolderPath, true);
            File.Delete(testFolderPath + ".meta");
            AssetDatabase.Refresh();
        }

        private static CreateAssetCommand CreateCommand(AssetType type, string name, string logicalName, string content = "")
        {
            var parameters = new CreateAssetParams
            {
                assetType = type,
                assetName = name,
                logicalName = logicalName,
                path = $"Assets/{TestFolderName}",
                content = content
            };
            return new CreateAssetCommand(parameters.ToJson());
        }

        [Test]
        public void Execute_CreatesScriptAsset_Successfully()
        {
            // Arrange
            var command = CreateCommand(AssetType.Script, "MyTestScript", "script_1");
            var expectedPath = $"Assets/{TestFolderName}/MyTestScript.cs";

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

            // Assert
            Assert.AreEqual(CommandOutcome.Success, outcome);
            Assert.IsTrue(File.Exists(expectedPath));
            Assert.AreEqual("script_1", (string)_context.CurrentSubject);
            Assert.IsTrue(_context.IdentifierMap.ContainsKey("script_1"));
            Assert.IsNotEmpty(_context.IdentifierMap["script_1"].guid); // Check that a GUID was assigned
        }

        [Test]
        public void Execute_CreatesMaterialAsset_Successfully()
        {
            // Arrange
            var command = CreateCommand(AssetType.Material, "MyTestMaterial", "mat_1");
            var expectedPath = $"Assets/{TestFolderName}/MyTestMaterial.mat";

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

            // Assert
            Assert.AreEqual(CommandOutcome.Success, outcome);
            Assert.IsTrue(File.Exists(expectedPath));
            Assert.IsNotNull(AssetDatabase.LoadAssetAtPath<Material>(expectedPath));
            Assert.IsTrue(_context.IdentifierMap.ContainsKey("mat_1"));
        }

        [Test]
        public void Execute_CreatesFolderAsset_Successfully()
        {
            // Arrange
            var command = CreateCommand(AssetType.Folder, "MySubFolder", "folder_1");
            var expectedPath = $"Assets/{TestFolderName}/MySubFolder";

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

            // Assert
            Assert.AreEqual(CommandOutcome.Success, outcome);
            Assert.IsTrue(Directory.Exists(expectedPath));
            Assert.IsTrue(_context.IdentifierMap.ContainsKey("folder_1"));
        }
        
        [Test]
        public void Execute_CreatesEmptyPrefab_Successfully()
        {
            // Arrange
            var command = CreateCommand(AssetType.Prefab, "MyTestPrefab", "prefab_1");
            var expectedPath = $"Assets/{TestFolderName}/MyTestPrefab.prefab";

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

            // Assert
            Assert.AreEqual(CommandOutcome.Success, outcome);
            Assert.IsTrue(File.Exists(expectedPath));
            Assert.IsNotNull(AssetDatabase.LoadAssetAtPath<GameObject>(expectedPath));
            Assert.IsTrue(_context.IdentifierMap.ContainsKey("prefab_1"));
        }

        [Test]
        public void Execute_WithMissingAssetName_ReturnsError()
        {
            // Arrange
            var parameters = new CreateAssetParams { assetType = AssetType.Script, assetName = "" };
            var command = new CreateAssetCommand(parameters.ToJson());

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

            // Assert
            Assert.AreEqual(CommandOutcome.Error, outcome);
            Assert.IsNotNull(_context.ErrorMessage);
            Assert.IsTrue(_context.ErrorMessage.Contains("assetName is required"));
        }
    }
}
