#include <util/digest/fnv.h>
#include <util/digest/city.h>
#include <util/string/builder.h>

#include <library/cpp/getopt/last_getopt.h>
#include <mapreduce/yt/interface/client.h>

#include "partition.h"
#include "run_config.h"
#include "task_newgone.h"
#include "tasks.h"
#include "util.h"

namespace NWebmaster {

namespace {
const char *FIELD_HOST = "Host";
const char *FIELD_TIMESTAMP = "Timestamp";
const char *FIELD_PATH = "Path";
const char *FIELD_LAST_ACCESS = "LastAccess";
const char *FIELD_SEARCH_STATUS = "SearchStatus";
const char *FIELD_TITLE = "Title";
const char *FIELD_URL_STATUS = "UrlStatus";

const char *FIELD_EX_REGION = "Region";
const char *FIELD_EX_ADD_TIME = "AddTime";
const char *FIELD_EX_BEAUTY_URL = "BeautyUrl";
const char *FIELD_EX_HTTP_CODE = "HttpCode";
const char *FIELD_EX_MAIN_HOST = "MainHost";
const char *FIELD_EX_MAIN_PATH = "MainPath";
const char *FIELD_EX_MAIN_REGION = "MainRegion";
const char *FIELD_EX_REDIR_TARGET = "RedirTarget";
const char *FIELD_EX_REL_CANONICAL_TARGET = "RelCanonicalTarget";
const char *FIELD_EX_IS_FAKE = "IsFake";
const char *FIELD_EX_IS_INDEXED = "IsIndexed";
const char *FIELD_EX_IS_SEARCHABLE = "IsSearchable";
const char *FIELD_EX_IS_TURBO_PAGE = "IsTurboPage";
const char *FIELD_EX_IS_FROM_SITEMAP = "IsFromSitemap";
const char *FIELD_EX_TURBO_SOURCE_FLAGS = "TurboSourceFlags";
const char *FIELD_EX_VALID_FROM_METRIKA_LAST_ACCESS = "ValidFromMetrikaLastAccess";
const char *FIELD_EX_VALID_FROM_INDEXNOW_LAST_ACCESS = "ValidFromIndexNowLastAccess";
}

const time_t SKIP_EVENTS_BEFORE_BASE = 1480489200;

void TMapEvents::Do(TReader *reader, TWriter *writer) {
    const TRunConfig &config = TRunConfig::CInstance();
    TStringBuilder data;
    for (; reader->IsValid(); reader->Next()) {
        const NYT::TNode &row = reader->GetRow();
        const TString &title = row[FIELD_TITLE].AsString();
        const TString &hostId = GetHostId(row[FIELD_HOST].AsString());
        const TString &path = row[FIELD_PATH].AsString();
        time_t baseDate = GetTimestamp(row, FIELD_TIMESTAMP);
        if (baseDate <= SKIP_EVENTS_BEFORE_BASE) {
            continue;
        }
        const TString &eventStr = row[FIELD_SEARCH_STATUS].AsString();
        int event = eventStr == "+" ? 1 : 0;

        data << baseDate << "\t"
             << hostId << "\t"
             << encode(path) << "\t"
             << PrintTimestampField(row, FIELD_LAST_ACCESS) << "\t"
             << event << "\t"
             << encode(title) << "\t"
             << PrintNumOrDefault(row, FIELD_URL_STATUS, -1) << "\t"
             << PrintNullableString(row, FIELD_EX_REGION) << "\t"
             << PrintTimestampField(row, FIELD_EX_ADD_TIME) << "\t"
             << PrintNullableString(row, FIELD_EX_BEAUTY_URL) << "\t"
             << PrintNumOrDefault(row, FIELD_EX_HTTP_CODE, 0) << "\t"
             << PrintNullableString(row, FIELD_EX_MAIN_HOST) << "\t"
             << PrintNullableString(row, FIELD_EX_MAIN_PATH) << "\t"
             << PrintNullableString(row, FIELD_EX_MAIN_REGION) << "\t"
             << PrintNullableString(row, FIELD_EX_REDIR_TARGET) << "\t"
             << PrintNullableString(row, FIELD_EX_REL_CANONICAL_TARGET) << "\t"
             << PrintBool(row, FIELD_EX_IS_FAKE) << "\t"
             << PrintBool(row, FIELD_EX_IS_INDEXED) << "\t"
             << PrintBool(row, FIELD_EX_IS_TURBO_PAGE) << "\t"
             << PrintBool(row, FIELD_EX_IS_FROM_SITEMAP) << "\t"
             << PrintBool(row, FIELD_EX_IS_SEARCHABLE) << "\t"
             << PrintNumOrDefault(row, FIELD_EX_TURBO_SOURCE_FLAGS, 0) << "\t"
             << PrintTimestampField(row, FIELD_EX_VALID_FROM_METRIKA_LAST_ACCESS) << "\t"
             << PrintTimestampField(row, FIELD_EX_VALID_FROM_INDEXNOW_LAST_ACCESS) << "\n";

        NYT::TNode resultRow;
        resultRow["data"] = data;
        resultRow["TableId"] = FnvHash<size_t>(hostId) % config.TablesCount;
        resultRow["PartitionKey"] = ToString(CityHash64(hostId) % 16);
        resultRow["OrderKey"] = Sprintf("%s%016lX%s", hostId.c_str(), baseDate, path.c_str());
        resultRow["IsPacked"] = false;
        writer->AddRow(resultRow);
        data.clear();
    }
}

} //namespace NWebmaster
