//
// Created by Ht on 2020/8/14.
//

#ifndef LIBDEVCPP_QTIMERENGINE_H
#define LIBDEVCPP_QTIMERENGINE_H

#include <functional>
#include <list>
#include <unordered_map>

#include <qlibc/httplib.h>
#include <qlibc/QLogger.h>
#include <cross/SystemUtil.h>
#include <qlibc/DateUtils.hpp>
#include <qlibc/QMemObject.h>

#ifdef WIN32
#include <cross/platform.h>
#else
#include <sys/time.h>
#endif

namespace qlibc {

    /**
     *  激活后，启动线程：根据设定参数、定期激活、检查Timer的运行清空。当连续无Timer时，自动停止线程；当Timer存量大于1时、运行管理线程。
     *      执行线程，需要共享Operator的线程池
     *
     */

#ifdef DEBUG
#define TM_COUNT_START 0
#define TM_SPEED_TIMES 1
#define TM_PRINT_TICKING 0
#define TM_PRINT_INVOKE 0
#else
#define TM_COUNT_START 0
#define TM_SPEED_TIMES 1
#define TM_PRINT_TICKING 0
#define TM_PRINT_INVOKE 0
#endif

    using QTypeIndex = unsigned char;
    using QBuckIndex = unsigned short;
    using QTickIndex = unsigned long;

    enum QBucketType {
        BTypeMSec  = 0,
        BTypeSecond,
        BTypeMinute,
        BTypeHour,
        BTypeDay,
        BTypeMonth,
        BTypeYear,
    };

    enum QLastType {
        LTUlimit = 0,           //循环类型，无限制
        LTTimes,                //计数
        LTDuration,             //周期
        LTTimePoint,            //时间点
    };

    enum QTimerAccuracy {
        TATypeNormal = 0,
        TATypeHigh = 1,
    };

    static const QTypeIndex  recheck_offset_level = 1;   //cursor校验精度级别，在多久后重新校验偏移值
    static const QBucketType bucket_types [] ={BTypeYear, BTypeMonth, BTypeDay, BTypeHour, BTypeMinute, BTypeSecond, BTypeMSec};

    static const QBuckIndex buck_end = 0xFFFF;
    static const QBuckIndex bucket_count_normal[] = {0, 0, 30, 24, 60, 60,buck_end};          //Max 3Yeas
    static const QBuckIndex bucket_count_high[] = {100, 12, 30, 24, 60, 60, 50, buck_end};     //Max 100Years
    static const QBuckIndex* bucket_counts[] = {bucket_count_normal, bucket_count_high};

    static const QTickIndex tick_end = (QTickIndex)0xFFFFFFFFFFFFFFFF;
    static const QTickIndex bucket_ticks_normal[] = {31104000, 2592000, 86400, 3600, 60, 1, tick_end, tick_end};
    static const QTickIndex bucket_ticks_high[] = {1555200000, 129600000, 4320000, 180000, 3000, 50, 1, tick_end};     //Max 100Years
    static const QTickIndex* bucket_ticks[] = {bucket_ticks_normal, bucket_ticks_high};

    const static QBuckIndex normal_accuracy = 1000;
    const static QBuckIndex high_accuracy = 50;
    class QTimer;
    using QRTimer = std::shared_ptr<QTimer>;

    using QTimerTask = std::function<bool(QRTimer, void*)>;

    using QTimerList = std::list<QRTimer>;
    using QTimerBucketSlots = std::vector<QTimerList>;
    using QTimerBucketPool = std::vector<QTimerBucketSlots>;

    class JE_API QTimer {
        QTimerTask*         task_;
        QTickIndex          repeat_;
        QTickIndex          delay_;
        QTickIndex          last_;      //循环次数或到时间退出,默认为0,永远循环
        void*               context_;
        bool                run_alone_ = true;   //默认单独线程执行，不锁定timer
        QTimerList*         list_ = nullptr;
        QRTimer             listSelfSPPtr_=nullptr;//指向list中保存 shared_ptr值指针，不用删除自己
    public:
        explicit QTimer(const QTimerTask& task, QTickIndex repeat_gap_msec,
                        void* param = nullptr, QTickIndex delay = 0,
                        bool alone = true, QTickIndex last = 0);

        ~QTimer() {
            last_ = 1;
            delete task_;
            task_ = nullptr;
        }

        bool operator()();

        QTickIndex repeat();

        QTickIndex delay();

        bool stand_alone();

        bool quit();

        void resetDelay(QTickIndex left);

        void setPos(QTimerList &list){
            list_ = &list;
            auto &r = list.back();
            //保存在list中的指针拷贝，但不复制shared_ptr，调用时复制
            //每次刷新list时重新设置
            //在执行过程中，如果list中的值被释放，则需要重新刷新 selfSPPtr_
            listSelfSPPtr_ = r;
        }

        void clearSelfRef() {
            listSelfSPPtr_ = nullptr;
        }

        void removeMeFromBuckets();
    };

    class JE_API QTimerEngine : public QSelfRefObject {
    protected:
        std::string         engine_name_;

        httplib::RThreadPool thread_pool_;
            QTimerBucketPool     buckets_;
            std::vector<QBuckIndex>  cursors_;

        bool                ticking = false;
        bool                stopped = false;
        QBuckIndex          tick_gap_;   //Timer精度, 50 , 1000
        std::recursive_mutex
                            tick_mutex_;
        QTimerAccuracy      acc_type_;
        unsigned int        tm_off_base_;       //初始计数的毫秒偏移
        long                tm_correct_ = 0;   //纠正偏移
        QTickIndex          tm_couted_ = TM_COUNT_START;    //已计数的修正量

        std::mutex              tick_wait_mutex_;
        std::condition_variable tick_wait_;


        void freshTick();

        void cascades(QTypeIndex lastType, QTypeIndex off_level);

        bool insertToBuckets(QRTimer& timer, QTickIndex tick_count);

        bool invokeTimer(QRTimer& timer);

        bool execTimer(QRTimer timer);

        QRTimer& doAddTimer(QRTimer& timer, bool repeat = false);

        //一般模式，支持一天以内的触发器。超过1天的触发器，如何处理？用高精度模式、
        void buildBuckets();

        long markSystemTime();

        QTickIndex  timerLast(QTickIndex last, QLastType lastType);

        void repeatTimer(QRTimer& timer);

        QRTimer& addTimer(QRTimer timer);

        void clearTimers();

    public:
        explicit QTimerEngine(httplib::RThreadPool pool , QTimerAccuracy acc = TATypeNormal);

        virtual ~QTimerEngine();

        QRTimer repeatRun(const QTimerTask& task, QTickIndex repeat, QTickIndex delay = 0, bool alone = true, void* param = nullptr, QTickIndex last = 0, QLastType lastType = LTTimes);

        QRTimer delayRun(QTickIndex delay, const QTimerTask& task, bool alone = true, void* param = nullptr);

        void stopTimer(QRTimer& tmr);

        void stopEngine();

        void startTimerEngine();

        bool isActive() {
            RECURSIVE_LOCK(tick_mutex_);
            return ticking;
        }

        httplib::RThreadPool getPoolRef() {
            return thread_pool_;
        }

        const std::string &objId() override;


    };

    using QRTimerEngine = std::shared_ptr<QTimerEngine>;
}

#define declareTimerTask(__n,__t,__p) bool __n(qlibc::QRTimer __t, void* __p)
#define lamdaTimerTask(__t,__p) (const qlibc::QRTimer& __t, void* __p)->bool


#endif //LIBDEVCPP_QTIMERENGINE_H
