import logging
import sys
import traceback
from logging.handlers import RotatingFileHandler

try:
	from typing import TypeAlias
except ImportError:
	from typing_extensions import TypeAlias  # noqa: F401

from tools.options import Options

LoggingLevel: TypeAlias = int

LEVEL_TO_OPTION_MAP = {
	logging.DEBUG: Options.Option.LOG_DEBUG,
	logging.INFO: Options.Option.LOG_INFO,
	logging.WARNING: Options.Option.LOG_WARNING,
	logging.ERROR: Options.Option.LOG_ERROR,
	logging.CRITICAL: Options.Option.LOG_CRITICAL,
}


def get_logging_level() -> LoggingLevel:
	"""
	Determines the appropriate logging level based on enabled options.

	This function checks which logging level options are enabled in the Options
	system and returns the most verbose (lowest) enabled level. The levels are
	checked in ascending order of severity: DEBUG, INFO, WARNING, ERROR, CRITICAL.

	Returns:
		LoggingLevel: The most verbose enabled logging level.
						If no specific level is enabled, defaults to WARNING.
	"""

	for logging_level in sorted(LEVEL_TO_OPTION_MAP.keys()):
		logging_level_name = LEVEL_TO_OPTION_MAP[logging_level]

		if Options.is_enabled(logging_level_name):
			return logging_level

	return logging.WARNING


def init_logger():
	"""
	Initializes the application's logging system.

	This function sets up a rotating file logger that writes to "monpage.log",
	configures the logging format, and sets the appropriate logging level
	based on the enabled options. It also installs an exception hook to
	ensure that uncaught exceptions are logged before the program terminates.

	The log files will rotate when they reach 5MB in size, keeping up to 5 backup files.
	"""

	log_filename = "monpage.log"
	logging.basicConfig(
		handlers=[
			RotatingFileHandler(
				log_filename, maxBytes=5000 * 1024, backupCount=5, encoding="utf-8"
			)
		],
		level=get_logging_level(),
		format="%(asctime)s - %(levelname)s[%(name)s]: %(message)s",
		datefmt="%Y-%m-%d %H:%M:%S",
	)

	# log uncaught exceptions
	def log_exceptions(type, value, tb):
		logging.exception(
			"Uncaught exception:\n"
			+ "".join(traceback.format_exception(type, value, tb))
		)

		sys.__excepthook__(type, value, tb)  # calls default excepthook

	sys.excepthook = log_exceptions
