#include "callback.h"

#include <balancer/kernel/coro/waked.h>

using namespace NSrvKernel;

namespace NBalancerServer {
    Y_TLS(server_callback) {
        explicit TTls(TContExecutor& executor)
            : EventWaker(&executor)
        {
        }
    public:
        NSrvKernel::TEventWaker EventWaker;
    };

    MODULE_WITH_TLS(server_callback) {
    public:
        TModule(const NSrvKernel::TModuleParams& mp)
            : TModuleBase(mp)
        {
        }

        TModuleCallback* CallbackPtr = nullptr;
    private:
        THolder<TTls> DoInitTls(IWorkerCtl* process) override {
            return MakeHolder<TTls>(process->Executor());
        }

        TError DoRun(const NSrvKernel::TConnDescr& descr, TTls& tls) const final {
            descr.ExtraAccessLog.SetSummary(Handle()->Name(), "success");
            Y_TRY(TError, error) {
                try {
                    const TCallbackEnv params = {
                            &tls.EventWaker,
                    };

                    return (*CallbackPtr)(descr, params);
                } Y_TRY_STORE(yexception);
            } Y_CATCH {
                // rewrite summary, only if it's not set by CallbackPtr
                if (TAccessLogSummary* summary = descr.ExtraAccessLog.Summary()) {
                    if (summary->AnsweredModule == Handle()->Name()) {
                        summary->AnswerReason = "error";
                    }
                }
                return error;
            };
            return {};
        }
    };

    IModule* TCallbackModuleHandle::DoConstruct(const TModuleParams& mp) const {
        THolder<IModule> res = TModule::Handle()->Construct(mp);
        TModule* m = dynamic_cast<TModule*>(res.Get());
        Y_VERIFY(m);

        m->CallbackPtr = const_cast<TModuleCallback*>(&Callback_);

        return res.Release();
    }

    const TString& TCallbackModuleHandle::DoName() const noexcept {
        return TModule::Handle()->Name();
    }
}


