#pragma once

#include "bundle_meta.h"
#include "wad_patcher.h"

#include <robot/jupiter/library/rtdoc/interface/mercury.h>
#include <robot/jupiter/library/rtdoc/file/model/docidmap.h>
#include <robot/jupiter/library/rtdoc/file/model/builder_input.h>
#include <robot/jupiter/library/rtdoc/merger/wad_merger.h>
#include <robot/jupiter/library/opt/mropt.h>
#include <robot/jupiter/library/opt/common/common.h>
#include <robot/jupiter/library/opt/shard_merge.h>
#include <mapreduce/yt/interface/client.h>
#include <kernel/doom/wad/wad.h>
#include <kernel/doom/wad/mega_wad.h>
#include <util/generic/yexception.h>
#include <util/generic/ptr.h>

namespace NFusion {
    struct TJupiterCmd;

    // Bind non-standard routines (TMode::WadCustomMerge, index conversion, etc.)
    class ICmdExtensions: public TThrRefBase {
    public:
        using TPtr = TIntrusivePtr<ICmdExtensions>;

    public:
        virtual void Init(TJupiterCmd& /*cmd*/, const TBundleVersion& /*bundleVer*/) {
        }

        virtual NRtDoc::IWadMerger::TPtr CreateWadCustomMerger() {
            return nullptr;
        }

        virtual void PreprocessInputs(const NRtDoc::IBuilderInputs& /*inputs*/) {
        }

        virtual TString ConstructFileName(const TString& outputPrefix) const;

        virtual bool UsesCustomRebuild() const {
            return false;
        }

        virtual bool ShouldSwitchToRebuild() const {
            ythrow yexception() << "not implemented"; // method is used only with some TDeploy values
        }
    };

    struct TJupiterCmd {
    public:
        TString DisplayName;
        TString OutputPrefix;
        NBundleMeta::TMode Mode;
        NBundleMeta::TDeploy Deploy;
        ICmdExtensions::TPtr Extensions;
        TVector<TString> IndexFilePrefixes; // for WadMerge mode
        std::function<void(NJupiter::TShardMergerOpts&, NYT::IIOClient& client)> Method;
    };

    using TJupiterCmds = TVector<TJupiterCmd>;

    struct TMercuryPrepCmd {
        TString DisplayName;
        NJupiter::TMercuryCmdPtr Method;
    };

    using TMercuryCmds = TVector<TMercuryPrepCmd>;

    using TSpecialCmds = THashSet<TString>;

    struct TPrepArchiveConfig {
        bool Enabled = false;
        bool KeepAll = false;
        TVector<TString> Filter;
    };

    class TExtBuilderBundle {
    public:
        TMercuryCmds PriorPrepCommands;
        TJupiterCmds PriorCommands;

        TMercuryCmds PrepCommands;
        TJupiterCmds Commands;
        TSpecialCmds SpecialCommands;

        TJupiterCmds LateCommands;

        //TODO(REFRESH-383): refactor class TExtBuilderBundle into something enumerable. The current structure is out of control: Prior, Prep, Special, Late...

        TPrepArchiveConfig SavedPreparates;
    };
}
