#pragma once

#include <util/generic/set.h>
#include <util/string/vector.h>

#include <mapreduce/yt/interface/client.h>

#include <robot/jupiter/protos/acceptance.pb.h>
#include <robot/library/yt/static/tags.h>

#include <wmconsole/version3/processors/indexing/sitetree/protos/searchbase.pb.h>
#include <wmconsole/version3/protos/exported.pb.h>
#include <wmconsole/version3/protos/urltree.pb.h>
#include <wmconsole/version3/wmcutil/url.h>
#include <wmconsole/version3/library/jupiter/jupiter.h>

namespace NWebmaster {

using namespace NJupiter;

static TInputTag<NProto::TWebmasterHost> WebmasterHostInputTag                      (1);
static TInputTag<NProto::TUserSettings> UserSettingsInputTag                        (2);
static TInputTag<NJupiter::TAcceptanceUrlForWebMasterRecord> SearchBaseInputTag     (3);
static TInputTag<NProto::TSearchBaseDiffRecord> SearchBaseDiffInputTag              (4);
static TInputTag<NProto::TTurboPageInfo> TurboPageInputTag                          (5);

static TOutputTag<NProto::TPreparedUrl> PreparedUrlOutputTag                        (1);

struct TReduceUrls : public TTaggedReducer {

public:
    enum {
        NATURAL = 0,
        USER = 1,
    };

    TReduceUrls() = default;
    TReduceUrls(const THashSet<TString> &monsterHosts, const THashSet<TString> &webmasterHosts)
        : MonsterHosts(monsterHosts)
        , WebmasterHosts(webmasterHosts)
    {
    }

    void Save(IOutputStream& stream) const override {
        ::Save(&stream, MonsterHosts);
        ::Save(&stream, WebmasterHosts);
        TTaggedReducer::Save(stream);
    }

    void Load(IInputStream& stream) override {
        ::Load(&stream, MonsterHosts);
        ::Load(&stream, WebmasterHosts);
        TTaggedReducer::Load(stream);
    }

    void DoTagged(TTagedReader reader, TTagedWriter writer) override {
        const ui32 TABLENO_NORMAL_REDUCED_URLS   = 0;
        const ui32 TABLENO_MONSTER_REDUCED_URLS  = 1;

        const TMaybe<NProto::TWebmasterHost> mbWebmasterHost            = reader.GetRowMaybe(WebmasterHostInputTag);
        reader.SkipRows(WebmasterHostInputTag);
        const TMaybe<NProto::TUserSettings> mbSettings                  = reader.GetSingleRowMaybe(UserSettingsInputTag);
        const TMaybe<NJupiter::TAcceptanceUrlForWebMasterRecord> mbBase = reader.GetSingleRowMaybe(SearchBaseInputTag);
        const TMaybe<NProto::TSearchBaseDiffRecord> mbDiff              = reader.GetSingleRowMaybe(SearchBaseDiffInputTag);
        TMaybe<NProto::TTurboPageInfo> mbTurboPage;
        size_t turboSourceFlags = 0;

        if (reader.IsValid()) {
            for (auto row : reader.GetRows(TurboPageInputTag)) {
                turboSourceFlags |= row.GetSourceFlag();
            }
        }

        TString host, path;
        if (mbBase.Defined()) {
            host = mbBase.GetRef().GetHost();
            path = mbBase.GetRef().GetPath();
        } else if (mbDiff.Defined()) {
            host = mbDiff.GetRef().GetHost();
            path = mbDiff.GetRef().GetPath();
        }  else if (mbWebmasterHost.Defined()) {
            host = mbWebmasterHost.GetRef().GetHost();
            path = mbWebmasterHost.GetRef().GetPath();
        } else {
            return;
        }

        if (!WebmasterHosts.contains(host)) {
            return;
        }

        proto::urltree::RecordSourceInfo msg;
        msg.set_path(path);

        if (mbSettings.Defined()) {
            const TVector<TString> filters = SplitString(mbSettings.GetRef().GetValue(), "\t");
            for (size_t i = 0; i < filters.size(); i++) {
                *msg.add_user_path() = filters[i];
            }
        }

        if (mbBase.Defined()) {
            const auto &row = mbBase.GetRef();
            proto::urltree::KiwiUrlInfo *rec = msg.mutable_latest_url_info();
            rec->set_http_code(row.GetHttpCode());
            rec->set_branch(proto::urltree::BRANCH_RUS); // JUPITER-238
            rec->set_last_access(row.GetLastAccess());

            if (row.GetIsSearchable()) {
                msg.mutable_search_base_acceptance()->set_from_jupiter(true);
                msg.mutable_search_base_production()->set_from_jupiter(true);
                rec->set_jupiter_url_status_searchable(row.GetUrlStatus());
            } else {
                bool isBadMimeImage = row.GetUrlStatus() == NJupiter::EAcceptanceUrlForWebMasterSimpleStatus::AUFWSS_BAD_MIME_TYPE && IsImagePathExtension(path);
                if (isBadMimeImage) {
                    return;
                }
                rec->set_jupiter_url_status_excluded(row.GetUrlStatus());
            }
            *msg.add_url_info() = msg.latest_url_info();
        }

        if (mbDiff.Defined()) {
            proto::urltree::SearchDiffStatus convertedStatus;
            switch(mbDiff.GetRef().GetDiffStatus()) {
                case NProto::EDiffStatus::NEW:
                    convertedStatus = proto::urltree::SEARCH_DIFF_STATUS_NEW;
                    break;
                case NProto::EDiffStatus::GONE:
                    convertedStatus = proto::urltree::SEARCH_DIFF_STATUS_GONE;
                    break;
                default:
                    ythrow yexception() << "unknown EDiffStatus value";
            }

            msg.mutable_search_base_acceptance()->set_search_diff_status(convertedStatus);
            msg.mutable_search_base_production()->set_search_diff_status(convertedStatus);
        }
        msg.set_turbo_source_flags(turboSourceFlags);
        TString stream;
        Y_PROTOBUF_SUPPRESS_NODISCARD msg.SerializeToString(&stream);

        NProto::TPreparedUrl dstMsg;
        dstMsg.SetHost(host);
        dstMsg.SetPath(path);
        dstMsg.SetProto(stream);

        if (MonsterHosts.contains(host)) {
            writer.AddRowWithOffset(dstMsg, PreparedUrlOutputTag, TABLENO_MONSTER_REDUCED_URLS);
        } else {
            writer.AddRowWithOffset(dstMsg, PreparedUrlOutputTag, TABLENO_NORMAL_REDUCED_URLS);
        }
    }
public:
    THashSet<TString> MonsterHosts;
    THashSet<TString> WebmasterHosts;
};

} //namespace NWebmaster
