#include "stats_collector.h"
#include <algorithm>

#include <iostream>
#include <string>
#include <vector>

#include <cctype>

#include "beacon.h"
#include "tcpinfo.h"

#include <library/cpp/json/json_reader.h>


TStatsCollector::TStatsCollector(std::optional<TString> geodataPath)
    : GeobaseLookup_(geodataPath)
{
}

void TStatsCollector::CollectRequest(TStringBuf body, const TServerRequestData& reqData) {
    try {
        NJson::TJsonValue content;
        NJson::ReadJsonTree(body, &content, true);

        const auto& beacons = content.GetMapSafe().at("entries").GetArraySafe();
        for (const NJson::TJsonValue& v : beacons) {
            TBeacon beacon(v);
            auto asnList = ExtractASNList(reqData.HeaderInOrEmpty("X-Forwarded-For-Y"));
            YasmStats_.CountBeacon(beacon, asnList);
            SolomonStats_.CountBeacon(beacon, asnList);
        }
    } catch(...) {
        //Cerr << CurrentExceptionMessage() << "\n";
        // TODO: count misparsed requests in self-stat
    }
}

void TStatsCollector::CollectRequestTcpInfo(TStringBuf body, const TServerRequestData&) {
    try {
        NJson::TJsonValue content;
        NJson::ReadJsonTree(body.SubStr(body.find_first_of(' ')), &content, true);
        std::optional<NGeobase::NImpl::StrList> asnList;
        TTcpInfo tcpInfo;
        double rttd = 0;
        double retran = 0;

        const auto& beacons = content.GetMapSafe().at("headers").GetArraySafe();
        for (const NJson::TJsonValue& v : beacons) {

            TStringStream tmp;
            tmp << v;
            TStringBuf tmp2 = to_lower(tmp.Str());

            if (tmp2.Contains("x-forwarded-for-y")) {
                TStringBuf val;
                TStringBuf ip;
                tmp2.RNextTok("\",\"", val);
                val.NextTok("\"]", ip);
                asnList = ExtractASNList(ip);
            } else if (tmp2.Contains("x-yandex-tcp-info")) {
                TStringBuf val;
                TStringBuf rtt;
                TStringBuf retrans;
                tmp2.RNextTok(',', val);
                val.RNextTok("rtt=", rtt);
                rtt.RNextTok("s; rttvar", val);
                rttd = FromString<double>(rtt);

                val.RNextTok("total_retrans=", retrans);
                retrans.NextTok("\"", retrans);
                retran = FromString<double> (retrans);
            }
        }

        tcpInfo.Rtt = rttd;
        tcpInfo.Retransmits = retran;

        YasmStats_.CountTcpInfo(tcpInfo, asnList);
    } catch(...) {
        Cerr << CurrentExceptionMessage() << "\n";
        // TODO: count misparsed requests in self-stat
    }
}

std::optional<NGeobase::NImpl::StrList> TStatsCollector::ExtractASNList(TStringBuf clientIp) {
    if (!GeobaseLookup_ || clientIp == nullptr)
        return std::nullopt;
    return GeobaseLookup_->GetAsTraitsByIp(std::string(clientIp)).AsList;
}
