#include "worker.h"

namespace {
struct TWorkerHolder {
    NHttp::NRequesters::TWorker* Worker = nullptr;
};
}

namespace NHttp::NRequesters {
TWorker::TCoroutine::~TCoroutine() {
    Cancel();
}

bool TWorker::TCoroutine::IsRunning() const {
    return Cont_;
}

void TWorker::TCoroutine::Cancel() {
    if (!Cont_) {
        return;
    }

    Worker_.Execute([this]() {
        if (!Cont_) {
            return;
        }

        Y_VERIFY(Cont_ != RunningCont());
        Cont_.load()->Cancel();
        RunningCont()->Join(Cont_, TInstant::Max());
    });
}

TWorker::TWorker(const TString& name)
    : Executor_{16_KB}
    , Channel_{std::numeric_limits<size_t>::max()}
    , Thread_{TThread::TParams{&TWorker::Run, this}.SetName(name)}
{
    Thread_.Start();
}

TWorker::~TWorker() {
    Execute([this] {
        Executor_.CreateOwned([this](TCont*) {
            Executor_.Abort();
        }, "TContExecutor::Abort");
    });
}

TContExecutor& TWorker::Executor() {
    return Executor_;
}

TWorker* TWorker::Current() {
    return FastTlsSingletonWithPriority<TWorkerHolder, 0>()->Worker;
}

void* TWorker::Run(void* data) {
    auto self = reinterpret_cast<TWorker*>(data);
    FastTlsSingletonWithPriority<TWorkerHolder, 0>()->Worker = self;

    self->Executor_.SetFailOnError(true);
    self->Executor_.CreateOwned([self](TCont* cont) { self->Loop(cont); }, "NHttp::TWorker::Loop");
    self->Executor_.Execute();

    FastTlsSingletonWithPriority<TWorkerHolder, 0>()->Worker = nullptr;

    return nullptr;
}

void TWorker::Loop(TCont* cont) {
    std::function<void ()> func;
    while (!cont->Cancelled() && Channel_.Receive(func, TInstant::Max(), RunningCont()) == NSrvKernel::EChannelStatus::Success) {
        func();
    }
}
}
