// SPDX-License-Identifier: Apache-2.0
// Copyright 2023 Pionix GmbH and Contributors to EVerest
#pragma once

#include <chrono>

namespace iso15118 {

using TimePoint = std::chrono::steady_clock::time_point;

inline TimePoint get_current_time_point() {
    return std::chrono::steady_clock::now();
}

inline TimePoint offset_time_point_by_ms(const TimePoint& time_point, int32_t offset) {
    return time_point + std::chrono::milliseconds(offset);
}

inline int32_t get_timeout_ms_until(const TimePoint& until, int32_t max_timeout_ms) {
    const auto duration =
        std::chrono::duration_cast<std::chrono::duration<int32_t, std::milli>>(until - get_current_time_point());
    const auto timeout_ms = duration.count();

    // if the timeout is already reached, return 0 to trigger an immediate timeout event
    if (timeout_ms <= 0) {
        return 0;
    }

    return timeout_ms < max_timeout_ms ? timeout_ms : max_timeout_ms;
}

class Timeout {
public:
    explicit Timeout(uint32_t timeout_ms) {
        timeout_point = get_current_time_point() + std::chrono::milliseconds(timeout_ms);
    };
    ~Timeout() = default;

    bool is_reached() {
        return get_current_time_point() >= timeout_point;
    }

    TimePoint get_timeout_point() const {
        return timeout_point;
    }

private:
    TimePoint timeout_point{};
};

} // namespace iso15118
