#pragma once

#include "master_main.h"
#include "multithreading.h"
#include "initializer_message.h"
#include <balancer/kernel/coro/coro_event.h>
#include <balancer/kernel/process/base_process.h>

namespace NSrvKernel::NProcessCore {
    class TMasterProcess : public IDisposable {
    public:
        explicit TMasterProcess(TMainTask* task);
        void StartStatsListener();
        void StartAdminListener();

        void Execute(NThreading::TPromise<void>* startPromise);
        void HealthCheckInitializer();
        void InitializerRead();
        void FDChecker();

        void DoLaunchStartupAfterReloadConfigLoop() noexcept;
        void MasterShutDown(const TGracefulShutdownOpts& opts = TGracefulShutdownOpts{});
        void DoDispose() noexcept override;
        bool IsNeedShutdown() const noexcept;
        TSystemLog& Log() noexcept;

        TInitializerMessage PullMessageFromInitializer(TCont* cont);
        void PushMessageToInitializer(TCont* cont, const TInitializerMessage& message);

        // it is called from AdminCallBack_
        void ReopenLog(TEventData& event);
        void Version(TEventData& event);
        void ResetDnsCache(TEventData& event) noexcept;
        void GetConfigTag(TEventData& event) noexcept;
        void ShowListen(TEventData& event) noexcept;
        void DbgWorkersReady(TEventData& event) noexcept;
        void SandboxTaskId(TEventData& event) noexcept;
        void PrintMasterPid(TEventData& event);
        void ShutDown(TEventData& event);
        void GracefulShutdown(TEventData& event, const TGracefulShutdownOpts& opts);
        void ReloadConfig(TEventData& event, const TReloadConfigOpts& opts);
        void DumpSharedFiles(TEventData& event);
        void CallEvent(TEventData& event, bool jsonOut);

        void ProcessJsonEvent(TEventData& event);
        void ListEventHandlers(TEventData& event);

        TContExecutor& Executor() const noexcept;

        TSystemLog& Log() const {
            return Log_;
        }

        TMainTask* MainTask() {
            return MainTask_;
        }
    private:
        struct TReloadConfigStatus {
            bool Success = false;
            bool Timeouted = false;
            TString ErrorMsg;
        };

    private:
        void SendReloadSuccessful();
        void SendCancelReload();
        void SendOldMasterClosedUnistat();
        void RecvLoop();
        TReloadConfigStatus ReloadThroughInitializer(const TReloadConfigOpts& opts);

    private:
        TMainTask* MainTask_;
        TTwoNonblockingPipes* InitializerPipes_= nullptr;
        const TMainConfig& MainConfig_;
        size_t ExpectWorkersAfterReload_ = 0;
        TSystemLog& Log_;

        THolder<TW2WChannel<TC2MMessage>> MasterChannel_;
        THolder<TWorkerCpuStat> MasterCpuStat_;
        THolder<TOwnExecutor> MasterExecutor_;
        TAdminCallback AdminCallBack_;
        TStatsCallback StatsCallback_;
        THolder<TOwnListener> AdminListener_;
        THolder<TOwnListener> StatsListener_;
        THolder<TChildrenManager> ChildrenManager_;

        TCoroSingleCondVar ReloadStateMsgReceiveCV_;
        TInitializerMessage LastReloadStateMsg_;
        TCoroutine CpuMeasureCoroutine_;
        TCoroutine RecvLoopTask_;
        TCoroutine FDChecker_;
        TCoroutine HealthCheckTask_;
        TCoroutine InitializerCommunicationTask_;
        TCoroutine StopCont_;
        TCoroutine ReopenLogCont_;
        TCoroutine BannedAddressesCleaner_;

        bool IsTerminating_ = false;
        bool IsReloadingConfig_ = false;
        bool IsNewMaster_ = false;
    };
}
