# encoding=utf-8
"""
Script exécutable pour lancer soit la fenêtre Cotation, soit la fenêtre Passation.
"""

__author__ = "Roland Trouville"
__copyright__ = "Copyright 2015+, Consortium MonPaGe"
__license__ = "Creative Commons 4.0 By-Nc-Sa"
__maintainer__ = "Roland Trouville"
__email__ = "contact.monpage@gmail.com"
__status__ = "Production"

from tools.environment_tools import EnvironmentTools
from tools.package_installer import PackageManager

EnvironmentTools.check_environment()
if not PackageManager().check_all_packages_installed():
	print("Nous allons tenter de procéder à l'installation des librairies manquantes")
	PackageManager().install_packages()

import locale  # noqa: E402
import logging  # noqa: E402
import os  # noqa: E402
import sys  # noqa: E402
from logging import getLevelName  # noqa: E402

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

from PySide6 import QtWidgets  # noqa: E402
from PySide6.QtCore import QCoreApplication, Qt  # noqa: E402

from tools.logger import (  # noqa: E402
	LEVEL_TO_OPTION_MAP,
	get_logging_level,
	init_logger,
)
from tools.options import Options  # noqa: E402
from ui.LoadedWindow import LoadedWindow  # noqa: E402

QCoreApplication.setAttribute(Qt.ApplicationAttribute.AA_ShareOpenGLContexts)
QCoreApplication.setAttribute(Qt.ApplicationAttribute.AA_DontUseNativeMenuBar)
app = QtWidgets.QApplication(sys.argv)
logger = logging.getLogger(__name__)


