using UnityEngine;

namespace Cogwheel
{
    public static class COGWHEEL
    {
        public static ICommandsManager CommandsManager { get; private set; }
        public static CogwheelSettings Settings { get; private set; }
        public static CogwheelConsole Console { get; private set; }

        public static void Start(CogwheelSettings settings, ICommandsManager commandsManager, CogwheelConsole console)
        {
            Settings = settings;
            CommandsManager = commandsManager;
            Console = console;
        }

        #region BUILT-IN COMMANDS

        [Command(Description = "Logs a message to the console.")]
        public static void Log(string message)
        {
            Console.Log(message);
        }
        
        [Command(Description = "Logs an error message to the console.")]
        public static void LogError(string message)
        {
            Console.LogError(message);
        }

        [Command(Description = "Logs a warning to the console.")]
        public static void LogWarning(string message)
        {
            Console.LogWarning(message);
        }
        
        [Command(Description = "Clears the console.")]
        public static void Clear()
        {
            Console.Clear();
        }
        
        [Command(Description = "Lists available commands for the current context. Use '-a' to list all commands in registry.")]
        public static void List(string arg = "")
        {
            foreach (var command in CommandsManager.Commands.Values)
            {
                if (command.Method.IsStatic)
                {
                    Log($"{command.Name} - {command.Description}");
                }
                else
                {
                    if (arg == "-a")
                    {
                        Log(CommandsManager.IsCommandContextValid(command)
                            ? $"<color=green>({command.Method.DeclaringType.Name})</color> : {command.Name} - <i>{command.Description}</i>"
                            : $"<color=#333333>({command.Method.DeclaringType.Name})</color> : {command.Name} - <i>{command.Description}</i>");
                    }

                    if (CommandsManager.IsCommandContextValid(command))
                    {
                        Log($"<color=green>({command.Method.DeclaringType.Name})</color> : {command.Name} - <i>{command.Description}</i>");
                    }
                }
            }
        }

        [Command(Description = "Gets usage for a given command")]
        public static void Help(string commandName)
        {
            
            Command command = CommandsManager.GetCommandByName(commandName);
            if (command is null)
            {
                Console.LogError($"Command error: '{commandName}' is not a command.");
                return;
            }

            Console.Log($"-- Command Usage For {commandName} --\n" +
                                $"Description: {command.Description}\n" +
                                $"Usage: {CommandsManager.GetCommandUsage(command)}");
        }

        [Command(CommandName = "cd", Description = "Sets the context to the given path\n(If no specific path is given, it will set the context to the first object with the given name found in the scene)")]
        public static void SetContextByName(string name)
        {
            CommandsManager.SetContext(name);
        }

        [Command(CommandName = "ctx", Description = "Prints out the current Context name")]
        public static void PrintContext()
        {
            if (CommandsManager.Context is null)
            {
                LogWarning("No context set.");
                return;
            }
            Log($"-- CONTEXT <i>{CommandsManager.Context.name}</i> --");
            Log("-Components-");
            if (CommandsManager.Context.GetComponentCount() < 1)
            {
                LogWarning("No components found on this object.");
                return;
            }
            foreach (var component in CommandsManager.Context.GetComponents<MonoBehaviour>())
            {
                Log($"<color=green>- {component.GetType()}</color>");
            }
        }

        [Command(CommandName = "tree", Description = "Prints the hierarchy of the scene")]
        public static void PrintObjectsInHierarchy()
        {
            foreach (var rootObject in UnityEngine.SceneManagement.SceneManager.GetActiveScene().GetRootGameObjects())
            {
               PrintHierarchy(rootObject.transform, 0); 
            }
        }
        
        private static void PrintHierarchy(Transform transform, int indentLevel)
        {
            string indent = new string(' ', indentLevel * 2);
            Log($"{indent}- {transform.name}");
            for (int i = 0; i < transform.childCount; i++)
            {
                PrintHierarchy(transform.GetChild(i), indentLevel + 1);
            }
        }
        
        #endregion
    }
}