using System.Linq;
using System.Text.RegularExpressions;
using UnityEngine;
using Object = UnityEngine.Object;

namespace LLM.Editor.Analysis
{
    /// <summary>
    /// Provides a list of GameObjects found in the current scene based on a query.
    /// Supports searching by name (with wildcards), component type, or tag.
    /// </summary>
    public class FindInSceneProvider : IContextProvider
    {
        public class SceneQueryResult
        {
            public string name;
            public string id;
        }

        public object GetContext(Object target, string qualifier)
        {
            if (string.IsNullOrEmpty(qualifier))
            {
                return "Error: A query string (qualifier) is required for FindInScene (e.g., 'name: Player', 'component: Rigidbody', 'tag: Enemy').";
            }

            var gameObjects = Object.FindObjectsOfType<GameObject>();
            var queryParts = qualifier.Split(new[] { ':' }, 2);
            var queryType = queryParts[0].Trim().ToLower();
            var queryValue = queryParts.Length > 1 ? queryParts[1].Trim() : "";

            var results = gameObjects.AsQueryable();

            switch (queryType)
            {
                case "name":
                    var pattern = WildcardToRegex(queryValue);
                    results = results.Where(go => Regex.IsMatch(go.name, pattern, RegexOptions.IgnoreCase));
                    break;
                case "component":
                    var componentType = GetTypeByName(queryValue);
                    if (componentType != null)
                    {
                        results = results.Where(go => go.GetComponent(componentType));
                    }
                    else
                    {
                        // If the type can't be found, return no results.
                        results = Enumerable.Empty<GameObject>().AsQueryable();
                    }
                    break;
                case "tag":
                    results = results.Where(go => go.CompareTag(queryValue));
                    break;
                case "layer":
                    results = results.Where(go => go.layer == LayerMask.NameToLayer(queryValue));
                    break;
                default:
                    return $"Error: Invalid query type '{queryType}'. Use 'name', 'component', or 'tag'.";
            }

            // Return a structured result with name and instance ID for each found object.
            return results.Select(go => new SceneQueryResult { name = go.name, id = go.GetInstanceID().ToString() }).ToList();
        }
        
        private static System.Type GetTypeByName(string typeName)
        {
            foreach (var assembly in System.AppDomain.CurrentDomain.GetAssemblies())
            {
                var type = assembly.GetType(typeName);
                if (type != null) return type;
            }
            return null;
        }
        
        private static string WildcardToRegex(string value)
        {
            return "^" + Regex.Escape(value).Replace("\\*", ".*").Replace("\\?", ".") + "$";
        }
    }
}
