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

#include <library/cpp/getopt/last_getopt.h>
#include <mapreduce/yt/interface/client.h>
#include <wmconsole/version3/protos/queries2.pb.h>

#include "partition.h"
#include "run_config.h"
#include "task_query_groups.h"
#include "util.h"

namespace NWebmaster {

void TMapQueryGroups::WriteQueryStat(size_t tableId, const TString &date, const TString &hostId,
    const TString &groupId, const TQueryStat &queryStat, int32_t regionId, const TString &deviceType, TWriter* writer) {

    TStringBuilder data;
    data << date << "\t"
         << hostId << "\t"
         << groupId << "\t"
         << ToString(regionId) << "\t"
         << ToString(queryStat.ShowsTotal) << "\t"
         << ToString(queryStat.ClicksTotal) << "\t"
         << ToString(queryStat.Shows_1) << "\t"
         << ToString(queryStat.Clicks_1) << "\t"
         << ToString(queryStat.Shows_2_3) << "\t"
         << ToString(queryStat.Clicks_2_3) << "\t"
         << ToString(queryStat.AgrPosShows_2_3) << "\t"
         << ToString(queryStat.AgrPosClicks_2_3) << "\t"
         << ToString(queryStat.Shows_4_10) << "\t"
         << ToString(queryStat.Clicks_4_10) << "\t"
         << ToString(queryStat.AgrPosShows_4_10) << "\t"
         << ToString(queryStat.AgrPosClicks_4_10) << "\t"
         << ToString(queryStat.Shows_11_50) << "\t"
         << ToString(queryStat.Clicks_11_50) << "\t"
         << ToString(queryStat.AgrPosShows_11_50) << "\t"
         << ToString(queryStat.AgrPosClicks_11_50) << "\t"
         << ToString(queryStat.SerpsTotal) << "\t"
         << deviceType << "\n";

    const TString partitionKey = date.substr(0, 7); // (aka month)
    NYT::TNode row;
    row["data"] = data;
    row["TableId"] = tableId;
    row["PartitionKey"] = partitionKey;
    row["OrderKey"] =  Sprintf("%s%08X%s", hostId.c_str(), (ui32) regionId + 0x8000000, groupId.c_str());
    row["IsPacked"] = false;
    writer->AddRow(row);
}

void TMapQueryGroups::WriteGroupValues(size_t tableId, const TString &date, const TString &hostId,
    const TString &groupId, const NWebmaster::proto::queries2::QueryMessage &message, TWriter *writer) {

    THashMap<TString, TQueryStat> statsByDevice;
    for (const proto::queries2::QueryRegionInfo &regionInfo : message.reports_by_region()) {
        const TString deviceType = PrintDeviceType(regionInfo.is_mobile(), regionInfo.is_pad());
        statsByDevice[deviceType].Add(regionInfo);
        WriteQueryStat(tableId, date, hostId, groupId, TQueryStat(regionInfo), regionInfo.region_id(), deviceType,
                         writer);
    }
    // write fake total region
    for (const auto &pair : statsByDevice) {
        WriteQueryStat(tableId, date, hostId, groupId, pair.second, -1, pair.first, writer);
    }
}

void TMapQueryGroups::Do(TReader *reader, TWriter *writer) {
    const THashSet<TString> &STOP_HOSTS = GetStopHostsList();
    const TRunConfig &config = TRunConfig::CInstance();
    proto::queries2::QueryMessage message;
    const TString &defaultDate = TRunConfig::CInstance().DateFieldValue;
    for (; reader->IsValid(); reader->Next()) {
        TString tableDate;
        if (!config.TableDates.empty()) {
            tableDate = config.TableDates[reader->GetTableIndex()];
        } else {
            tableDate = defaultDate;
        }
        const TString &hostId = GetHostId(reader->GetRow()["key"].AsString());
        const TString &groupId = reader->GetRow()["subkey"].AsString();
        if (STOP_HOSTS.contains(hostId)) {
            continue;
        }
        message.Clear();
        Y_PROTOBUF_SUPPRESS_NODISCARD message.ParseFromString(reader->GetRow()["value"].AsString());
        size_t tableId = FnvHash<size_t>(hostId) % config.TablesCount;

        WriteGroupValues(tableId, tableDate, hostId, groupId, message, writer);
    }
}

} //namespace NWebmaster
