
#include "lualib.h"
#include "luax/luax.h"
#include "luax/impl/luaerror.h"

namespace Luax
{
	static Error sIntance;

	Error& Error::instance() { return sIntance; }

	void  Error::registerHandler(HandlerId id, ErrCallback&& errCallback)
	{
		EA::Thread::AutoFutex lock(mLock);

		EA_ASSERT_MSG(eastl::find_if(mHandlers.begin(), mHandlers.end(), [id](auto&& handler) { return handler.first == id; }) == mHandlers.end(), "Handler already registered.");
		mHandlers.emplace_back(id, errCallback);
	}

	void  Error::unregisterHandler(HandlerId id)
	{
		EA::Thread::AutoFutex lock(mLock);

		mHandlers.erase(eastl::remove_if(mHandlers.begin(), mHandlers.end(), [id](auto&& handler) { return handler.first == id; }), mHandlers.end());
	}

	void  Error::handle(lua_State* L) const
	{
		ErrMessage msg;
		if (!mContext.empty())
		{
			msg.append(mContext.back().data());
			msg.append(" : ");
		}

		getMsg(L, msg);

		sendError(msg);
	}

	void  Error::sendError(eastl::string_view err) const
	{
		EA::Thread::AutoFutex lock(mLock);

		for (auto& [id, func] : mHandlers)
		{
			func(err);
		}
	}

	void Error::getMsg(lua_State* L, ErrMessage& msg) const
	{
		msg = lua_tostring(L, -1);
		lua_pop(L, 1);
		// force complete garbage collection in case of error
		lua_gc(L, LUA_GCCOLLECT, 0);
	}

}