#include <saas/library/sender_neh/waiter.h>
#include <library/cpp/testing/unittest/registar.h>

namespace {

    struct TTask : public IObjectInQueue {
        void Process(void*) override {
            Times.push_back(Now());
        }
        TVector<TInstant> Times;
    };

}

Y_UNIT_TEST_SUITE(WaiterSuite) {
    Y_UNIT_TEST(StartStop) {
        TThreadPool mtp;
        TTask task;
        mtp.Start(1);
        TWaiter waiter(mtp);
        waiter.Start();
        waiter.Stop(true);
        waiter.Start();
        waiter.Stop(false);
        waiter.Start();
        waiter.Add(TInstant::Max(), &task);
        waiter.Add(TInstant::Max(), &task);
        waiter.Add(TInstant::Max(), &task);
        waiter.Stop(false);
        UNIT_ASSERT_EQUAL(task.Times.size(), 0);
        waiter.Start();
        TInstant now = Now();
        waiter.Add(now + TDuration::MilliSeconds(300), &task);
        waiter.Add(now + TDuration::MilliSeconds(600), &task);
        waiter.Add(now + TDuration::MilliSeconds(900), &task);
        waiter.Stop(true);
        mtp.Stop();
        UNIT_ASSERT_EQUAL(task.Times.size(), 3);
    }

    Y_UNIT_TEST(Times) {
        TThreadPool mtp;
        TTask task;
        mtp.Start(1);
        TWaiter waiter(mtp);
        waiter.Start();
        TInstant now = Now();
        TVector<TInstant> times {
            now + TDuration::MilliSeconds(600),
            //insert to begin
            now + TDuration::MilliSeconds(300),
            //insert to end
            now + TDuration::MilliSeconds(900)
        };
        for (auto time : times) {
            waiter.Add(time, &task);
        }
        waiter.Stop(true);
        mtp.Stop();
        UNIT_ASSERT_EQUAL(task.Times.size(), times.size());
        UNIT_ASSERT(fabs(double(task.Times[0].MilliSeconds() - now.MilliSeconds()) - 300) < 50);
        UNIT_ASSERT(fabs(double(task.Times[1].MilliSeconds() - now.MilliSeconds()) - 600) < 50);
        UNIT_ASSERT(fabs(double(task.Times[2].MilliSeconds() - now.MilliSeconds()) - 900) < 50);
    }
}
