#include "vault.hpp"
#include <cstdio>
#include <cstring>
#include <array>
#include <memory>
#include <stdexcept>
#include <sstream>
#include <fstream>

static std::string exec_cmd(const std::string& cmd) {
    std::array<char, 4096> buf;
    std::string out;
    FILE* pipe = popen(cmd.c_str(), "r");
    if (!pipe) {
        LOG(INFO, "vault: popen failed");
        return "";
    }
    while (fgets(buf.data(), buf.size(), pipe)) {
        out += buf.data();
    }
    pclose(pipe);
    return out;
}

static std::string b64_decode(const std::string& in) {
    std::string cmd = "echo '" + in + "' | openssl base64 -d 2>/dev/null";
    return exec_cmd(cmd);
}

VaultKey load_key_from_file(const std::string& path) {
    std::ifstream f(path);
    if (!f) {
        LOG(INFO, "vault: cannot open key file");
        return VaultKey();
    }
    std::string b64((std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>());
    std::string raw = b64_decode(b64);
    if (raw.size() != 32 && raw.size() != 64) {
        LOG(INFO, "vault: invalid key size");
        return VaultKey();
    }
    SecureBuffer<32> sb;
    std::memcpy(sb.data(), raw.data(), std::min(raw.size(), sb.size()));
    return VaultKey(std::move(sb));
}

VaultKey load_key_from_shield() {
    LOG(INFO, "vault: key shield fetch placeholder");
    return VaultKey();
}

std::string decrypt_vault(const std::string& encrypted_path, const VaultKey& key) {
    char key_hex[131];
    for (size_t i = 0; i < key.size() && i < 64; ++i) {
        std::snprintf(key_hex + i * 2, 3, "%02x", key.data()[i]);
    }
    key_hex[key.size() * 2] = '\0';
    std::ostringstream oss;
    oss << "openssl enc -aes-256-cbc -d -salt -pbkdf2 -iter 100000"
        << " -in " << encrypted_path
        << " -pass pass:" << key_hex << " 2>/dev/null";
    return exec_cmd(oss.str());
}

std::string decrypt_vault(const std::string& encrypted_path, const std::string& key_file) {
    std::ostringstream oss;
    oss << "openssl enc -aes-256-cbc -d -salt -pbkdf2 -iter 100000"
        << " -in " << encrypted_path
        << " -pass file:" << key_file << " 2>/dev/null";
    return exec_cmd(oss.str());
}

std::string decrypt_vault_data(const std::vector<uint8_t>& encrypted_data, const VaultKey& key) {
    std::string tmp_in = "/tmp/.vault_in_" + std::to_string(getpid());
    {
        std::ofstream tf(tmp_in, std::ios::binary);
        tf.write(reinterpret_cast<const char*>(encrypted_data.data()), encrypted_data.size());
    }
    std::string out = decrypt_vault(tmp_in, key);
    std::remove(tmp_in.c_str());
    return out;
}
