#include <util/datetime/base.h>
#include <util/draft/date.h>
#include <util/system/env.h>

#include <library/cpp/neh/http_common.h>

#include <quality/user_sessions/request_aggregate_lib/all.h>

#include <wmconsole/version3/processors/user_sessions/library/source_tables.h>
#include <wmconsole/version3/processors/user_sessions/conf/config.h>
#include <wmconsole/version3/processors/user_sessions/protos/user_sessions.pb.h>
#include <wmconsole/version3/protos/queries2.pb.h>
#include <wmconsole/version3/wmcutil/log.h>
#include <wmconsole/version3/wmcutil/regex.h>

#include "utils.h"

namespace NWebmaster {
namespace NUserSessions {

NYT::TRichYPath DebugPath(const TString &table) {
    NYT::TRichYPath path(table);
    //path.AddRange(NYT::TReadRange().Exact(NYT::TReadLimit().Key(NYT::TKey("uu/d56438c56cfc44a7846152325fb4cdd1"))));
    //path.AddRange(NYT::TReadRange().Exact(NYT::TReadLimit().Key(NYT::TKey("https://lenta.ru"))));
    return path;
}

TBlockStatInfo GetBlockstatInfo(NYT::IClientBasePtr client) {
    const static char *FORMAT = "%Y-%m-%d";
    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";
}

time_t GetLatestUserSessionsTimestamp(bool fast) {
    const TString Token = GetEnv("REACTOR_TOKEN");

    NNeh::TMessage msg;
    msg.Addr = "https://reactor.yandex-team.ru/api/v1/a/i/get/last";
    const TString headers = TStringBuilder()
        << "Authorization: OAuth " << Token << "\r\n"
        << "Accept: application/json"
    ;

    const TString request1D = "{\"artifactIdentifier\": {\"namespaceIdentifier\": {\"namespacePath\": \"/user_sessions/hahn/pub/search/1d\"}}}";
    const TString request30m = "{\"artifactIdentifier\": {\"namespaceIdentifier\": {\"namespacePath\": \"/user_sessions/hahn/pub/search/30min\"}}}";
    const TString &request = fast ? request30m : request1D;
    NNeh::NHttp::MakeFullRequest(msg, headers, request, "application/json", NNeh::NHttp::ERequestType::Post);
    const auto& resp = NNeh::Request(msg)->Wait(TDuration::Seconds(5));

    if (!resp) {
        ythrow yexception() << "Could not receive response";
    } else if (resp->IsError()){
        ythrow yexception() << "Could not receive response: " << resp->GetErrorText();
    }

    TStringStream json(resp->Data);
    NJson::TJsonValue root;
    NJson::ReadJsonTree(&json, &root, true);

    const TString timestampStr = root["result"]["userTimestamp"].GetString();
    return TInstant::ParseIso8601(timestampStr).TimeT() + timezone;
}

TString GetClicksShowsTableName(time_t timestamp) {
    const TString dateStr = TDate(timestamp).ToStroka("%Y%m%d");
    return Sprintf("clicks_shows_%s_%s_for_wmc_web", dateStr.c_str(), dateStr.c_str());
}

time_t GetClicksShowsTimestamp(const TString &tableName) {
    const static TRegularExpression regex("^clicks_shows_(\\d+)_(\\d+)_for_wmc_web$");
    TVector<TString> hits;
    Y_ENSURE(regex.GetMatches(tableName, hits) == 2 && hits[0] == hits[1], "incorrect clicks_shows table name");
    return TDate(hits[0], "%Y%m%d").GetStart();
}

void PrepareDaily(NYT::IClientBasePtr client, const TString &root, bool legacy) {
    const size_t TABLE_USER_SESSIONS_STORE_PERIOD = 730;
    NYTUtils::CreatePath(client, root);
    const time_t now = Now().TimeT();
    TDeque<NYTUtils::TTableInfo> tables;
    NYTUtils::GetTableList(client, root, tables);
    for (const auto &table : tables) {
        const TString tableName = NYTUtils::GetTableName(table.Name);
        const time_t timestamp = legacy ? GetClicksShowsTimestamp(tableName) : TDate(tableName, TConfig::FORMAT).GetStart();
        const size_t ageSeconds = now - timestamp;
        const size_t ageDays = ageSeconds / 86400;
        if (ageDays > TABLE_USER_SESSIONS_STORE_PERIOD) {
            client->Remove(table.Name);
            LOG_INFO("user_sessions, removed %s", table.Name.c_str());
        }
    }
}

} //namespace NUserSessions
} //namespace NWebmaster
