#pragma once

#include <types/base/types.h>
#include <types/ptr/ref_counted.h>
#include <types/ptr/intrusive_ptr.h>
#include <types/const/priority.h>
#include <tbb/concurrent_hash_map.h>
#include <tbb/concurrent_priority_queue.h>
#include <tbb/parallel_for.h>
#include <tbb/blocked_range.h>
#include <atomic>
#include <vector>

namespace extra2d {

using TimerHdl = uint32;
constexpr TimerHdl INVALID_HDL = 0;

/**
 * @brief 定时器目标接口
 * 
 * 实现此接口的对象可以接收 update 回调
 */
class TimerTarget {
public:
    virtual ~TimerTarget() = default;
    virtual void update(float dt) = 0;
};

/**
 * @brief 定时器基类
 */
class Timer : public RefCounted {
public:
    virtual ~Timer() = default;

    virtual void update(float dt) = 0;
    virtual void trigger() = 0;

    bool isPaused() const { return paused_; }
    bool isDone() const { return done_; }
    TimerHdl hdl() const { return hdl_; }

    void pause() { paused_ = true; }
    void resume() { paused_ = false; }
    void cancel() { done_ = true; }

protected:
    Timer() = default;

    float elapsed_ = -1.0f;
    float interval_ = 0.0f;
    float delay_ = 0.0f;
    uint32 repeat_ = 0;
    uint32 timesExecuted_ = 0;
    bool useDelay_ = false;
    bool runForever_ = false;
    bool paused_ = false;
    bool done_ = false;
    TimerHdl hdl_ = INVALID_HDL;

    friend class Scheduler;
};

/**
 * @brief 调度器
 * 
 * 基于 TBB 实现的线程安全调度器，支持定时器和 update 回调
 */
class Scheduler {
public:
    using Cb = Fn<void(float)>;
    using VoidCb = Fn<void()>;

    static Scheduler& inst();

    TimerHdl scheduleUpdate(TimerTarget* target, int pri = 0);
    void unscheduleUpdate(TimerTarget* target);

    TimerHdl schedule(Cb cb, float interval, uint32 repeat = 0, float delay = 0.0f);
    TimerHdl scheduleOnce(VoidCb cb, float delay);
    TimerHdl scheduleForever(Cb cb, float interval);

    void unschedule(TimerHdl hdl);
    void unscheduleAll();
    void pause(TimerHdl hdl);
    void resume(TimerHdl hdl);

    void setTimeScale(float scale) { timeScale_ = scale; }
    float timeScale() const { return timeScale_; }

    void update(float dt);
    void updateParallel(float dt);

    bool isScheduled(TimerHdl hdl) const;
    size_t count() const;

private:
    Scheduler() = default;

    struct UpdateEntry {
        TimerTarget* target;
        int pri;
        bool paused;
        bool markedForDel;

        bool operator<(const UpdateEntry& o) const { return pri > o.pri; }
    };

    std::vector<UpdateEntry> updates_;
    tbb::concurrent_hash_map<TimerTarget*, size_t> updateIndex_;
    tbb::concurrent_hash_map<TimerHdl, Ptr<Timer>> timers_;
    tbb::concurrent_priority_queue<UpdateEntry> updateQueue_;

    std::atomic<TimerHdl> nextHdl_{1};
    std::atomic<float> timeScale_{1.0f};
    std::atomic<bool> locked_{false};

    TimerHdl genHdl();
};

#define SCHED extra2d::Scheduler::inst()

} // namespace extra2d
