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

#include <unistd.h>
#include <cstring>
#include <iostream>
#include <sstream>
#include <filesystem>
#include "utils/assert.hpp"

namespace dropshell {

int edit_handler(const CommandContext& ctx);

static std::vector<std::string> edit_name_list={"edit"};

// Static registration
struct EditCommandRegister {
    EditCommandRegister() {
        CommandRegistry::instance().register_command({
            edit_name_list,
            edit_handler,
            shared_commands::std_autocomplete,
            false, // hidden
            false, // requires_config
            false, // requires_install
            0,     // min_args (after command)
            2,     // max_args (after command)
            "edit [SERVER] [SERVICE]",
            "Edit dropshell, server or service configuration",
            // heredoc
            R"(
            Edit dropshell, server or service configuration.
            edit                      edit the dropshell config.
            edit <server>             edit the server config.
            edit <server> <service>   edit the service config.
            )"
        });
    }
} edit_command_register;
 
// ------------------------------------------------------------------------------------------------
// edit command implementation
// ------------------------------------------------------------------------------------------------



// ------------------------------------------------------------------------------------------------
// utility function to edit a file
// ------------------------------------------------------------------------------------------------
bool edit_file(const std::string &file_path, bool has_bb64)
{
    // make sure parent directory exists.
    std::string parent_dir = get_parent(file_path);
    std::filesystem::create_directories(parent_dir);

    std::string editor_cmd;
    const char* editor_env = std::getenv("EDITOR");

    if (editor_env && std::strlen(editor_env) > 0) {
        editor_cmd = std::string(editor_env) + " " + quote(file_path);
    } else if (isatty(STDIN_FILENO)) {
        // Check if stdin is connected to a terminal if EDITOR is not set
        editor_cmd = "nano -w " + quote(file_path);
    } else {
        error << "Standard input is not a terminal and EDITOR environment variable is not set." << std::endl;
        info << "Try setting the EDITOR environment variable (e.g., export EDITOR=nano) or run in an interactive terminal." << std::endl;
        info << "You can manually edit the file at: " << file_path << std::endl;
        return false;
    }

    info << "Editing file: " << file_path << std::endl;

    if (has_bb64) {
        return execute_local_command("", editor_cmd, {}, nullptr, cMode::Interactive);
    }
    else {
        // might not have bb64 at this early stage. Direct edit.
        int ret = system(editor_cmd.c_str());
        return EXITSTATUSCHECK(ret);
    }
}

// ------------------------------------------------------------------------------------------------
// edit config
// ------------------------------------------------------------------------------------------------
int edit_config()
{
    if (!gConfig().is_config_set())
        gConfig().save_config(false); // save defaults.

    std::string config_file = localfile::dropshell_json();
    if (!edit_file(config_file, false) || !std::filesystem::exists(config_file))
        return die("Error: Failed to edit config file.");

    gConfig().load_config();
    if (!gConfig().is_config_set())
        return die("Error: Failed to load and parse edited config file!");

    gConfig().save_config(true);

    std::cout << "Successfully edited config file at " << config_file << std::endl;
    return 0;
}

// ------------------------------------------------------------------------------------------------
// edit server
// ------------------------------------------------------------------------------------------------
int edit_server(const std::string &server_name)
{
    if (localpath::server(server_name).empty()) {
        std::cerr << "Error: Server not found: " << server_name << std::endl;
        return -1;
    }

    std::string config_file = localfile::server_json(server_name);

    if (!edit_file(config_file, true)) {
        error << "Failed to edit server config" << std::endl;
        info << "You can manually edit this file at: " << config_file << std::endl;
        return 1;
    }

    info << "If you have changed DROPSHELL_DIR, you should manually move the files to the new location NOW." << std::endl;
    info << "You can ssh in to the remote server with:  dropshell ssh "<<server_name<< std::endl;
    info << "Once moved, reinstall all services with:   dropshell install " << server_name << std::endl;
    return 0;
}

// ------------------------------------------------------------------------------------------------
// edit service config
// ------------------------------------------------------------------------------------------------
int edit_service_config(const std::string &server, const std::string &service)
{
    std::string config_file = localfile::service_env(server, service);
    if (!std::filesystem::exists(config_file))
    {
        error << "Service config file not found: " << config_file << std::endl;
        return 1;
    }

    if (edit_file(config_file, true) && std::filesystem::exists(config_file))
        info << "To apply your changes, run:\n   dropshell install " + server + " " + service << std::endl;
    return 0;
}

// ------------------------------------------------------------------------------------------------
// edit command handler
// ------------------------------------------------------------------------------------------------
int edit_handler(const CommandContext& ctx) {
    // edit dropshell config
    if (ctx.args.size() < 1) 
        return edit_config();

    // edit server config
    if (ctx.args.size() < 2) {
        edit_server(safearg(ctx.args,0));
        return 0;
    }

    // edit service config
    if (ctx.args.size() < 3) {
        edit_service_config(safearg(ctx.args,0), safearg(ctx.args,1));
        return 0;
    }

    info << "Edit handler called with " << ctx.args.size() << " args\n";
    return -1;
}




} // namespace dropshell