// SPDX-License-Identifier: MPL-2.0
#include "vybuild.hpp"
#include <unordered_set>
#include <mutex>
#define XXH_INLINE_ALL
using namespace std;
fs::path cache_directory;
fs::path smart_cache_directory;
bool smart_cache_enabled=false;
unordered_set<string> used_elements;
mutex cache_mutex;
void vybuild::cache::init_cache(bool enable_smart_cache) {
  fs::path cache_dir=fs::current_path()/".vybuild_cache";
  fs::path smart_cache_dir=fs::current_path()/".vybuild_scache";
  cache_directory=cache_dir;
  smart_cache_directory=smart_cache_dir;
  if (fs::exists(cache_dir) && !fs::is_directory(cache_dir)) {
    fs::remove(cache_dir);
  }
  fs::create_directories(cache_dir);
  if (fs::exists(smart_cache_dir)) {
    fs::remove_all(smart_cache_dir);
  }
  if (enable_smart_cache) {
    if (fs::exists(smart_cache_dir)) {
      fs::remove_all(smart_cache_dir);
    }
    fs::create_directories(smart_cache_dir);
  }
  smart_cache_enabled=enable_smart_cache;
  return;
}
void vybuild::cache::store_file(string key,fs::path file_path) {
  if (!std::all_of(key.begin(),key.end(),::isxdigit)) throw runtime_error("Invalid cache key.");
  if (!fs::exists(file_path)) throw std::runtime_error("Element named "+file_path.string()+" can't be put in cache: it doesn't exist.");
  if (!fs::is_regular_file(file_path)) throw std::runtime_error("Element named "+file_path.string()+" can't be put in cache: it is not a regular file.");
  auto final=cache_directory/key;
  auto tmp=final;
  tmp+=".tmp";
  fs::copy_file(file_path,tmp,fs::copy_options::overwrite_existing);
  fs::rename(tmp,final);
  {
    lock_guard<mutex> lock(cache_mutex);
    if (smart_cache_enabled) used_elements.emplace(key);
  }
  return;
}
bool vybuild::cache::cache_contains(string key) {
  if (fs::exists(cache_directory/key)) return true;
  return false;
}
void vybuild::cache::extract_file(string key,fs::path output_path) {
  if (!cache_contains(key)) throw runtime_error("Cache doesn't contain that key: "+key);
  auto source=cache_directory/key;
  auto tmp=output_path;
  tmp+=".tmp";
  fs::copy_file(source,tmp,fs::copy_options::overwrite_existing);
  fs::rename(tmp,output_path);
  {
    lock_guard<mutex> lock(cache_mutex);
    if (smart_cache_enabled) used_elements.emplace(key);
  }
  return;
}
string vybuild::cache::xxhash_to_string(XXH128_hash_t hash) {
  ostringstream oss;
  oss<<hex<<setfill('0')<<setw(16)<<hash.low64<<setw(16)<<hash.high64;
  return oss.str();
}
void vybuild::cache::clean_cache() {
  if (!smart_cache_enabled) return;
  for (auto &p:used_elements) {
    if (fs::exists(cache_directory/p)) fs::rename(cache_directory/p,smart_cache_directory/p);
  }
  fs::remove_all(cache_directory);
  fs::rename(smart_cache_directory,cache_directory);
  return;
}
