#include <util/thread/pool.h>

#include <wmconsole/version3/wmcutil/log.h>
#include <wmconsole/version3/wmcutil/regex.h>
#include <wmconsole/version3/wmcutil/yt/yt_runner.h>
#include <wmconsole/version3/wmcutil/yt/yt_utils.h>

#include "config.h"
#include "task_snapshot.h"
#include "utils.h"
#include "workflow.h"

namespace NWebmaster {

bool VerifyShardsContent(NYT::IClientBasePtr client, time_t prevSnapshotTs, time_t currSnapshotTs) try {
    TDeque<TString> shardsPrev;
    TDeque<TString> shardsCurrent;
    GetTableListOnly(client, TSnapshot(prevSnapshotTs).GetPath(), shardsPrev);
    GetTableListOnly(client, TSnapshot(currSnapshotTs).GetPath(), shardsCurrent);
    std::sort(shardsCurrent.begin(), shardsCurrent.end());
    std::sort(shardsPrev.begin(), shardsPrev.end());

    if (shardsCurrent.size() != shardsPrev.size()) {
        ythrow yexception() << "switch, shards count " << shardsCurrent.size() << " and " << shardsPrev.size();
    }

    if (shardsCurrent.empty()) {
        ythrow yexception() << "switch, shards empty";
    }

    for (size_t i = 0; i < shardsCurrent.size(); i++) {
        const TString current = NYTUtils::GetTableName(shardsCurrent[i]);
        const TString prev = NYTUtils::GetTableName(shardsPrev[i]);
        Cout << prev << "\t" << current << "\t" << shardsPrev[i] << "\t" << shardsCurrent[i] << Endl;
        if (current != prev) {
            ythrow yexception() << "switch, shard sequence is different " << current << " and " << prev;
        }
    }

    return true;
} catch (yexception &e) {
    LOG_ERROR("switch, verify shards content: %s", e.what());
    return false;
}

int TaskSwitch(int, const char **) {
    NYT::IClientPtr client = NYT::CreateClient(TCommonYTConfig::CInstance().MR_SERVER_HOST_JUPITER);
    NYT::ITransactionPtr tx = client->StartTransaction();

    time_t prevSnapshotTs = 0, currSnapshotTs = 0;
    auto &wf = TWorkflow::Instance();
    switch(wf.BeginProcessSnapshots(tx, prevSnapshotTs, currSnapshotTs)) {
        case TWorkflow::IN_PROGRESS:
            LOG_INFO("BeginProcessSnapshots: preparat is in progress");
            return 0;
        case TWorkflow::DONE:
            LOG_INFO("BeginProcessSnapshots: preparat in already processed");
            return 0;
        case TWorkflow::NEW:
            LOG_INFO("BeginProcessSnapshots: processing preparat %lu -> %lu", prevSnapshotTs, currSnapshotTs);
            break;
    }

    if (!VerifyShardsContent(tx, prevSnapshotTs, currSnapshotTs)) {
        ythrow yexception() << "switch, unable to process preparat";
    }

    tx->Commit();
    return 0;
}

} //namespace NWebmaster
