#pragma once

#include "master_main.h"
#include "messages.h"

#include <library/cpp/coroutine/engine/impl.h>

#include <util/generic/ptr.h>
#include <util/generic/vector.h>

namespace NSrvKernel {
    class TChild;

    class TStats {
    public:
        explicit TStats(ICtl& ctl)
            : ChildrenAliveCounter_(ctl.SharedStatsManager().MakeGauge("childs-alive").Build())
            , ThreadFreezing_(ctl.SharedStatsManager().MakeGauge("threads-froze").Build())
        {}

        void SetThreadFreezing(bool value) noexcept {
            ThreadFreezing_.Set(value);
        }

        void SetAliveChildren(size_t count) {
            ChildrenAliveCounter_.Set(count);
        }

    private:
        TSharedCounter ChildrenAliveCounter_;
        TSharedCounter ThreadFreezing_;
    };

    struct TChildrenManagerOpts {
        bool Watchdog = true;
        size_t WorkersCount = 1;
        TDuration WorkerStartDelay;
        TDuration WorkerStartDuration;
    };

    class TChildrenManager {
    public:
        TChildrenManager(TContExecutor& masterExecutor, NProcessCore::TMainTask& mainTask, TW2WChannel<TC2MMessage>& masterChannel,
                         TChildrenManagerOpts opts, NProcessCore::TChildProcessMask mask);

        ~TChildrenManager();

        void Start();

        bool IsShutdown() const {
            return ShutDown_;
        }

        void Shutdown(const TGracefulShutdownOpts& opts);

        void ResetDnsCache();

        void CallEvent(TEventData& eventData, bool jsonOut);
        void ListEventHandlers(TEventData& event);

    private:
        void SpawnChildren();

        void OnShutdown(TInstant deadline);

        void JoinThreads(TInstant deadline);

        void SendMessage(TM2CMessage message, TDuration timeout, std::function<void(size_t, TDuration, TCont*, TThreadLocalEventWaker*)> postProcess = {});

        void Run();

        void ThreadsChecker();

    private:
        bool ShutDown_ = false;
        TContExecutor& Executor_;
        NProcessCore::TMainTask& MainTask_;
        TSystemLog& Log_;
        TW2WChannel<TC2MMessage>& MasterChannel_;
        TChildrenManagerOpts Opts_;
        TStats Stats_;
        TVector<THolder<TChild>> Children_;
        TVector<std::pair<THolder<TW2WChannel<TM2CMessage>>, NProcessCore::TChildProcessType>> ChildrenChannels_;

        TCoroutine SpawningCoroutine_;
        TCoroutine ThreadsCheckerTask_;
    };
}
