#pragma once

#include "luax/config.h"
#include <EASTL/fixed_string.h>
#include <EASTL/fixed_vector.h>
#include <EASTL/functional.h>
#include <EASTL/vector.h>
#include <eathread/eathread_futex.h>

struct lua_State;

namespace Luax
{
	class LUAX_API Error
	{
	public:

		struct ContextScope
		{
			ContextScope(eastl::string_view context)
			{
				instance().pushContext(context);
			}

			~ContextScope()
			{
				instance().popContext();
			}

			ContextScope(const ContextScope&) = delete;
			ContextScope(ContextScope&&) = delete;
		};

		using HandlerId = const void*;
		using ErrCallback = eastl::function<void(eastl::string_view)>;
		using ErrMessage = eastl::fixed_string<char, 256>;
		using Handlers = eastl::vector<eastl::pair<HandlerId, ErrCallback>>;

		static Error& instance();

		void  registerHandler(HandlerId id, ErrCallback&& errCallback);
		void  unregisterHandler(HandlerId id);

		void  handle(lua_State* L) const;
		void  sendError(eastl::string_view err) const;

		void  pushContext(eastl::string_view context) { mContext.push_back(context); }
		void  popContext() { mContext.pop_back(); }

	private:
		void  getMsg(lua_State* L, ErrMessage& message) const;

		mutable EA::Thread::Futex	mLock;
		Handlers					mHandlers;

		static const size_t			kMaxContexts = 5;
		using Contexts				= eastl::fixed_vector<eastl::string_view, kMaxContexts>;
		Contexts					mContext;

	};
}

#define Luax_SetContext(NAME) Luax::Error::ContextScope lua_err_context_scope{ NAME };