#include <util/folder/dirut.h>
#include <library/cpp/json/writer/json_value.h>
#include <library/cpp/json/json_reader.h>
#include <saas/deploy_manager/storage/abstract.h>
#include <util/stream/file.h>
#include <library/cpp/getopt/opt.h>
#include <library/cpp/logger/global/global.h>
#include <library/cpp/digest/md5/md5.h>
#include <util/generic/ptr.h>

void CopyNodes(NRTYDeploy::IVersionedStorage& storageFrom, const TString& node, NRTYDeploy::IVersionedStorage& storageTo) {
    TVector<TString> nodes;
    TFsPath path(node);
    path = path.Fix();
    if (path.GetPath() == "/cluster_tasks")
        return;
    if (path.GetPath() == "/mrlock")
        return;
    if (path.GetPath() == "/locks")
        return;
    if (path.GetPath() == "/failed_tasks")
        return;
    if (path.GetPath() == "/history")
        return;
    if (path.GetName() == "current_configs" || path.GetName() == "rtyserver_current_configs" || path.GetName() == "intsearch_current_configs" ||
        path.GetName() == "metaservice_current_configs" || path.GetName() == "searchproxy_current_configs" || path.GetName() == "indexerproxy_current_configs")
        return;
    INFO_LOG << "exporting... " << node << "..." << Endl;
    if (storageFrom.GetNodes(node, nodes, true)) {
        for (auto&& i : nodes) {
            CopyNodes(storageFrom, node + "/" + i, storageTo);
        }
    }
    TString value;
    if (storageFrom.GetValue(node, value)) {
        INFO_LOG << "exporting... " << node << " md5(value) = " << MD5::Calc(value) << Endl;
        if (!storageTo.SetValue(node, value))
            ERROR_LOG << "cannot write " << node << " to storage";
    }
}

NJson::TJsonValue GetJsonFromFile(const TString& fileName) {
    if (!TFsPath(fileName).Exists())
        ythrow yexception() << "Incorrect file path: " << fileName << Endl;
    TUnbufferedFileInput fi(fileName);
    TString value = fi.ReadAll();
    NJson::TJsonValue result;
    NJson::ReadJsonFastTree(value, &result, true);
    return result;
}

int main(int argc, char **argv) {
    try {
        TString optsString("f:t:hl:");
        Opt opt(argc, argv, optsString.data());
        int optlet;
        TString logPath = "./converter.txt";
        NRTYDeploy::IVersionedStorage::TOptions optionsFrom;
        NRTYDeploy::IVersionedStorage::TOptions optionsTo;
        while ((optlet = opt.Get()) != EOF) {
            switch (optlet) {
            case 'f':
                optionsFrom.DeserializeFromJson(GetJsonFromFile(opt.GetArg()));
                break;
            case 't':
                optionsTo.DeserializeFromJson(GetJsonFromFile(opt.GetArg()));
                break;
            case 'l':
                logPath = opt.GetArg();
                break;
            default:
                break;
            }
        }

        DoInitGlobalLog(logPath, TLOG_DEBUG, true, false);

        THolder<NRTYDeploy::IVersionedStorage> storageFrom(NRTYDeploy::IVersionedStorage::Create(optionsFrom));
        THolder<NRTYDeploy::IVersionedStorage> storageTo(NRTYDeploy::IVersionedStorage::Create(optionsTo));

        CHECK_WITH_LOG(storageFrom);
        CHECK_WITH_LOG(storageTo);

        CopyNodes(*storageFrom, "/", *storageTo);
    } catch (...) {
        Cerr << "Exception: " << CurrentExceptionMessage() << Endl;
        return -1;
    }
    return 0;
}
