#include "fb_writer.h"

#include <saas/rtyserver/components/prop/prop.fbs.h>

#include <util/generic/algorithm.h>
#include <util/generic/vector.h>
#include <util/generic/strbuf.h>

namespace NRTYServer {
    namespace {
        class TStringTableBuilder {
        public:
            void Append(TStringBuf string) {
                Offsets.push_back(Data.size());
                Data.append(string);
            }

            flatbuffers::Offset<NFb::TStringTable> Write(flatbuffers::FlatBufferBuilder& builder) {
                const auto offsetsOffset = builder.CreateVector(Offsets);
                const auto dataOffset = builder.CreateString(Data);
                return NFb::CreateTStringTable(builder, offsetsOffset, dataOffset);
            }

            bool Empty() const { return Offsets.empty(); }

        private:
            TVector<uint32_t> Offsets;
            TString Data;
        };
    }

    TBlob WriteDocumentFlatbuffer(const TMessage::TDocument& document, const TPropConfig& config) {
        TVector<std::pair<TStringBuf, TStringBuf>> keyValue;

        for (const auto& prop: document.GetDocumentProperties()) {
            if (config.ShouldContainProperty(prop.GetName())) {
                keyValue.emplace_back(prop.GetName(), prop.GetValue());
            }
        }

        return WriteDocumentFlatbuffer(std::move(keyValue));
    }


    TBlob WriteDocumentFlatbuffer(TVector<std::pair<TStringBuf, TStringBuf>> keyValue) {
        SortBy(keyValue, [](const auto &x) { return x.first; });

        TStringTableBuilder keyBuilder;
        TStringTableBuilder valueBuilder;
        for (const auto& [key, value]: keyValue) {
            keyBuilder.Append(key);
            valueBuilder.Append(value);
        }

        if (keyBuilder.Empty()) {
            return {};
        }

        flatbuffers::FlatBufferBuilder builder;
        const auto keysOffset = keyBuilder.Write(builder);
        const auto valuesOffset = valueBuilder.Write(builder);
        const auto root = NFb::CreateTPropertyMap(builder, keysOffset, valuesOffset);
        builder.Finish(root);
        return TBlob::Copy(builder.GetBufferPointer(), builder.GetSize());
    }
}
