#include "DropshellScriptManager.hpp"
#include <fstream>
#include <string>
#include <vector>
#include <filesystem>
#include <algorithm>

namespace dropshelltool {
    extern const std::filesystem::path DROPSHELL_RC_PATH;
}

DropshellScriptManager::DropshellScriptManager() {}

// Helper function to trim whitespace from both ends of a string
static std::string trim(const std::string& s) {
    auto start = s.begin();
    while (start != s.end() && std::isspace(*start)) ++start;
    auto end = s.end();
    do { --end; } while (std::distance(start, end) > 0 && std::isspace(*end));
    return std::string(start, end + 1);
}

void DropshellScriptManager::ensureExists() const {
    if (!std::filesystem::exists(dropshelltool::DROPSHELL_RC_PATH)) {
        std::filesystem::create_directories(dropshelltool::DROPSHELL_RC_PATH.parent_path());
        std::ofstream outfile(dropshelltool::DROPSHELL_RC_PATH, std::ios::trunc);
        outfile << "# This file is managed by dropshell-tool. Do not edit manually!" << std::endl;
        outfile.close();
    }
}

void DropshellScriptManager::addToolEntry(const std::string& toolName, const std::string& toolDir) {
    ensureExists();
    std::ifstream infile(dropshelltool::DROPSHELL_RC_PATH);
    std::vector<std::string> lines;
    std::string line;
    std::string exportLine = "export PATH=\"" + toolDir + ":$PATH\" # dropshell-tool:" + toolName;
    bool found = false;
    while (std::getline(infile, line)) {
        if (line.find("# dropshell-tool:" + toolName) != std::string::npos) {
            found = true;
            lines.push_back(exportLine);
        } else {
            lines.push_back(line);
        }
    }
    infile.close();
    if (!found) lines.push_back(exportLine);
    std::ofstream outfile(dropshelltool::DROPSHELL_RC_PATH, std::ios::trunc);
    for (const auto& l : lines) outfile << l << "\n";
    outfile.close();
}

void DropshellScriptManager::removeToolEntry(const std::string& toolName) {
    ensureExists();
    std::ifstream infile(dropshelltool::DROPSHELL_RC_PATH);
    std::vector<std::string> lines;
    std::string line;
    while (std::getline(infile, line)) {
        if (line.find("# dropshell-tool:" + toolName) == std::string::npos) {
            lines.push_back(line);
        }
    }
    infile.close();
    std::ofstream outfile(dropshelltool::DROPSHELL_RC_PATH, std::ios::trunc);
    for (const auto& l : lines) outfile << l << "\n";
    outfile.close();
}

void DropshellScriptManager::addAlias(const std::string& alias, const std::string& toolName) {
    ensureExists();
    std::ifstream infile(dropshelltool::DROPSHELL_RC_PATH);
    std::vector<std::string> lines;
    std::string line;
    std::string aliasLine = "alias " + alias + "='" + toolName + "' # dropshell-alias:" + alias;
    bool found = false;
    while (std::getline(infile, line)) {
        if (line.find("# dropshell-alias:" + alias) != std::string::npos) {
            found = true;
            lines.push_back(aliasLine);
        } else {
            lines.push_back(line);
        }
    }
    infile.close();
    if (!found) lines.push_back(aliasLine);
    std::ofstream outfile(dropshelltool::DROPSHELL_RC_PATH, std::ios::trunc);
    for (const auto& l : lines) outfile << l << "\n";
    outfile.close();
}

void DropshellScriptManager::addAutocomplete(const std::string& toolName) {
    ensureExists();
    std::ifstream infile(dropshelltool::DROPSHELL_RC_PATH);
    std::vector<std::string> lines;
    std::string line;
    std::string funcName = "_" + toolName + "_autocomplete";
    std::string blockStart = "# DROPSHELL-AUTOCOMPLETE-START: " + toolName;
    std::string blockEnd = "# DROPSHELL-AUTOCOMPLETE-END: " + toolName;
    std::string funcDef;
    funcDef += blockStart + "\n";
    funcDef += funcName + "() {\n";
    funcDef += "    local cur=\"${COMP_WORDS[COMP_CWORD]}\"\n";
    funcDef += "    mapfile -t completions < <(" + toolName + " autocomplete \"${COMP_WORDS[@]:1:${COMP_CWORD}-1}\")\n";
    funcDef += "    mapfile -t COMPREPLY < <(compgen -W \"${completions[*]}\" -- \"$cur\")\n";
    funcDef += "}\n";
    funcDef += blockEnd + "\n";
    std::string completeLine = "complete -F " + funcName + " " + toolName + " # dropshell-autocomplete:" + toolName;
    bool blockFound = false, completeFound = false;
    bool inBlock = false;
    while (std::getline(infile, line)) {
        if (!inBlock && trim(line) == blockStart) {
            blockFound = true;
            inBlock = true;
            continue;
        }
        if (inBlock) {
            if (trim(line) == blockEnd) {
                inBlock = false;
                lines.push_back(funcDef); // Add new function block
            }
            continue; // Skip all lines in the old block
        }
        if (line.find("# dropshell-autocomplete:" + toolName) != std::string::npos) {
            completeFound = true;
            lines.push_back(completeLine);
        } else {
            lines.push_back(line);
        }
    }
    infile.close();
    if (!blockFound) lines.push_back(funcDef);
    if (!completeFound) lines.push_back(completeLine);
    std::ofstream outfile(dropshelltool::DROPSHELL_RC_PATH, std::ios::trunc);
    for (const auto& l : lines) outfile << l << "\n";
    outfile.close();
}

bool DropshellScriptManager::hasAlias(const std::string& alias) const {
    ensureExists();
    std::ifstream infile(dropshelltool::DROPSHELL_RC_PATH);
    std::string line;
    while (std::getline(infile, line)) {
        if (line.find("# dropshell-alias:" + alias) != std::string::npos) {
            return true;
        }
    }
    return false;
}

std::vector<std::string> DropshellScriptManager::listAliases() const {
    ensureExists();
    std::ifstream infile(dropshelltool::DROPSHELL_RC_PATH);
    std::string line;
    std::vector<std::string> aliases;
    while (std::getline(infile, line)) {
        auto pos = line.find("# dropshell-alias:");
        if (pos != std::string::npos) {
            auto aliasStart = line.find("alias ");
            if (aliasStart != std::string::npos) {
                auto eq = line.find('=', aliasStart + 6);
                if (eq != std::string::npos) {
                    std::string alias = line.substr(aliasStart + 6, eq - (aliasStart + 6));
                    aliases.push_back(alias);
                }
            }
        }
    }
    return aliases;
} 