using System;
using System.Linq;
using UnityEditor;
using UnityEngine;
using LLM.Editor.Data;
using System.Reflection;
using LLM.Editor.Commands;
using System.Collections.Generic;
namespace LLM.Editor.Core
{
///
/// Responsible for finding and executing commands from the session queue.
///
[InitializeOnLoad]
public static class CommandExecutor
{
private static List _commandQueue;
private static CommandContext _currentContext;
public static Action OnQueueUpdated;
static CommandExecutor()
{
// This will run when the editor loads, including after a recompile.
EditorApplication.delayCall += Initialize;
}
private static void Initialize()
{
Debug.Log("[CommandExecutor] Initializing...");
if (SessionManager.HasActiveSession())
{
_commandQueue = SessionManager.LoadCommandQueue();
if (!_commandQueue.Any())
{
SessionManager.EndSession();
return;
}
Debug.Log($"[CommandExecutor] Resuming session with {_commandQueue.Count} commands in queue.");
_currentContext = new CommandContext();
OnQueueUpdated?.Invoke();
}
else
{
_commandQueue = new List();
}
}
public static void SetQueue(List commands)
{
_commandQueue = commands;
_currentContext = new CommandContext();
SessionManager.SaveCommandQueue(_commandQueue);
OnQueueUpdated?.Invoke();
}
private static void ClearQueue()
{
_commandQueue.Clear();
SessionManager.SaveCommandQueue(_commandQueue);
OnQueueUpdated?.Invoke();
}
public static bool HasPendingCommands() => _commandQueue != null && _commandQueue.Any();
public static CommandData GetNextCommand() => HasPendingCommands() ? _commandQueue.First() : null;
public static void ExecuteNextCommand()
{
if (!HasPendingCommands())
{
Debug.LogWarning("[CommandExecutor] No commands to execute.");
return;
}
var commandData = _commandQueue.First();
_commandQueue.RemoveAt(0);
try
{
var commandInstance = CreateCommandInstance(commandData);
if (commandInstance != null)
{
Debug.Log($"[CommandExecutor] Executing: {commandData.commandName}");
var outcome = commandInstance.Execute(_currentContext);
var message = outcome == CommandOutcome.Success ? commandData.messages?.onSuccess : commandData.messages?.onError;
new DisplayMessageCommand(new DisplayMessageParams { message = message, outcome = outcome }).Execute(_currentContext);
if (outcome == CommandOutcome.Error)
{
Debug.LogError($"[CommandExecutor] Command '{commandData.commandName}' failed. Clearing remaining command queue.");
ClearQueue();
}
}
else
{
Debug.LogError($"[CommandExecutor] Could not create instance for command: {commandData.commandName}");
}
}
catch(Exception e)
{
Debug.LogError($"[CommandExecutor] Failed to execute command '{commandData.commandName}'. Error: {e.Message}");
ClearQueue();
}
// Save the modified queue
SessionManager.SaveCommandQueue(_commandQueue);
OnQueueUpdated?.Invoke();
}
private static ICommand CreateCommandInstance(CommandData data)
{
// Use reflection to find the command class in the Commands namespace
// This makes the system extensible without needing a giant switch statement.
var commandClassName = $"{data.commandName}Command";
var type = Assembly.GetExecutingAssembly().GetTypes()
.FirstOrDefault(t => t.Namespace == "LLM.Editor.Commands" && t.Name == commandClassName);
if (type != null)
{
// Assumes commands have a constructor that takes a single string (the JSON parameters)
return (ICommand)Activator.CreateInstance(type, data.jsonData);
}
Debug.LogError($"[CommandExecutor] Command type '{commandClassName}' not found.");
return null;
}
}
}