#pragma once

#include <saas/searchproxy/report/abstract/reply_data.h>
#include <search/idl/meta.pb.h>
#include <kernel/search_daemon_iface/cntintrf.h>

#include <library/cpp/logger/global/global.h>

#include <util/generic/array_ref.h>


namespace NProxyMeta {

    class TSearchReplyData : public ISearchReplyData {
    public:
        TSearchReplyData(const NMetaProtocol::TReport& report)
            : Report(report)
        {
        }

        virtual void FillArchiveInfo(int nGroup, int nDoc, const TGroupingIndex& /*gi*/, bool /*passages*/, TMainDocArchiveInfo& info) const override {
            CHECK_WITH_LOG(Report.GroupingSize() > 0);

            const NMetaProtocol::TGrouping& grouping = Report.GetGrouping(0);
            CHECK_WITH_LOG((ui32)nGroup < grouping.GroupSize());

            const NMetaProtocol::TGroup& group = grouping.GetGroup(nGroup);
            CHECK_WITH_LOG((ui32)nDoc < group.DocumentSize());

            const NMetaProtocol::TDocument& document = group.GetDocument(nDoc);
            info.UrlProperty = document.GetUrl();
            info.Url = document.GetUrl();
            info.DocId.FromString(document.GetDocId());
            info.Relevance = document.GetRelevance();

            const NMetaProtocol::TArchiveInfo& archiveInfo = document.GetArchiveInfo();

            info.HeadLine = archiveInfo.GetHeadline();
            info.Title = archiveInfo.GetTitle();
        }

        virtual void FillReportStat(TFullReportInfo& info) const override {
            if (Report.TotalDocCountSize() != 3) {
                DEBUG_LOG << "Incorrect Report format for TotalDocCount " << Report.TotalDocCountSize() << Endl;
            } else {
                info.Stat[0] = Report.GetTotalDocCount(0);
                info.Stat[1] = Report.GetTotalDocCount(1);
                info.Stat[2] = Report.GetTotalDocCount(2);
            }
        }

        virtual void FillGroupingInfo(const TGroupingIndex& /*gi*/, TGroupingInfo& info) const override {
            if (Report.GroupingSize() == 0)
                return;

            const NMetaProtocol::TGrouping& grouping = Report.GetGrouping(0);

            if (grouping.NumDocsSize() != 3) {
                DEBUG_LOG << "Incorrect Report format for NumDocs " << grouping.NumDocsSize() << Endl;
            } else {
                info.Stat[0] = grouping.GetNumDocs(0);
                info.Stat[1] = grouping.GetNumDocs(1);
                info.Stat[2] = grouping.GetNumDocs(2);
            }

            info.GroupsCount = grouping.GroupSize();
        }

        virtual void FillGroupInfo(int nGroup, const TGroupingIndex& /*gi*/, TGroupInfo& info) const override {
            CHECK_WITH_LOG(Report.GroupingSize() > 0);

            const NMetaProtocol::TGrouping& grouping = Report.GetGrouping(0);
            CHECK_WITH_LOG((ui32)nGroup < grouping.GroupSize());

            const NMetaProtocol::TGroup& group = grouping.GetGroup(nGroup);

            if (group.RelevStatSize() == 3) {
                info.Stat[0] = group.GetRelevStat(0);
                info.Stat[1] = group.GetRelevStat(1);
                info.Stat[2] = group.GetRelevStat(2);
            } else {
                DEBUG_LOG << "Incorrect Report format for GetRelevStat " << group.RelevStatSize() << Endl;
            }

            info.Relevance = group.GetRelevance();
            info.DocsCount =  group.DocumentSize();
            info.CategString = group.GetCategoryName();
        }

        virtual void FillDocCategInfo(int /*group*/, int /*doc*/, const TGroupingIndex& /*gi*/, const TString& /*attrName*/, int /*docInCateg*/, TDocCategInfo& /*info*/) const override {
        }

        virtual void FillIndexAttrsInfo(int /*group*/, int /*doc*/, const TGroupingIndex& /*gi*/, TAttrsInfo& /*info*/) const override {
        }

        virtual void FillPagingInfo(const TGroupingIndex&, const int, const long int, TPagingInfo& paging) const override {
            if (Report.GroupingSize() == 0) {
                return;
            }

            paging.FirstGroup = 0;
            const NMetaProtocol::TGrouping& grouping = Report.GetGrouping(0);
            paging.LastGroup = grouping.GroupSize();
        }

        virtual void SerializeAttributes(int nGroup, int nDoc, const TGroupingIndex& /*gi*/, TArrayRef<const char * const> /*attrNames*/, IAttributeWriter& writer, bool /*withSafe*/) const override {
            CHECK_WITH_LOG(Report.GroupingSize() > 0);

            const NMetaProtocol::TGrouping& grouping = Report.GetGrouping(0);
            CHECK_WITH_LOG((ui32)nGroup <grouping.GroupSize());

            const NMetaProtocol::TGroup& group = grouping.GetGroup(nGroup);
            CHECK_WITH_LOG((ui32)nDoc < group.DocumentSize());

            const NMetaProtocol::TDocument& document = group.GetDocument(nDoc);
            const NMetaProtocol::TArchiveInfo& archiveInfo = document.GetArchiveInfo();

            for (ui32 i = 0; i < archiveInfo.GtaRelatedAttributeSize(); ++i) {
                NMetaProtocol::TPairBytesBytes attr = archiveInfo.GetGtaRelatedAttribute(i);
                writer(attr.GetKey().data(), attr.GetValue().data());
            }
        }

        virtual TSearcherPropsRef GetSearchProperties() const override {
            return nullptr;
        }

        virtual void FillErrors(TVector<TString>& errors) const override {
            errors.push_back(Report.GetErrorInfo().GetText());
        }

    private:
        const NMetaProtocol::TReport& Report;
    };
}