class SplashWindow(LoadedWindow):
	logging_level_option: Options.Option

	radio_button_debug: QtWidgets.QRadioButton
	radio_button_info: QtWidgets.QRadioButton
	radio_button_warning: QtWidgets.QRadioButton
	radio_button_error: QtWidgets.QRadioButton
	radio_button_critical: QtWidgets.QRadioButton

	def __init__(self):
		super().__init__(os.path.join("ui", "monpage_splash.ui"))

		self.setWindowTitle(
			f"MonPaGe Accueil"
		)

		self.radio_button_debug: QtWidgets.QRadioButton = self.find_element(
			QtWidgets.QRadioButton, "radioButton_1"
		)
		self.radio_button_debug.toggled.connect(
			lambda checked: self.on_log_level_change(checked, logging.DEBUG)
		)
		self.radio_button_info: QtWidgets.QRadioButton = self.find_element(
			QtWidgets.QRadioButton, "radioButton_2"
		)
		self.radio_button_info.toggled.connect(
			lambda checked: self.on_log_level_change(checked, logging.INFO)
		)
		self.radio_button_warning: QtWidgets.QRadioButton = self.find_element(
			QtWidgets.QRadioButton, "radioButton_3"
		)
		self.radio_button_warning.toggled.connect(
			lambda checked: self.on_log_level_change(checked, logging.WARNING)
		)
		self.radio_button_error: QtWidgets.QRadioButton = self.find_element(
			QtWidgets.QRadioButton, "radioButton_4"
		)
		self.radio_button_error.toggled.connect(
			lambda checked: self.on_log_level_change(checked, logging.ERROR)
		)
		self.radio_button_critical: QtWidgets.QRadioButton = self.find_element(
			QtWidgets.QRadioButton, "radioButton_5"
		)
		self.radio_button_critical.toggled.connect(
			lambda checked: self.on_log_level_change(checked, logging.CRITICAL)
		)

		self.logging_level_option = LEVEL_TO_OPTION_MAP[get_logging_level()]
		self.init_radio_buttons_of_log()

		self.passationWindow = None
		self.cotationWindow = None

	def init_radio_buttons_of_log(self):
		"""
		Initialize radio buttons for logging levels based on predefined mappings.

		Sets the text of each radio button to the capitalized log level name and marks
		the radio button corresponding to the current logging level option as checked.
		Handles potential file save errors silently.

		No parameters.

		Raises:
			ValueError: If a corresponding radio button for a log level is not found.
		"""
		for i, (level, option) in enumerate(LEVEL_TO_OPTION_MAP.items(), 1):
			level_name = getLevelName(level).capitalize()

			if level == logging.DEBUG:
				radio_button = self.radio_button_debug
			elif level == logging.INFO:
				radio_button = self.radio_button_info
			elif level == logging.WARNING:
				radio_button = self.radio_button_warning
			elif level == logging.ERROR:
				radio_button = self.radio_button_error
			elif level == logging.CRITICAL:
				radio_button = self.radio_button_critical
			else:
				raise ValueError("Radio button not found")

			radio_button.setText(level_name)
			if option == self.logging_level_option:
				try:
					Options.set_option(option, True, save=True)
				except FileExistsError:
					pass

				radio_button.setChecked(True)

	@staticmethod
	def on_log_level_change(checked: bool, level: int):
		"""
		Handle changes to the log level radio buttons.

		If a radio button is unchecked, removes the corresponding option file.
		If checked, sets the option and saves it, handling file existence errors gracefully.

		Args:
			checked (bool): Whether the radio button is checked.
			level (int): The logging level associated with the radio button.
		"""
		option = LEVEL_TO_OPTION_MAP.get(level)

		if option:
			if not checked:
				# Remove the old option
				path = Options.get_full_option_path(option, True)

				try:
					os.remove(path)
				except FileNotFoundError:
					pass
			else:
				# Set the new one
				try:
					Options.set_option(option, checked, save=True)
				except FileExistsError:
					pass

	@override
	def setup(self):
		"""
		Set up UI elements and connect button signals to their respective handlers.

		Finds the 'passationBtn' and 'cotationBtn' buttons and connects their clicked signals
		to the `launch_passation` and `launch_cotation` methods, respectively.

		No parameters or return value.
		"""
		passation_button: QtWidgets.QPushButton = self.find_element(
			QtWidgets.QPushButton, "passationBtn"
		)

		passation_button.clicked.connect(self.launch_passation)

		cotation_button: QtWidgets.QPushButton = self.find_element(
			QtWidgets.QPushButton, "cotationBtn"
		)

		cotation_button.clicked.connect(self.launch_cotation)

	def launch_window(self, window: QtWidgets.QMainWindow):
		"""
		Hide the current window and show the specified window.

		Args:
			window (QtWidgets.QMainWindow): The window instance to be shown.
		"""
		self.hide()
		window.show()

	def launch_passation(self):
		"""
		Launch the Passation main window.

		Imports and initializes the PassationMainWindow if it hasn't been created yet,
		then displays it using launch_window.
		"""
		from passation.passation_main_window import PassationMainWindow

		if self.passationWindow is None:
			self.passationWindow = PassationMainWindow(self)

		self.launch_window(self.passationWindow)

	def launch_cotation(self):
		"""
		Launch the Cotation main window.

		Imports and initializes the CotationMainWindow if it hasn't been created yet,
		then displays it using launch_window.
		"""
		from cotation.cotation_main_window import CotationMainWindow

		if self.cotationWindow is None:
			self.cotationWindow = CotationMainWindow(self)

		self.launch_window(self.cotationWindow)


if __name__ == "__main__":
	init_logger()

	from tools.display_tools import DisplayTools
	from tools.options import Options
	from tools.preferences_tools import PreferencesTools

	try:
		Options.set_base_dir(os.path.dirname(__file__))
		Options.check_options()

		logger.info(
			f"version: {sys.version} | prefered encoding: {locale.getpreferredencoding()}"
		)

		PreferencesTools.load_preferences_config()
		DisplayTools.calculate_maximum_possible_resolution()
		DisplayTools.load_display_config(10)

		splash_window = SplashWindow()
		splash_window.show()
		return_code = app.exec()

		try:
			DisplayTools.save_display_config()
			PreferencesTools.save_preferences_config()
		except Exception as e:
			logger.error(f"Error saving preferences: {e}")

		sys.exit(return_code)
	except Exception as e:
		logger.error(f"Error initializing main window: {e}")
		sys.exit(-1)
