#include "utils.h"

#include <library/cpp/iterator/functools.h>

#include <util/stream/output.h>
#include <util/string/builder.h>
#include <util/string/join.h>

namespace NModCookiePolicy {
    TStatsVec GetUnistat(TStatsFixture& mock, bool skipZeros) {
        auto stat = mock.Unistat();
        TStatsVec res(Reserve(stat.size()));
        for (auto&& kv : stat) {
            res.emplace_back(kv.first, kv.second.GetInteger());
        }
        Sort(res);

        if (skipZeros) {
            EraseIf(res, [](auto&& v) { return !v.second; });
        }

        return res;
    }

    ui8 CutUi8(TStringBuf& wire) {
        if (!wire) {
            return 0;
        }
        ui8 res = wire[0];
        wire.Skip(1);
        return res;
    }

    TString CutStr(TStringBuf& wire, TString deflt) {
        if (!wire) {
            return deflt;
        }
        if (wire.size() == 1) {
            TString res(wire);
            wire.Clear();
            return res;
        }
        size_t sz = CutUi8(wire);
        sz = std::min(sz, wire.size());
        TString res(wire.SubStr(0, sz));
        wire.Skip(sz);
        return res;
    }

    TStrVec CutStrVec(TStringBuf& wire, TStrVec deflt) {
        if (!wire) {
            return deflt;
        }
        auto sz = CutUi8(wire);
        TStrVec res(Reserve(sz));
        for (auto i : xrange(sz)) {
            if (!wire) {
                break;
            }
            Y_UNUSED(i);
            res.emplace_back(CutStr(wire));
        }
        return res;
    }
}

using namespace NModCookiePolicy;

template <>
void Out<TStrVec>(IOutputStream& out, const TStrVec& s) {
    out << JoinSeq(",\n", NFuncTools::Map([](auto&& p) {
        return TStringBuilder() << p.Quote();
    }, s));
}

template <>
void Out<TStatsVec>(IOutputStream& out, const TStatsVec& s) {
    out << JoinSeq(",\n", NFuncTools::Map([](auto&& p) {
        return TStringBuilder() << p.first.Quote() << " -> " << p.second;
    }, s));
}
