#include "extended_facets.h"

#include <kernel/groupattrs/docsattrs.h>
#include <library/cpp/json/json_writer.h>

namespace {
    const TString HITS_ATTR = "RTY_HITS";
}

void TExtendedFacetBuilder::Process(ui32 docId, const NGroupingAttrs::TDocsAttrs& da, const TAllDocPositions* doc) {
    TMap<TString,TVector<TCateg>> attrs;
    for (const TString& attrName: AttrsUsed) {
        attrs[attrName] = TVector<TCateg>();
        TCategSeries categs;
        if (!da.DocCategs(docId, attrName.data(), categs))
            continue;
        TMap<TCateg,TString>& cache = Categ2ValueCache[attrName];
        for (const TCateg* categ = categs.Begin(); categ != categs.End(); ++categ) {
            Y_ASSERT(categ);
            if (cache.find(*categ) == cache.end()) {
                const char* categName = da.Metainfos().CategName(*categ, attrName.data());
                cache[*categ] = categName != NGroupingAttrs::NONAME ? TString(categName) : ToString(*categ);
            }
            attrs[attrName].push_back(*categ);
        }
    }

    if (HitsAreUsed && doc) {
        attrs[HITS_ATTR] = TVector<TCateg>({doc->TextHits.Count});
        Categ2ValueCache[HITS_ATTR][doc->TextHits.Count] = ToString(doc->TextHits.Count);
    }

    for (auto& aggr: Aggregators) {
        aggr.AddValue(attrs);
    }
}

void TExtendedFacetBuilder::FillProperties(TSearcherProps* props) const {
    for (auto& aggr : Aggregators) {
        TString propVal = aggr.GetResult(Categ2ValueCache);
        NJson::TJsonValue propValJs;
        propValJs["result"] = propVal;
        propValJs["aggr_type"] = aggr.GetAggrTypeName();
        props->Set(
            TString("rty_efacet_" + aggr.GetAggrTypeName() + "_" + aggr.GetAttrName() + "__" + aggr.GetChildAttrName()),
            NJson::WriteJson(propValJs, false));
    }
}

void TExtendedFacetBuilder::ParseExpression(const TString& expr) {
    TVector<TString> data, aggr;
    StringSplitter(expr).Split(':').SkipEmpty().Limit(2).Collect(&data);
    if (data.size() != 2) {
        return;
    }
    AttrsUsed.insert(data[0]);
    ERtyAggregationType aggrType;
    StringSplitter(data[1]).Split('@').SkipEmpty().Limit(2).Collect(&aggr);
    if (aggr.size() != 2 || !TryFromString<ERtyAggregationType>(aggr[1], aggrType)) {
        return;
    }
    if (HITS_ATTR == aggr[0]) {
        HitsAreUsed = true;
    } else {
        AttrsUsed.insert(aggr[0]);
    }

    Aggregators.push_back(THighAggregator(data[0], aggr[0], aggrType));
}
