#include <string>
#include <vector>
#include <fstream>
#include <filesystem>
#include <cstdlib>
#include <sstream>
#include <iostream>
#include <unistd.h>

#include "ArchiveManager.hpp"

namespace fs = std::filesystem;

ArchiveManager::ArchiveManager() {}

bool ArchiveManager::pack(const std::string& folderPath, const std::string& archivePath) {
    // Use system tar to create gzipped tarball
    std::ostringstream cmd;
    cmd << "tar -czf '" << archivePath << "' -C '" << folderPath << "' .";
    int ret = std::system(cmd.str().c_str());
    return ret == 0;
}

bool ArchiveManager::unpack(const std::string& archivePath, const std::string& outDir) {
    fs::create_directories(outDir);
    std::ostringstream cmd;
    cmd << "tar -xzf '" << archivePath << "' -C '" << outDir << "'";
    int ret = std::system(cmd.str().c_str());
    return ret == 0;
}

bool ArchiveManager::readConfigJson(const std::string& archivePath, std::string& outJson) {
    // Extract config json to stdout
    std::ostringstream cmd;
    cmd << "tar -xOzf '" << archivePath << "' dropshell-tool-config.json";
    FILE* pipe = popen(cmd.str().c_str(), "r");
    if (!pipe) return false;
    char buffer[4096];
    std::ostringstream ss;
    size_t n;
    while ((n = fread(buffer, 1, sizeof(buffer), pipe)) > 0) {
        ss.write(buffer, n);
    }
    int ret = pclose(pipe);
    if (ret != 0) return false;
    outJson = ss.str();
    return true;
}

bool ArchiveManager::writeConfigJson(const std::string& archivePath, const std::string& json) {
    // 1. Extract archive to temp dir
    std::string tmpDir = "/tmp/dropshell_tool_tmp_" + std::to_string(::getpid());
    fs::create_directories(tmpDir);
    std::ostringstream extractCmd;
    extractCmd << "tar -xzf '" << archivePath << "' -C '" << tmpDir << "'";
    if (std::system(extractCmd.str().c_str()) != 0) return false;
    // 2. Write new config json
    std::ofstream ofs(tmpDir + "/dropshell-tool-config.json", std::ios::binary);
    if (!ofs) return false;
    ofs << json;
    ofs.close();
    // 3. Repack
    std::ostringstream packCmd;
    packCmd << "tar -czf '" << archivePath << "' -C '" << tmpDir << "' .";
    int ret = std::system(packCmd.str().c_str());
    // 4. Cleanup
    std::ostringstream rmCmd;
    rmCmd << "rm -rf '" << tmpDir << "'";
    std::system(rmCmd.str().c_str());
    return ret == 0;
} 