#include "command_registry.hpp"
#include "utils/utils.hpp"
#include "config.hpp"

namespace dropshell {

CommandRegistry& CommandRegistry::instance() {
    static CommandRegistry reg;
    return reg;
}

void CommandRegistry::register_command(const CommandInfo& info) {
    auto ptr = std::make_shared<CommandInfo>(info);
    for (const auto& name : info.names) {
        command_map_[name] = ptr;
    }
    all_commands_.push_back(ptr);
}

const CommandInfo* CommandRegistry::find_command(const std::string& name) const {
    auto it = command_map_.find(name);
    if (it != command_map_.end()) return it->second.get();
    return nullptr;
}

std::vector<std::string> CommandRegistry::list_commands(bool include_hidden) const {
    std::set<std::string> out;
    for (const auto& cmd : all_commands_) {
        if (!cmd->hidden || include_hidden) {
            for (const auto& name : cmd->names) out.insert(name);
        }
    }
    return std::vector<std::string>(out.begin(), out.end());
}

std::vector<std::string> CommandRegistry::list_primary_commands(bool include_hidden) const {
    std::set<std::string> out;
    for (const auto& cmd : all_commands_) {
        if (!cmd->hidden || include_hidden) {
            if (cmd->names.size() > 0)
            {
                if (cmd->requires_config && !gConfig().is_config_set())
                    continue;
                if (cmd->requires_install && !gConfig().is_agent_installed())
                    continue;
                out.insert(cmd->names[0]);
            }
        }
    }
    return std::vector<std::string>(out.begin(), out.end());
}


void CommandRegistry::autocomplete(const CommandContext& ctx) const {
    // dropshell autocomplete <command> <arg> <arg> ...
    if (ctx.args.size() < 1) {
        for (const auto& name : list_primary_commands(false)) {
            std::cout << name << std::endl;
        }
        return;
    }

    // ctx command is autocomplete, so recreate ctx with the first arg removed
    CommandContext childcontext = {
        ctx.exename,
        ctx.args[0],
        std::vector<std::string>(ctx.args.begin() + 1, ctx.args.end())
    };
    auto* info = find_command(childcontext.command);
    if (info && info->autocomplete) {
        info->autocomplete(childcontext);
    }
}

} // namespace dropshell