#pragma once

#include <util/datetime/base.h>
#include <util/generic/queue.h>
#include <library/cpp/deprecated/atomic/atomic.h>
#include <util/system/condvar.h>
#include <util/system/mutex.h>
#include <util/thread/pool.h>

class TWaiter final : public IThreadFactory::IThreadAble {
public:
    TWaiter(IThreadPool& executer);
    ~TWaiter();
    void Start();
    void Stop(bool wait);
    void Add(TInstant time, IObjectInQueue* task);

private:
    struct TWaitedTask {
        Y_FORCE_INLINE TWaitedTask(TInstant time, IObjectInQueue* task)
            : Time(time)
            , Task(task)
        {}

        Y_FORCE_INLINE bool operator <(const TWaitedTask& task) const {
            return Time > task.Time;
        }

        TInstant Time;
        IObjectInQueue* Task;
    };

    using TQueue = TPriorityQueue<TWaitedTask, TVector<TWaitedTask>>;

private:
    virtual void DoExecute() override;
    bool NeedContinue() const;

    Y_FORCE_INLINE TInstant NextTaskTime() const {
        return Queue.empty() ? TInstant::Max() : Queue.top().Time;
    }

private:
    IThreadPool& Executer;
    TMutex Mutex;
    TQueue Queue;
    THolder<IThreadFactory::IThread> Thread;
    TCondVar Added;
    TAtomic Stopped = 0;
};
