#pragma once

#include "children_process_common.h"

#include <balancer/kernel/storage/storage.h>
#include <balancer/kernel/log/log.h>
#include <balancer/kernel/stats/manager.h>
#include <balancer/kernel/dns/resolver.h>
#include <balancer/kernel/memory/shared.h>
#include <balancer/kernel/net/address.h>
#include <balancer/kernel/net/socket.h>
#include <balancer/kernel/fs/shared_files.h>
#include <balancer/kernel/custom_io/stream.h>
#include <balancer/kernel/pinger/common/pinger_manager_face.h>
#include <library/cpp/config/config.h>
#include <library/cpp/json/json_writer.h>
#include <library/cpp/logger/log.h>
#include <util/datetime/base.h>

namespace NYP::NServiceDiscovery {
    class TEndpointSetManager;
}

namespace NConnectionManager {
    class TConnectionManager;
}

namespace NSrvKernel {
    namespace NRpsLimiter {
        struct TQuotaManager;
    }

    class TEventHandler;
    class TThreadedQueue;
    class IModule;
    struct TModuleRequirements;

    class TBannedAddresses;

    class TBackendProtocolFactory;
    struct IChannelRequest;

    namespace NProcessCore {
        struct TMainConfig;
    }

    namespace NDynamicBalancing {
        class TUpdaterManager;
    }

    struct TBackendCheckOverridenParameters;

    struct TGracefulShutdownOpts {
        TDuration CoolDown = TDuration::Seconds(0);
        TDuration Timeout = TDuration::Seconds(10);
        TDuration CloseTimeout = TDuration::Seconds(5);
        bool SkipBlockRequests = false;
    };

    struct TReloadConfigOpts {
        TString NewConfigPath;
        NConfig::TGlobals NewGlobals;
        size_t NewCoroStackSize = 0;
        TDuration Timeout = TDuration::Seconds(60);
        TDuration WorkerStartDelay = TDuration::Seconds(1);
        bool SaveGlobals = false;
        TGracefulShutdownOpts GracefulShutdownOpts;
    };

    class TEventData {
    public:
        TEventData(TStringBuf event, IExceptionlessOutputStream& out) noexcept
            : Event_(event)
            , Out_(out)
            , JsonWriter_(&Out_, /* formatOutput = */ false)
        {}

        const TStringBuf Event() const noexcept {
            return Event_;
        }

        NJson::TJsonWriter& Out() noexcept {
            return JsonWriter_;
        }

        IExceptionlessOutputStream& RawOut() noexcept {
            return Out_;
        }

        TEventData Copy(IExceptionlessOutputStream& out) const noexcept {
            return { Event_, out };
        }

        TEventData Copy(TStringBuf event) const noexcept {
            return { event, Out_ };
        }

        void SetEvent(TStringBuf event) noexcept {
            Event_ = event;
        }

        void SetError() {
            Error_ = true;
        }

        bool IsError() {
            return Error_;
        }

    private:
        TStringBuf Event_;
        IExceptionlessOutputStream& Out_;
        NJson::TJsonWriter JsonWriter_;
        bool Error_ = false;
    };

    class IModuleData {
    public:
        virtual ~IModuleData() {}
    };

    class IGracefulShutdownHandler : public TIntrusiveListItem<IGracefulShutdownHandler> {
    public:
        virtual ~IGracefulShutdownHandler() {}
        virtual void OnShutdown() noexcept = 0;
    };

    class IWorkerCtl {
    public:
        explicit IWorkerCtl(size_t workerId)
            : WorkerId_(workerId)
        {}

        virtual ~IWorkerCtl() = default;

        size_t WorkerId() const {
            return WorkerId_;
        }

        virtual TEventHandler* EventHandler() const noexcept = 0;
        virtual TSharedFiles* SharedFiles() = 0;
        virtual TThreadedQueue* ThreadedQueue(const TString& name) = 0;
        virtual NSrvKernel::IPingerManager& SharedPingerManager() = 0;
        virtual bool IsShuttingDown() const = 0;
        virtual bool BlockNewRequests() const = 0;
        virtual NDns::IResolver& Resolver() = 0;
        virtual TLog* GetLog(const TString& name) = 0;
        virtual TLog* GetDynamicBalancingLog() = 0;
        virtual NProcessCore::TChildProcessType WorkerType() const = 0;
        virtual TContExecutor& Executor() const = 0;
        virtual void DumpSharedFiles(NJson::TJsonWriter& out) = 0;
        virtual void AddGracefulShutdownHandler(IGracefulShutdownHandler* handler, bool isHTTP2) = 0;

        virtual void RegisterBackendGroup(TString /*id*/, IModule* /*self*/) {};
        virtual void CloseListeners(const TGracefulShutdownOpts&) {};

        virtual const TBackendCheckOverridenParameters& BackendCheckOverrides() = 0;

    private:
        const size_t WorkerId_ = 0;
    };

    class ICtl {
    public:
        virtual ~ICtl() = default;

        TLog* CreateDefaultLog() {
            return CreateLog(TString());
        }

        virtual TLog* CreateLog(const TString& name) = 0;
        virtual NSrvKernel::TSharedAllocator& SharedAllocator() noexcept = 0;
        virtual NSrvKernel::TSharedStatsManager& SharedStatsManager() noexcept = 0;
        virtual THolder<IModuleData>& GetModuleData(TStringBuf name) noexcept = 0;
        virtual NYP::NServiceDiscovery::TEndpointSetManager* GetSDManager() noexcept = 0;
        virtual bool IsPingerEnabled() const noexcept = 0;
        virtual NDynamicBalancing::TUpdaterManager& DynamicBalancingUpdaterManager() noexcept = 0;
        virtual NConnectionManager::TConnectionManager* ConnectionManager()  noexcept = 0;
        virtual size_t GetCountOfChildren() const noexcept = 0;
        virtual TSharedFiles& GetSharedFiles() noexcept = 0;
        virtual NRpsLimiter::TQuotaManager* GetQuotaManager() noexcept = 0;
        virtual TBackendProtocolFactory& GetProtocolFactory() const noexcept = 0;
        virtual void RegisterStorage(NSrvKernel::NStorage::TStorage*) = 0;
        virtual const NProcessCore::TMainConfig& GetMainConfig() const noexcept = 0;
        virtual const TString& GetConfigHash() const noexcept = 0;
        virtual TBannedAddresses& BannedAddresses() noexcept = 0;
        virtual TModuleRequirements& GetModuleRequirements() const noexcept = 0;
    };
}
