#pragma once

#include <psemek/ecs/detail/id.hpp>

#include <iostream>
#include <format>

namespace psemek::ecs
{

	struct handle
	{
		detail::entity_id id;
		detail::entity_epoch epoch;

		friend bool operator == (handle const &, handle const &) = default;
		friend auto operator <=> (handle const &, handle const &) = default;

		static handle null()
		{
			return {-1, -1};
		}

		explicit operator bool() const
		{
			return (*this) != null();
		}
	};

	inline std::ostream & operator << (std::ostream & out, handle const & handle)
	{
		out << '(' << handle.id << ',' << handle.epoch << ')';
		return out;
	}

}

namespace std
{

	template <>
	struct hash<::psemek::ecs::handle>
	{
		uint64_t operator()(::psemek::ecs::handle const & h) const noexcept
		{
			return (static_cast<uint64_t>(h.id) << 32) | h.epoch;
		}
	};

	template <typename Char>
	struct formatter<::psemek::ecs::handle, Char>
	{
		constexpr auto parse(std::format_parse_context & ctx)
		{
			return ctx.begin();
		}

		auto format(::psemek::ecs::handle const & handle, std::format_context & ctx) const
		{
			return std::format_to(ctx.out(), "({},{})", handle.id, handle.epoch);
		}
	};

}
