#include "gafacet_builder.h"

#include <kernel/groupattrs/docsattrs.h>

#include <util/string/builder.h>

TGroupAttrFacetBuilder::TGroupAttrFacetBuilder(const TVector<TString>& attributesWithParams, const ui32 docCount)
        : DocCountInSegment(docCount)
{
    Attributes.reserve(attributesWithParams.size());
    for (auto&& attrWithParam: attributesWithParams) {
        auto splitted = SplitString(attrWithParam, ":", 0, KEEP_EMPTY_TOKENS);
        TString& name = splitted[0];

        if (splitted.size() > 1) {
            TryFromString(splitted[1], Facets[name].Top);
        }

        Attributes.emplace_back(std::move(name));
    }
    SortUnique(Attributes);
}

void TGroupAttrFacetBuilder::ProcessDoc(ui32 docId, const NGroupingAttrs::TDocsAttrs& da) {
    MaxDocId = Max<ui32>(MaxDocId, docId);
    for (const TString& attrName: Attributes) {
        TCategSeries categs;
        if (!da.DocCategs(docId, attrName.data(), categs)) {
            continue;
        }

        for (const TCateg* categ = categs.Begin(); categ != categs.End(); ++categ) {
            Y_ASSERT(categ);
            TFacetField& facetField = Facets[attrName][*categ];
            if (!facetField.Count) {
                const char* categName = da.Metainfos().CategName(*categ, attrName.data());
                facetField.StringValue = categName != NGroupingAttrs::NONAME ? TString(categName) : ToString(*categ);
            }
            ++facetField.Count;
        }
    }
}

void TGroupAttrFacetBuilder::FillProperties(TSearcherProps* props) const {
    for (const auto& facet: Facets) {
        TStringBuilder facetString;
        if (facet.second.Top == DefaultTop) {
            for (const auto& i: facet.second) {
                facetString << i.second.StringValue << ':' << i.second.Count << ';';
            }
        } else {
            typedef std::pair<ui32, TStringBuf> TFacetPair;
            TVector<TFacetPair> tmpFacets;
            tmpFacets.reserve(facet.second.size());
            for (const auto& i: facet.second) {
                tmpFacets.emplace_back(i.second.Count, i.second.StringValue);
            }
            Sort(tmpFacets, [](const TFacetPair& first, const TFacetPair& second) -> bool {
                return first.first > second.first;
            });

            for (ui32 f = 0; f < Min(static_cast<ui32>(tmpFacets.size()), facet.second.Top); ++f) {
                facetString << tmpFacets[f].second << ':' << tmpFacets[f].first << ';';
            }
        }

        if (!facetString.empty()) {
            facetString.erase(facetString.end());
        }
        props->Set(TString::Join("facet_", facet.first), facetString);
    }
    props->Set(TString("rty_max_gafacet_max_docid"), MaxDocId);
    props->Set(TString("rty_max_gafacet_segment_docs"), DocCountInSegment);
}
