/*
 * Copyright 2015 - 2025 gary@drinkingtea.net
 *
 * 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/.
 */

#include <ox/std/fmt.hpp>
#include <ox/std/realstd.hpp>
#include <ox/std/stacktrace.hpp>
#include <ox/std/trace.hpp>

#include <ox/std/assert.hpp>

namespace ox {

void panic(Error const &err, StringViewCR panicMsg, std::source_location const &src) noexcept {
	oxErrf("\033[31;1;1mPANIC:\033[0m [{}:{}]: {}\n", src.file_name(), src.line(), panicMsg);
	if (err.msg) {
		oxErrf("\tError Message:\t{}\n", err.msg);
	}
	oxErrf("\tError Code:\t{}\n", static_cast<ErrorCode>(err));
	if (err.src.file_name() != nullptr) {
		oxErrf("\tError Location:\t{}:{}\n", err.src.file_name(), err.src.line());
	}
#ifdef OX_USE_STDLIB
	printStackTrace(2);
	oxTrace("panic").del("") << "Panic: " << panicMsg << " (" << src.file_name() << ":" << src.line() << ")";
	std::abort();
#else
	while (1);
#endif
}

#if __GNUC__ && !_WIN32
__attribute__((weak))
#endif
void panic(Error const &err, char const*panicMsg, std::source_location const &src) noexcept {
	panic(err, StringView{panicMsg}, src);
}

void assertFailFuncRuntime(
	StringViewCR assertTxt,
	StringViewCR msg,
	std::source_location const &src) noexcept {
#ifdef OX_USE_STDLIB
	auto const st = genStackTrace(2);
	oxTracef(
		"assert", "Failed assert: {} ({}) [{}:{}]:\n{}",
		msg,
		assertTxt,
		src.file_name(),
		src.line(),
		st);
	abort();
#else
	oxErrf(
		"\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n",
		src.file_name(),
		src.line(),
		msg);
	oxTracef(
		"assert", "Failed assert: {} ({}) [{}:{}]",
		msg,
		assertTxt,
		src.file_name(),
		src.line());
	constexprPanic(msg, {}, src);
#endif
}

void assertFailFuncRuntime(
	[[maybe_unused]] Error const &err,
	StringViewCR,
	StringViewCR assertMsg,
	std::source_location const &src) noexcept {
#if defined(OX_USE_STDLIB)
	auto msg = sfmt(
		"\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n",
		src.file_name(),
		src.line(),
		assertMsg);
	if (err.msg) {
		msg += sfmt("\tError Message:\t{}\n", err.msg);
	}
	msg += sfmt("\tError Code:\t{}\n", static_cast<ErrorCode>(err));
	if (err.src.file_name() != nullptr) {
		msg += sfmt("\tError Location:\t{}:{}\n", err.src.file_name(), err.src.line());
	}
	msg += genStackTrace(2);
	oxErr(msg);
	oxTracef("assert", "Failed assert: {} [{}:{}]", assertMsg, src.file_name(), src.line());
	abort();
#else
	constexprPanic(assertMsg, {}, src);
#endif
}

}
