using NUnit.Framework;
using LLM.Editor.Analysis;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

namespace LLM.Editor.Tests.Unit
{
    // A helper component for testing schema discovery
    public class SchemaTestComponent : MonoBehaviour
    {
        public int publicField;
        public string PublicProperty { get; set; }
        [SerializeField] protected bool protectedField;
        internal int internalField; // Should not be found
        private string PrivateProperty { get; set; } // Should not be found
        [System.Obsolete]
        public int obsoleteField; // Should not be found
        [HideInInspector]
        public float hiddenField; // Should not be found
    }

    [TestFixture]
    public class GetComponentSchemaProviderTests
    {
        private GetComponentSchemaProvider _provider;

        [SetUp]
        public void SetUp()
        {
            _provider = new GetComponentSchemaProvider();
        }

        [Test]
        public void GetContext_WithStandardComponent_ReturnsCorrectSchema()
        {
            // Arrange
            var qualifier = "UnityEngine.Transform";

            // Act
            var context = _provider.GetContext(null, qualifier);

            // Assert
            Assert.IsInstanceOf<List<GetComponentSchemaProvider.MemberSchema>>(context);
            var schema = (List<GetComponentSchemaProvider.MemberSchema>)context;
            Assert.IsNotEmpty(schema);
            
            var memberNames = schema.Select(s => s.name).ToList();
            
            // Check for some well-known, writable properties of Transform
            Assert.Contains("position", memberNames);
            Assert.Contains("rotation", memberNames);
            Assert.Contains("localScale", memberNames);
            Assert.Contains("parent", memberNames);
        }

        [Test]
        public void GetContext_WithCustomComponent_ReturnsCorrectSchema()
        {
            // Arrange
            var qualifier = "LLM.Editor.Tests.Unit.SchemaTestComponent";

            // Act
            var context = _provider.GetContext(null, qualifier);
            
            // Assert
            Assert.IsInstanceOf<List<GetComponentSchemaProvider.MemberSchema>>(context);
            var schema = (List<GetComponentSchemaProvider.MemberSchema>)context;
            
            var memberNames = schema.Select(s => s.name).ToList();
            
            // 1. Check for members defined in SchemaTestComponent
            Assert.Contains("publicField", memberNames, "Should find public fields.");
            Assert.Contains("PublicProperty", memberNames, "Should find public properties.");
            Assert.Contains("protectedField", memberNames, "Should find fields with [SerializeField] attribute.");

            // 2. Check for inherited members from MonoBehaviour/Behaviour
            Assert.Contains("enabled", memberNames, "Should find inherited public properties like 'enabled'.");
            Assert.Contains("tag", memberNames, "Should find inherited public properties like 'tag'.");

            // 3. Check that non-serialized or obsolete members are excluded
            Assert.IsFalse(memberNames.Contains("internalField"), "Internal fields without [SerializeField] should be excluded.");
            Assert.IsFalse(memberNames.Contains("PrivateProperty"), "Private properties should be excluded.");
            Assert.IsFalse(memberNames.Contains("obsoleteField"), "Obsolete members should be excluded.");
            Assert.IsFalse(memberNames.Contains("hiddenField"), "Members with [HideInInspector] should be excluded.");
        }

        [Test]
        public void GetContext_WithInvalidType_ReturnsErrorString()
        {
            // Arrange
            var qualifier = "Invalid.Component.TypeName";

            // Act
            var context = _provider.GetContext(null, qualifier);

            // Assert
            Assert.IsInstanceOf<string>(context);
            Assert.IsTrue(((string)context).Contains("Could not find a Component type"));
        }
    }
}
