#pragma once

#include <string>
#include <vector>
#include <functional>
#include <unordered_map>
#include <optional>
#include <variant>

#include "lumacs/i_command_target.hpp" // New include for ICommandTarget
// #include "lumacs/editor_core.hpp" // Required for EditorCore definition - moved to .cpp

namespace lumacs {

class EditorCore; // Forward declaration
class MinibufferManager; // Forward declare MinibufferManager for interactive args

/// @brief Defines the status of a command execution.
enum class CommandStatus {
    Success,
    Failure,
    PendingInput // Indicates the command is waiting for user input
};

/// @brief Represents the result of a command execution.
struct CommandResult {
    CommandStatus status;
    std::string message;
    // Potentially add more fields, like return value, error code, etc.
};

/// @brief Context object passed to command functions for argument access and interaction.
class CommandContext {
public:
    CommandContext(ICommandTarget& target, MinibufferManager& minibuffer_manager, const std::vector<std::string>& args)
        : target_(target), minibuffer_manager_(minibuffer_manager), args_(args) {} // Corrected initializer list order

    /// @brief Get argument at index as string.
    std::optional<std::string> get_string_arg(size_t index) const;

    /// @brief Get argument at index as integer.
    std::optional<int> get_int_arg(size_t index) const;

    // TODO: Add more typed accessors as needed (bool, double, etc.)

    /// @brief Prompts the user for a string argument.
    std::optional<std::string> read_string(const std::string& prompt);

    /// @brief Prompts the user for a file path.
    std::optional<std::string> read_file_path(const std::string& prompt);

    // Access to core components for command logic
    ICommandTarget& target() { return target_; }

    /// @brief Get all gathered arguments.
    [[nodiscard]] const std::vector<std::string>& get_args() const { return args_; }

private:
    ICommandTarget& target_; // Declared first
    [[maybe_unused]] MinibufferManager& minibuffer_manager_; // Declared second, will be used when interactive methods are implemented
    std::vector<std::string> args_; // Declared third
};

/// @brief Type for command functions.
/// Commands take a CommandContext reference and return a CommandResult.
using CommandFunction = std::function<CommandResult(CommandContext&)>;

/// @brief Represents a single command.
struct Command {
    std::string name;
    CommandFunction function;
    std::string doc_string; // Documentation for the command
    bool interactive;       // Whether the command can be called interactively (e.g., via M-x)
    std::string interactive_spec; // Emacs-like interactive spec for argument gathering
    std::vector<std::string> aliases; // New: list of alias names for this command

    Command(std::string name, CommandFunction func, std::string doc = "", bool interactive = false, std::string i_spec = "", std::vector<std::string> aliases = {})
        : name(std::move(name)), function(std::move(func)), doc_string(std::move(doc)), interactive(interactive), interactive_spec(std::move(i_spec)), aliases(std::move(aliases)) {}
};

/// @brief Manages the registration and execution of editor commands.
class CommandSystem {
public:
    explicit CommandSystem(EditorCore& core, MinibufferManager& minibuffer_manager);

    /// @brief Registers a command with the system.
    void register_command(const std::string& name, CommandFunction function,
                          const std::string& doc_string = "", bool interactive = false, 
                          std::string interactive_spec = "", std::vector<std::string> aliases = {});

    /// @brief Clears all registered commands and aliases.
    void clear_commands();

    /// @brief Executes a command by name with given arguments.
    /// @param name The name of the command to execute.
    /// @param args Arguments for the command.
    /// @return CommandResult indicating success/failure and a message.
    CommandResult execute(const std::string& name, const std::vector<std::string>& args);

    /// @brief Get a list of all registered command names.
    std::vector<std::string> get_command_names() const;

    /// @brief Get documentation for a specific command.
    std::optional<std::string> get_command_doc_string(const std::string& name) const;

    /// @brief Get the interactive spec for a specific command.
    std::optional<std::string> get_command_interactive_spec(const std::string& name) const;


    /// @brief Executes a command interactively, prompting the user for arguments if needed.
    /// @param name The name of the command to execute.
    /// @return CommandResult indicating success/failure and a message, or a pending state.
    CommandResult execute_interactive(const std::string& name);

    /// @brief Access the EditorCore instance.
    EditorCore& core() const { return core_; }

private:
    EditorCore& core_; // Reference to EditorCore
    MinibufferManager& minibuffer_manager_; // Reference to MinibufferManager
    std::unordered_map<std::string, Command> commands_;
    std::unordered_map<std::string, std::string> alias_map_; // Maps alias to canonical command name

    // State for interactive command execution
    std::optional<Command> current_interactive_command_;
    size_t current_interactive_spec_index_ = 0;
    std::vector<std::string> gathered_interactive_args_;

    CommandResult process_next_interactive_argument();
};

} // namespace lumacs