#pragma once

#include "assert_policy.h"

#include <robot/jupiter/library/rtdoc/file/model/stop_flag.h>
#include <robot/jupiter/library/rtdoc/protos/builder_task.pb.h>
#include <library/cpp/logger/log.h>
#include <util/generic/ptr.h>

namespace NFusion {
    class ITaskTrace : public TThrRefBase {
    public:
        using TPtr = TIntrusivePtr<ITaskTrace>;
    public:
        virtual TLog* GetProgressLogger() = 0;
    };

    class IExtBuilderTrace : public TThrRefBase {
    public:
        using TPtr = TIntrusivePtr<IExtBuilderTrace>;
    public:
        virtual void OnAppStart(const TString& statePrefix, const TAssertPolicy& assertPol) = 0;
        virtual ITaskTrace::TPtr OnTaskStart(const NRtDoc::TBuilderTask& task) noexcept = 0;
        virtual void OnTaskEnd(const NRtDoc::TBuilderTask& task, const NRtDoc::TBuilderTaskResult& result) noexcept = 0;
    };

    //
    // Application container
    //
    class TExtBuilderExecutor {
    private:
        // Main entry point
        bool DoMerge(NRtDoc::TBuilderTaskResult& result, const NRtDoc::TBuilderTask& args, ITaskTrace::TPtr logger);

    public:
        TExtBuilderExecutor()
            : Stop_(MakeIntrusive<NRtDoc::TStopHandle>())
        {
        }

        void AsyncStop() noexcept {
            Stop_->Signal();
        }

        //sync run
        void Merge(NRtDoc::TBuilderTaskResult& result, const NRtDoc::TBuilderTask& args) noexcept {
            ITaskTrace::TPtr logger;
            if (Trace_) {
                logger = Trace_->OnTaskStart(args);
            }

            try {
                const bool ok = DoMerge(result, args, logger);
                result.SetErrorCode(ok ? 0 : !Stop_->Get() ? 1 : 10);
            } catch (...) {
                result.SetErrorCode(1);
            }

            if (Trace_) {
                Trace_->OnTaskEnd(args, result);
            }
        }

    public:
        void SetAssertPolicy(const TAssertPolicy& policy) {
            AssertPolicy_ = policy;
        }

        void SetTrace(IExtBuilderTrace::TPtr trace) {
            Trace_ = trace;
        }

    private:
        TAssertPolicy AssertPolicy_;
        IExtBuilderTrace::TPtr Trace_;
        NRtDoc::TStopHandle::TPtr Stop_;
    };

}
