/*
{{copyright}}
*/

/*
{{version}}
*/

/*
{{license}}
*/

#pragma once

#include <chrono>

namespace sdi_toolBox::dateTime
{
//--------------------------------------------------------------
/**
 * @brief Abstract interface for timer functionality.
 *
 * Provides a common interface for timer implementations, allowing
 * measurement of elapsed time and checking for timeouts.
 * Derived classes must implement the now() method to provide the
 * current time point.
 */
class ITimer
{
  public:
  using Clock     = std::chrono::high_resolution_clock;
  using TimePoint = Clock::time_point;
  using Duration  = std::chrono::milliseconds;

  public:
  virtual ~ITimer()                        = default;     // Default destructor
  ITimer(const ITimer &obj)                = default;     // Copy constructor
  ITimer(ITimer &&obj) noexcept            = default;     // Move constructor
  ITimer &operator=(const ITimer &obj)     = default;     // Copy assignment operator
  ITimer &operator=(ITimer &&obj) noexcept = default;     // Move assignment operator

  /**
   * @brief Resets the reference time point to the current time.
   */
  void reset();

  /**
   * @brief Returns the current time point.
   * @return The current time point as defined by the derived class.
   */
  [[nodiscard]] virtual TimePoint now() const = 0;

  /**
   * @brief Returns the elapsed duration since the last reset.
   * @return Duration since the last reset.
   */
  [[nodiscard]] Duration getElapsed() const;

  /**
   * @brief Checks if the specified duration has elapsed since the last reset.
   * @param duration The duration to check.
   * @param autoReset If true, automatically resets the timer when the duration has elapsed.
   * @return True if the duration has elapsed, false otherwise.
   */
  [[nodiscard]] bool isElapsed(const Duration duration,
                               bool           autoReset = false);

  protected:
  ITimer() = default;     // Default constructor

  TimePoint m_t0;     // Timepoint t0 for elapsed time measurement
};
//--------------------------------------------------------------
/* Reset the timepoint t0 */
inline void ITimer::reset()
{
  m_t0 = now();
}
//--------------------------------------------------------------
/* Get the elapsed time */
inline ITimer::Duration ITimer::getElapsed() const
{
  return std::chrono::duration_cast<Duration>(now() - m_t0);
}
//--------------------------------------------------------------
/* Check if the specified delay has elapsed */
inline bool ITimer::isElapsed(const Duration duration, bool autoReset)
{
  Duration elapsed = getElapsed();
  if (elapsed >= duration)
  {
    if (autoReset)
      reset();
    return true;
  }

  return false;
}
//--------------------------------------------------------------
}     // namespace sdi_toolBox::dateTime
