#include "job_cache_sha256.h"

#include <cstdio>
#include <filesystem>
#include <fstream>
#include <sstream>

namespace fs = std::filesystem;

namespace fn::cache_sha256 {

namespace {

std::string subdir_for(const std::string& key) {
    return key.size() >= 2 ? key.substr(0, 2) : key;
}

} // namespace

std::string path_for(const std::string& root,
                     const std::string& key,
                     const std::string& suffix) {
    fs::path p = fs::path(root) / subdir_for(key) / (key + suffix);
    return p.string();
}

bool ensure_dir(const std::string& root, const std::string& key) {
    std::error_code ec;
    fs::path dir = fs::path(root) / subdir_for(key);
    fs::create_directories(dir, ec);
    return !ec;
}

bool read(const std::string& root,
          const std::string& key,
          const std::string& suffix,
          std::string* out) {
    if (!out) return false;
    std::ifstream f(path_for(root, key, suffix), std::ios::binary);
    if (!f.is_open()) return false;
    std::ostringstream ss;
    ss << f.rdbuf();
    *out = ss.str();
    return f.good() || f.eof();
}

bool write(const std::string& root,
           const std::string& key,
           const std::string& suffix,
           const std::string& bytes) {
    if (!ensure_dir(root, key)) return false;
    std::ofstream f(path_for(root, key, suffix),
                    std::ios::binary | std::ios::trunc);
    if (!f.is_open()) return false;
    f.write(bytes.data(), (std::streamsize)bytes.size());
    return f.good();
}

bool exists(const std::string& root,
            const std::string& key,
            const std::string& suffix) {
    std::error_code ec;
    return fs::exists(path_for(root, key, suffix), ec) && !ec;
}

} // namespace fn::cache_sha256
