#include <util/draft/date.h>
#include <util/digest/fnv.h>
#include <util/generic/size_literals.h>
#include <util/string/printf.h>

#include <kernel/search_query/search_query.h>
#include <library/cpp/json/json_writer.h>
#include <mapreduce/yt/interface/protos/yamr.pb.h>

#include <quality/ab_testing/stat_collector_lib/common.h>
#include <quality/ab_testing/stat_collector_lib/common/logs/baobab.h>
#include <quality/user_metrics/surplus_metrics/lib/surplus.h>
#include <quality/user_sessions/request_aggregate_lib/all.h>

#include <robot/jupiter/protos/export.pb.h>
#include <robot/library/yt/static/command.h>
#include <robot/library/yt/static/tags.h>

#include <wmconsole/version3/library/jupiter/jupiter.h>
#include <wmconsole/version3/protos/queries2.pb.h>
#include <wmconsole/version3/wmcutil/log.h>

using namespace NJupiter;

#define OPERATION_WEIGHT 20.0f

namespace NWebmaster {

const char *FORMAT = "%Y-%m-%d";

TBlockStatInfo GetBlockstatInfo(NYT::IClientBasePtr client) {
    const TString DICT_ROOT = "//statbox/statbox-dict-by-name/blockstat.dict";
    const TDate startDate = TDate(Now().TimeT());
    const TDate endDate = startDate - 180;
    for (TDate curDate = startDate; curDate > endDate; --curDate) {
        const TString dictPath = NYTUtils::JoinPath(DICT_ROOT, curDate.ToStroka(FORMAT));
        if (client->Exists(dictPath)) {
            return TBlockStatInfo(*client->CreateFileReader(dictPath).Get());
        }
    }
    ythrow yexception() << "blockstat.dict " << "not found";
}

} //namespace NWebmaster

int main(int argc, const char **argv) {
    NYT::Initialize(argc, argv);
    using namespace NWebmaster;

    NYT::IClientPtr client = NYT::CreateClient("arnold.yt.yandex.net");
    TBlockStatInfo bsi = GetBlockstatInfo(client);
    TString uid, dateStr, reqId;
    NLastGetopt::TOpts opts;

    opts
        .AddCharOption('u', "yuid")
        .StoreResult(&uid)
        .Required()
    ;

    opts
        .AddCharOption('d', "Date YYYY-MM-DD")
        .StoreResult(&dateStr)
        .Required()
    ;
    opts
        .AddCharOption('r', "Request ID")
        .StoreResult(&reqId)
        .DefaultValue("")
    ;
    NLastGetopt::TOptsParseResult res(&opts, argc, argv);

    const TVector sources = {
        "//user_sessions/pub/search/daily",
        "//user_sessions/pub/direct_urls/daily",
        "//user_sessions/pub/bs_chevent_log/daily",
    };

    NRA::TLogsParserParams lpParams(bsi);
    auto lpFilter = lpParams.GetFilterMainServices();
    lpFilter.set(MSS_WEB);
    lpFilter.set(MSS_PORTAL);
    lpFilter.set(MSS_TURBO);
    lpParams.SetFilterMainServices(lpFilter);
    lpParams.SetErrorHandler(new NRA::TCerrLogsParserErrorHandler(true, false));

    //params.SetErrorHandler(new NRA::TCerrLogsParserErrorHandler(true, false));
    //params.SetBlockStatInfo(&bsi);
    //params.SetEntitiesManager(NRA::GetFullEntitiesConfiguration());
    NRA::TLogsParser lp(lpParams);

    for (const auto &source : sources) {
        const TString inputTable = NYTUtils::JoinPath(source, dateStr, "robots");
        NYT::TRichYPath path(inputTable);
        path.AddRange(NYT::TReadRange().Exact(NYT::TReadLimit().Key(NYT::TKey(uid))));
        path.SortedBy(NYT::TSortColumns("key", "subkey"));

        auto reader = client->CreateTableReader<NYT::TYamr>(path);
        for (; reader->IsValid(); reader->Next()) {
            auto &row = reader->GetRow();
            lp.AddRec(row.GetKey(), row.GetSubkey(), row.GetValue());
        }
    }
    lp.Join();

    NRA::TRequestsContainer rcont(lp.GetRequestsContainer());

    int counter = 0;
    //const auto &config = NSurplus::LoadDefaultConfig();
    const NRA::TRequests &requests = rcont.GetRequests();
    for (const auto &request : requests) {
        if (!reqId.empty() && request->GetReqID() != reqId) {
            continue;
        }

        TString name        = Sprintf("dump_%s-%04d.json", uid.c_str(), counter);
        TString nameSurplus = Sprintf("dump_%s-%04d_surplus.json", uid.c_str(), counter);
        SubstGlobal(name, "/", "_");
        SubstGlobal(nameSurplus, "/", "_");
        counter++;

        {
            TAtomicSharedPtr<const NBaobab::NTamus::TMarkersContainer> tamusMarkersPtr = NStatCollector::GetBaobabInfo(request.Get(), rcont.GetBaobabWeakTies());
            const NSurplus::TSurplusWebRequest webRequest(request.Get(), MakeAtomicShared<const NBaobab::NTamus::TMarkersContainer>(*tamusMarkersPtr));
            if (webRequest.CommonProperties.IsSurplusAcceptableRequest_) {
                const NSurplus::TSurplusConfigManager configManager(NSurplus::ESurplusConfigFile::SURPLUS_DEFAULT_CONFIG, "");
                NSurplus::TSurplus surplus;
                NSurplus::CalculateSurplus(webRequest, configManager, surplus);
                TBuffered<TFileOutput> jsonStream(8192, nameSurplus);
                NJsonConverters::ToTValue(surplus).ToJsonPretty(jsonStream);
                jsonStream.Finish();
            }
        }

        {
            TBuffered<TFileOutput> jsonStream(8192, name);
            NJson::TJsonWriter jw(&jsonStream, true, true);
            request->ToJson(jw);
            jw.Flush();
            jsonStream.Finish();
        }
    }
}
