// =====================================================================================================================
//  fennec, a free and open source game engine
//  Copyright © 2025 - 2026  Medusa Slockbower
//
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program.  If not, see <https://www.gnu.org/licenses/>.
// =====================================================================================================================

///
/// \file fennec/core/logger.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 - 2026 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///


#ifndef FENNEC_CORE_LOGGER_H
#define FENNEC_CORE_LOGGER_H

#include <fennec/containers/pair.h>
#include <fennec/filesystem/file.h>
#include <fennec/rtti/singleton.h>
#include <fennec/containers/tuple.h>
#include <fennec/lang/system.h>

namespace fennec
{

///
/// \brief logger class
class logger : public singleton<logger> {

// Definitions =========================================================================================================
public:

	///
	/// \brief Log Severities
	enum severity : uint32_t {
		info = 0,
		alert,
		warning,
		error,
		fatal,
	};

	static const pair<cstring, cstring>& severity_color(uint32_t severity) {
		static constexpr pair<cstring, cstring> colors[] = {
			{ "\033[0m",    "\033[0m" }, // severity_info
			{ "\033[36m",   "\033[0m" }, // severity_alert
			{ "\033[33m",   "\033[0m" }, // severity_warning
			{ "\033[31m",   "\033[0m" }, // severity_error
			{ "\033[1;31m", "\033[0m" }, // severity_fatal
		};
		return colors[severity];
	}


// Logger System Interface =============================================================================================
public:

	/// \name System Interface
	/// @{

	///
	/// \brief Log a string to the log file and cout
	/// \param str the string to log
	/// \param _line the line of the log call
	/// \param _file the file log was called in
	static void log(uint32_t severity,
	                const cstring& str,
	                uint32_t _line = FENNEC_BUILTIN_LINE(),
	                const char* _file = FENNEC_BUILTIN_FILE()
	) {
		logger& inst = instance();

		if (inst._logfile.is_open()) {
			inst._logfile.print(cstring(_file, strlen(_file)));
			inst._logfile.printf("({}): ", _line);
			inst._logfile.println(str);
		}

		const auto& color = severity_color(severity);
		inst._cout->print(color.first);
		inst._cout->print(cstring(_file, strlen(_file)));
		inst._cout->printf("({}): ", _line);
		inst._cout->print(str);
		inst._cout->println(color.second);
	}

	///
	/// \brief Log a string to the log file and cout
	/// \param str the string to log
	/// \param _line the line of the log call
	/// \param _file the file log was called in
	static void log(uint32_t severity,
	                const string& str,
		uint32_t _line = FENNEC_BUILTIN_LINE(),
		const char* _file = FENNEC_BUILTIN_FILE()
	) {
		logger& inst = instance();

		if (inst._logfile.is_open()) {
			inst._logfile.print(cstring(_file, strlen(_file)));
			inst._logfile.printf("({}): ", _line);
			inst._logfile.println(str);
		}


		const auto& color = severity_color(severity);
		inst._cout->print(color.first);
		inst._cout->print(cstring(_file, strlen(_file)));
		inst._cout->printf("({}): ", _line);
		inst._cout->print(str);
		inst._cout->println(color.second);
	}

	/// @}


// Private Member Variables ============================================================================================
private:
	file  _logfile;
	file* _cout;


// Private Constructors & Destructor ===================================================================================
private:
	logger();
	~logger();

	friend struct singleton;
};

}

#endif // FENNEC_CORE_LOGGER_H