/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
 */

#pragma once

#include <stdint.h>

namespace OpenVulkano::Math
{
	class Timestamp final
	{
		static constexpr uint64_t SECONDS_TO_NANOS = 1'000'000'000ull;
		static constexpr double NANOS_TO_SECONDS = 1.0 / SECONDS_TO_NANOS;

		uint64_t timestamp;

	public:
		explicit Timestamp(uint64_t nanos = 0) : timestamp(nanos) {}
		explicit Timestamp(double seconds) : timestamp(static_cast<uint64_t>(seconds * SECONDS_TO_NANOS)) {}

		[[nodiscard]] uint64_t GetNanos() const { return timestamp; }
		[[nodiscard]] double GetSeconds() const { return timestamp * NANOS_TO_SECONDS; }

		Timestamp& operator+=(const Timestamp& rhs)
		{
			timestamp += rhs.timestamp;
			return *this;
		}

		Timestamp& operator-=(const Timestamp& rhs)
		{
			timestamp -= rhs.timestamp;
			return *this;
		}

		Timestamp& operator =(double time)
		{
			timestamp = Timestamp(time).timestamp;
			return *this;
		}

		Timestamp& operator =(uint64_t time)
		{
			timestamp = time;
			return *this;
		}
	};

	inline bool operator==(const Timestamp& lhs, const Timestamp& rhs)
	{
		return lhs.GetNanos() == rhs.GetNanos();
	}

	inline bool operator!=(const Timestamp& lhs, const Timestamp& rhs)
	{
		return !(lhs == rhs);
	}

	inline bool operator<(const Timestamp& lhs, const Timestamp& rhs)
	{
		return lhs.GetNanos() < rhs.GetNanos();
	}

	inline bool operator>(const Timestamp& lhs, const Timestamp& rhs)
	{
		return rhs < lhs;
	}

	inline bool operator>=(const Timestamp& lhs, const Timestamp& rhs)
	{
		return !(lhs < rhs);
	}

	inline bool operator<=(const Timestamp& lhs, const Timestamp& rhs)
	{
		return !(rhs < lhs);
	}

	inline Timestamp operator-(const Timestamp& lhs, const Timestamp& rhs)
	{
		return Timestamp(lhs.GetNanos() - rhs.GetNanos());
	}

	inline Timestamp operator+(const Timestamp& lhs, const Timestamp& rhs)
	{
		return Timestamp(lhs.GetNanos() + rhs.GetNanos());
	}

	inline double operator/(const Timestamp& lhs, const Timestamp& rhs)
	{
		return lhs.GetNanos() / static_cast<double>(rhs.GetNanos());
	}
}