#pragma once

#include <cstdint>
#include <functional>

namespace blitz {
namespace utils {

std::uint64_t GetTime();

typedef std::function<void()> TimerExecFunction;

// utililty class to call a function at regular period of time
class AutoTimer {
  private:
	std::uint64_t m_Interval;
	TimerExecFunction m_Function;

	std::uint64_t m_LastTime = GetTime();
	std::uint64_t m_InternalTime = 0;

  public:
	AutoTimer() : m_Interval(0), m_Function(nullptr) {}
	AutoTimer(std::uint64_t interval) : m_Interval(interval), m_Function(nullptr) {}
	AutoTimer(std::uint64_t interval, TimerExecFunction callback) : m_Interval(interval), m_Function(callback) {}

	void Update();
	void Update(std::uint64_t delta);

	void Reset();

	void SetInterval(std::uint64_t newInterval) {
		m_Interval = newInterval;
	}

	std::uint64_t GetInterval() const {
		return m_Interval;
	}

	void SetCallbackFunction(TimerExecFunction newCallback) {
		m_Function = newCallback;
	}

	TimerExecFunction GetCallbackFunction() const {
		return m_Function;
	}
};

// utililty class to trigger update at regular period of time
class Timer {
  private:
	std::uint64_t m_Interval;  // in millis
	std::uint64_t m_InternalTime = 0;

  public:
	Timer() : m_Interval(0) {}
	Timer(std::uint64_t interval) : m_Interval(interval) {}

	bool Update(std::uint64_t delta);

	void Reset();

	void SetInterval(std::uint64_t newInterval) {
		m_Interval = newInterval;
	}

	std::uint64_t GetInterval() const {
		return m_Interval;
	}
};

// utililty class to trigger update at regular period of time with a cooldown
class CooldownTimer {
  private:
	std::uint64_t m_Cooldown;  // in millis
	std::uint64_t m_CooldownTime;

  public:
	CooldownTimer() : m_Cooldown(0), m_CooldownTime(0) {}
	CooldownTimer(std::uint64_t cooldown) : m_Cooldown(0), m_CooldownTime(cooldown) {}

	bool Update(std::uint64_t delta);

	void ApplyCooldown();

	void Reset();

	void SetCooldown(std::uint64_t newCooldown) {
		m_CooldownTime = newCooldown;
	}

	std::uint64_t GetCooldown() const {
		return m_CooldownTime;
	}
};

}  // namespace utils
}  // namespace blitz
