#include "connection_manager_process.h"

#include <balancer/kernel/balancing/updater.h>
#include <balancer/kernel/ctl/children_process_common.h>
#include <balancer/kernel/dns/dns_helper.h>
#include <balancer/kernel/process/sd/sd.h>


namespace NSrvKernel::NProcessCore {
    void TConnectionManagerProcess::Execute() {
        Executor_->Executor().Execute();
    }

    void TConnectionManagerProcess::Stop() {
        Dispose();
    }

    void TConnectionManagerProcess::RecvLoop() {
        auto runningCont = Executor_->Executor().Running();
        auto waker = ThreadLocalEventWaker(runningCont);
        auto* wakerPtr = waker.Get();

        bool shutdown = false;
        while (!runningCont->Cancelled() && !shutdown) {
            TM2CMessage message;
            auto status = M2CChannel_.Receive(message, TInstant::Max(), runningCont, wakerPtr);
            if (status != EChannelStatus::Success) {
                return;
            }

            std::visit(TOverloaded{
                [&](const TEvent& masterEvent) {
                    Y_UNUSED(masterEvent.OutputChannel->Send("", TInstant::Max(), runningCont, wakerPtr));
                },

                [&](const TListEvents& toMaster) {
                    Y_UNUSED(toMaster.OutputChannel->Send(TVector<TString>{}, TInstant::Max(), runningCont, wakerPtr));
                },

                [&](const TShutDown&) {
                    Stop();
                    shutdown = true;
                },

                [&](const TResetDnsCache&) {
                }
            }, message);
        }
    }

    TConnectionManagerProcess::TConnectionManagerProcess(TMainTask& task, const TMainOptions& options, TW2WChannel<TM2CMessage>& m2cChannel,
            NConnectionManager::TConnectionManager* connectionManager)
        : TBaseProcess(task.Config().NChildren + ChildProcessTypeToIndex(WorkerType()), task)
        , MainStats_(MakeHolder<TMainStats>(*MainTask_.MainStats_, WorkerId()))
        , M2CChannel_(m2cChannel)
    {
        ConnectionManager_ = connectionManager;
        const auto& config = task.Config();

        WorkerCpuStat_ = task.ProcessStatOwner_->GetProcessStat(WorkerType())->GetWorkerCpuStat(WorkerId());

        Executor_ = MakeHolder<TOwnExecutor>(
            options.CoroStackSize(),
            options.Poller,
            options.CoroStackGuard,
            options.CoroPoolSettings,
            WorkerCpuStat_.Get()
        );
        Executor_->Executor().SetFailOnError(config.CoroFailOnError);

        CpuMeasureCoroutine_ = StartCpuAndTimeMeasurer(Executor_->Executor(), WorkerCpuStat_.Get(), nullptr);

        ConnectionManagerLog_ = task.ConnectionManagerLog_.GenerateThreadedLog(&Executor(), WorkerId());
        ConnectionManagerLog_ << "hello from connection manager" << Endl;

        Runtime_ = ConnectionManager_->StartRuntime(&Executor());

        RecvLoop_ = TCoroutine(ECoroType::Service, "TConnectionManagerProcess::RecvLoop", &Executor_->Executor(),
                &TConnectionManagerProcess::RecvLoop, this);
    }

    TConnectionManagerProcess::~TConnectionManagerProcess() {
        Dispose();
    }

    TSharedFiles* TConnectionManagerProcess::SharedFiles() noexcept {
        Y_FAIL();
    }

    TThreadedQueue* TConnectionManagerProcess::ThreadedQueue(const TString&) noexcept {
        Y_FAIL();
    }

    NSrvKernel::TPingerManager& TConnectionManagerProcess::SharedPingerManager() noexcept {
        Y_FAIL();
    }

    TLog* TConnectionManagerProcess::GetLog(const TString&) {
        Y_FAIL();
    }

    NProcessCore::TChildProcessType TConnectionManagerProcess::WorkerType() const noexcept {
        return NProcessCore::TChildProcessType::ConnectionManager;
    }

    NDns::IResolver& TConnectionManagerProcess::Resolver() noexcept {
        Y_FAIL();
    }

    void TConnectionManagerProcess::DoDispose() noexcept {
        Runtime_.Destroy();
        ConnectionManagerLog_.DisposeBackend();
        Executor_->Executor().Abort();
    }

    TLog* TConnectionManagerProcess::GetDynamicBalancingLog() {
        Y_FAIL();
    }
}
