#include <util/draft/date.h>
#include <util/generic/queue.h>

#include <library/cpp/getopt/last_getopt.h>
#include <mapreduce/yt/interface/constants.h>

#include <kernel/yt/attrs/attrs.h>
#include <kernel/urlnorm/normalize.h>

#include <robot/library/yt/static/command.h>
#include <robot/library/yt/static/table.h>
#include <robot/library/yt/static/tags.h>

#include <wmconsole/version3/wmcutil/log.h>

#include <wmconsole/version3/processors/siteservices/conf/config.h>
#include <wmconsole/version3/processors/siteservices/protos/services.pb.h>
#include <wmconsole/version3/processors/siteservices/protos/sources.pb.h>

#include "import_util.h"
#include "task_merge.h"

namespace NWebmaster {

using namespace NJupiter;

TInputTag<NProto::TPrepAlice> PrepAliceInputTag                 (1);
TInputTag<NProto::TPrepCompanyInfo> PrepSpravInputTag           (2);
TInputTag<NProto::TPrepMobileApp> PrepMobileInputTag            (3);
TInputTag<NProto::TPrepShop> PrepShopInputTag                   (4);
TInputTag<NProto::TPrepDirect> PrepDirectInputTag               (5);
TInputTag<NProto::TPrepMarket> PrepMarketInputTag               (6);
TInputTag<NProto::TPrepMetrika> PrepMetrikaInputTag             (7);
TInputTag<NProto::TPrepRadar> PrepRadarInputTag                 (8);
TInputTag<NProto::TPrepUslugi> PrepUslugiInputTag               (9);
TInputTag<NProto::TPrepSnippetPic> PrepSnippetInputTag          (10);
TInputTag<NProto::TPrepNews> PrepNewsInputTag                   (11);
TInputTag<NProto::TPrepVerticalShare> PrepVerticalShareInputTag (12);

TOutputTag<NProto::TServices> ServicesOutputTag                 (1);

//ReduceBy MascotOwner
struct TMergeServicesJoinReducer : public TTaggedReducer {
public:
    void DoTagged(TTagedReader reader, TTagedWriter writer) override {
        NProto::TServices dstMsg;

        if (reader.IsValid()) {
            TMaybe <NProto::TPrepAlice> prepAliceMaybe = reader.GetRowMaybe(PrepAliceInputTag);

            if (prepAliceMaybe.Defined()) {
                const auto &prepAlice = prepAliceMaybe.GetRef();
                dstMsg.SetMascotOwner(prepAlice.GetMascotOwner());
                dstMsg.SetAliceInfo(prepAlice.GetAliceInfo());
            }
        }
        reader.SkipRows(PrepAliceInputTag);

        if (reader.IsValid()) {
            TMaybe <NProto::TPrepCompanyInfo> prepSpravMaybe = reader.GetRowMaybe(PrepSpravInputTag);

            if (prepSpravMaybe.Defined()) {
                const auto &prepSprav = prepSpravMaybe.GetRef();
                dstMsg.SetMascotOwner(prepSprav.GetMascotOwner());
                dstMsg.SetCompanyInfo(prepSprav.GetCompanyInfo());
            }
        }
        reader.SkipRows(PrepSpravInputTag);

        if (reader.IsValid()) {
            TMaybe <NProto::TPrepMobileApp> prepMobileMaybe = reader.GetRowMaybe(PrepMobileInputTag);

            if (prepMobileMaybe.Defined()) {
                const auto &prepMobile = prepMobileMaybe.GetRef();
                dstMsg.SetMascotOwner(prepMobile.GetMascotOwner());
                dstMsg.SetMobileAppInfo(prepMobile.GetAppInfo());
            }
        }
        reader.SkipRows(PrepMobileInputTag);

        if (reader.IsValid()) {
            TMaybe <NProto::TPrepShop> prepShopMaybe = reader.GetRowMaybe(PrepShopInputTag);

            if (prepShopMaybe.Defined()) {
                const auto &prepShop = prepShopMaybe.GetRef();
                dstMsg.SetMascotOwner(prepShop.GetMascotOwner());
                dstMsg.SetIsShop(true);
            } else {
                dstMsg.SetIsShop(false);
            }
        }
        reader.SkipRows(PrepShopInputTag);

        if (reader.IsValid()) {
            TMaybe <NProto::TPrepDirect> prepDirectMaybe = reader.GetRowMaybe(PrepDirectInputTag);

            if (prepDirectMaybe.Defined()) {
                const auto &prepDirect = prepDirectMaybe.GetRef();
                dstMsg.SetMascotOwner(prepDirect.GetMascotOwner());
                dstMsg.SetUseDirect(true);
            } else {
                dstMsg.SetUseDirect(false);
            }
        }
        reader.SkipRows(PrepDirectInputTag);

        if (reader.IsValid()) {
            TMaybe <NProto::TPrepMarket> prepMarketMaybe = reader.GetRowMaybe(PrepMarketInputTag);

            if (prepMarketMaybe.Defined()) {
                const auto &prepMarket = prepMarketMaybe.GetRef();
                dstMsg.SetMascotOwner(prepMarket.GetMascotOwner());
                dstMsg.SetMarketRating(prepMarket.GetRating());
                dstMsg.SetMarketId(prepMarket.GetShopId());
            }
        }
        reader.SkipRows(PrepMarketInputTag);

        if (reader.IsValid()) {
            TMaybe <NProto::TPrepMetrika> prepMetrikaMaybe = reader.GetRowMaybe(PrepMetrikaInputTag);

            if (prepMetrikaMaybe.Defined()) {
                const auto &prepMetrika = prepMetrikaMaybe.GetRef();
                dstMsg.SetMascotOwner(prepMetrika.GetMascotOwner());
                dstMsg.SetUseMetrika(true);
            } else {
                dstMsg.SetUseMetrika(false);
            }
        }
        reader.SkipRows(PrepMetrikaInputTag);

        if (reader.IsValid()) {
            TMaybe <NProto::TPrepRadar> prepRadarMaybe = reader.GetRowMaybe(PrepRadarInputTag);

            if (prepRadarMaybe.Defined()) {
                const auto &prepRadar = prepRadarMaybe.GetRef();
                dstMsg.SetMascotOwner(prepRadar.GetMascotOwner());
                dstMsg.SetRadarType(prepRadar.GetType());
            }
        }
        reader.SkipRows(PrepRadarInputTag);

        if (reader.IsValid()) {
            TMaybe <NProto::TPrepUslugi> prepUslugiMaybe = reader.GetRowMaybe(PrepUslugiInputTag);

            if (prepUslugiMaybe.Defined()) {
                const auto &prepUslugi = prepUslugiMaybe.GetRef();
                dstMsg.SetMascotOwner(prepUslugi.GetMascotOwner());
                dstMsg.SetUslugiId(prepUslugi.GetId());
            }
        }
        reader.SkipRows(PrepUslugiInputTag);

        if (reader.IsValid()){
            TMaybe <NProto::TPrepSnippetPic> prepSnippetPicMaybe = reader.GetRowMaybe(PrepSnippetInputTag);
            if (prepSnippetPicMaybe.Defined()){
                dstMsg.SetHaveSnippetPic(true);
            } else {
                dstMsg.SetHaveSnippetPic(false);
            }
        }
        reader.SkipRows(PrepSnippetInputTag);

        if (reader.IsValid()){
            TMaybe <NProto::TPrepNews> prepNewsMaybe = reader.GetRowMaybe(PrepNewsInputTag);
            if (prepNewsMaybe.Defined()){
                dstMsg.SetIsNews(true);
            } else {
                dstMsg.SetIsNews(false);
            }
        }
        reader.SkipRows(PrepNewsInputTag);

        if (reader.IsValid()){
            TMaybe <NProto::TPrepVerticalShare> prepVerticalShareMaybe = reader.GetRowMaybe(PrepVerticalShareInputTag);
            if (prepVerticalShareMaybe.Defined()){
                const auto &prepVerticalShare = prepVerticalShareMaybe.GetRef();
                dstMsg.SetMascotOwner(prepVerticalShare.GetMascotOwner());
                dstMsg.SetVerticalShareRating(prepVerticalShare.GetRating());
                dstMsg.SetVerticalShareIsValidated(prepVerticalShare.GetIsValidated());
            }
        }
        reader.SkipRows(PrepVerticalShareInputTag);

        TString owner = dstMsg.GetMascotOwner();
        TString normalized;
        if (NUrlNorm::NormalizeUrl(owner, normalized)){
            dstMsg.SetMascotOwner(GetOwner(normalized));
            writer.AddRow(dstMsg, ServicesOutputTag);
        }
    }
};

REGISTER_REDUCER(TMergeServicesJoinReducer)

void MergeServices(NYT::ITransactionPtr tx) {
    const auto &cfg = TConfig::CInstance();
    const NYT::TSortColumns KEYS = {"MascotOwner"};

    LOG_INFO("siteservices, merging");
    TReduceCmd<TMergeServicesJoinReducer>(tx)
        .Input(TTable<NProto::TPrepAlice>(tx, cfg.TABLE_SERVICES_PREP_ALICE), PrepAliceInputTag)
        .Input(TTable<NProto::TPrepCompanyInfo>(tx, cfg.TABLE_SERVICES_PREP_SPRAV), PrepSpravInputTag)
        .Input(TTable<NProto::TPrepMobileApp>(tx, cfg.TABLE_SERVICES_PREP_MOBILE_APPS), PrepMobileInputTag)
        .Input(TTable<NProto::TPrepShop>(tx, cfg.TABLE_SERVICES_PREP_SHOP_HOSTS), PrepShopInputTag)
        .Input(TTable<NProto::TPrepDirect>(tx, cfg.TABLE_SERVICES_PREP_DIRECT), PrepDirectInputTag)
        .Input(TTable<NProto::TPrepMarket>(tx, cfg.TABLE_SERVICES_PREP_MARKET), PrepMarketInputTag)
        .Input(TTable<NProto::TPrepMetrika>(tx, cfg.TABLE_SERVICES_PREP_METRIKA), PrepMetrikaInputTag)
        .Input(TTable<NProto::TPrepRadar>(tx, cfg.TABLE_SERVICES_PREP_RADAR), PrepRadarInputTag)
        .Input(TTable<NProto::TPrepUslugi>(tx, cfg.TABLE_SERVICES_PREP_USLUGI), PrepUslugiInputTag)
        .Input(TTable<NProto::TPrepSnippetPic>(tx, cfg.TABLE_SERVICES_PREP_SNIPPET_PIC), PrepSnippetInputTag)
        .Input(TTable<NProto::TPrepNews>(tx,cfg.TABLE_SERVICES_PREP_NEWS), PrepNewsInputTag)
        .Input(TTable<NProto::TPrepVerticalShare>(tx,cfg.TABLE_SERVICES_PREP_VERTICAL_SHARE), PrepVerticalShareInputTag)
        .Output(TTable<NProto::TServices>(tx, cfg.TABLE_SERVICES_EXPORT_RU ), ServicesOutputTag)
        .OperationWeight(cfg.OPERATION_WEIGHT)
        .ReduceBy(KEYS)
        .Do();


    TSortCmd<NProto::TServices>(tx, TTable<NProto::TServices>(tx, cfg.TABLE_SERVICES_EXPORT_RU))
        .By(KEYS)
        .Do();

    LOG_INFO("siteservices, merging - done");
}

int TaskMerge(int, const char **) {
    const auto &cfg = TConfig::CInstance();

    NYT::IClientPtr client = NYT::CreateClient(cfg.MR_SERVER_HOST);
    NYTUtils::CreatePath(client, cfg.TABLE_SERVICES_PREP_ROOT);

    NYT::ITransactionPtr tx = client->StartTransaction();
    MergeServices(tx);
    tx->Commit();

    return 0;
}

} //namespace NWebmaster
