#include "config_files.h"

#include <saas/rtyserver/config/config.h>

#include <mapreduce/yt/interface/operation.h>

#include <util/folder/path.h>
#include <util/system/execpath.h>

namespace {
    template <typename TCallback>
    void Traverse(const TFsPath& path, TCallback&& callback) {
        if (path.IsFile()) {
            callback(path);
            return;
        }
        TVector<TFsPath> children;
        path.List(children);
        for (auto& c : children) {
            Traverse(c, callback);
        }
    }
}

void TYTConfigFiles::FillSpecFiles(NYT::TUserJobSpec& jobSpec) const {
    if (!DoUseFiles) {
        return;
    }
    for (const auto& it : TransmitFiles) {
        jobSpec.AddLocalFile(it.second,
            NYT::TAddLocalFileOptions().PathInJob(it.first));
    }
}

void TYTConfigFiles::Init(const TString& configPath, const TString& dictPath) {
    DoUseFiles = true;
    TFsPath configDir = TFsPath(configPath).Parent().Fix();
    TransmitFiles.clear();
    DoAttachPath("configs", configDir);
    if (!!dictPath) {
        if (!TFsPath(dictPath).Exists()) {
            ythrow yexception() << "dict path presents in config but does not exist: " << dictPath;
        }
        AttachFile("dict.dict", dictPath);
    }
}

void TYTConfigFiles::AttachPath(const TString& path) {
    const auto localPath = TStringBuf{path}.Before(':');
    const auto jobPath = TStringBuf{path}.After(':');
    if (!jobPath.empty()) {
        DoAttachPath(jobPath, localPath);
    } else {
        const TFsPath fullPath(path);
        DoAttachPath(fullPath.Basename(), fullPath);
    }
}

void TYTConfigFiles::DoAttachPath(const TFsPath& jobPath, const TFsPath& localPath) {
    Traverse(localPath, [&](const TFsPath& childPath) {
        AttachFile(jobPath / childPath.RelativePath(localPath), childPath);
    });
}

void TYTConfigFiles::AttachFile(const TFsPath& jobPath, const TFsPath& localPath) {
    auto inserted = TransmitFiles.emplace(jobPath, localPath);
    Y_ENSURE(inserted.second, "cannot transmit 2 files to the same destination " << jobPath);
}

THolder<TRTYServerConfig> TRtyConfigBundle::Parse() const {
    return ParseRtyConfig(Text, Variables);
}
