# encoding=utf-8
"""
File for the ModuleWindow class
"""

__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"

import logging
import math
import os
from datetime import datetime

from PySide6.QtCore import QSize, Qt
from PySide6.QtGui import QKeySequence, QShortcut
from PySide6.QtWidgets import (
	QApplication,
	QGroupBox,
	QLabel,
	QProgressBar,
	QPushButton,
	QWidget,
)

from tools.audio_manager import AudioManager
from tools.display_tools import DisplayTools
from tools.general_tools import GeneralTools
from tools.options import Options
from tools.participant_manager import ParticipantManager
from ui.MainWindow import MainWindow

logger = logging.getLogger(__name__)


class ModuleWindow(QWidget):
	"""
	Window used to display a module
	"""

	parent: MainWindow
	btn_quit: QPushButton
	btn_start: QPushButton
	btn_next: QPushButton
	btn_record: QPushButton
	btn_stop: QPushButton
	btn_restart: QPushButton
	text_display: QLabel
	items = []
	current_module_index = 0
	module_name: str
	participant_code: str
	progress_bar: QProgressBar
	progress_bar_label: QLabel

	option_group = None

	accent = None

	btn_next_icons = []
	btn_quit_icons = []
	btn_record_icons = []
	btn_stop_icons = []
	btn_restart_icons = []

	btn_quit_shortcuts = []
	btn_stop_shortcuts = []
	btn_record_shortcuts = []
	btn_next_shortcuts = []

	session_path = None
	session_affix = ""

	def __init__(
		self, parent: MainWindow, participant_code, module_name, accent, items
	):
		super(ModuleWindow, self).__init__()
		self.items = items
		self.accent = accent
		self.module_name = module_name
		AudioManager.init()
		self.parent = parent
		self.participant_code = participant_code
		ParticipantManager.set_current_participant(participant_code)

		self.session_date = (
			("%02d" % datetime.now().year)
			+ "_"
			+ ("%02d" % datetime.now().month)
			+ "_"
			+ ("%02d" % datetime.now().day)
		)
		self.init_ui()
		self.display_buttons("init")

	def prepare_directory(self):
		"""
		Create a directory for this session of module for the participant
		:return:
		"""
		ParticipantManager.start_session(self.module_name)

	def init_ui(self):
		"""
		Initialize the ui for the ModuleWindow
		:return: None
		"""
		self.setGeometry(80, 80, 800, 600)
		self.setWindowTitle("MonPaGe Passation")

		self.btn_quit_icons = DisplayTools.prepare_icons("./ui/icons/btn_quit.png")
		self.btn_next_icons = DisplayTools.prepare_icons("./ui/icons/btn_next.png")
		self.btn_record_icons = DisplayTools.prepare_icons("./ui/icons/btn_record.png")
		self.btn_stop_icons = DisplayTools.prepare_icons("./ui/icons/btn_stop.png")
		self.btn_restart_icons = DisplayTools.prepare_icons(
			"./ui/icons/btn_restart.png"
		)

		self.option_group = QGroupBox("", self)
		self.option_group.resize(600, 100)
		self.option_group.setAutoFillBackground(True)
		self.option_group.setPalette(self.parent.display_palette)

		self.btn_quit = QPushButton("", self.option_group)
		self.btn_quit.setIcon(self.btn_quit_icons[0])
		self.btn_quit.setIconSize(QSize(45, 45))
		self.btn_quit.resize(50, 50)
		self.btn_quit.clicked.connect(self.end_module)

		self.btn_next = QPushButton("", self.option_group)
		self.btn_next.setIcon(self.btn_next_icons[0])
		self.btn_next.setIconSize(QSize(45, 45))
		self.btn_next.resize(50, 50)
		self.btn_next.clicked.connect(self.next_module_item)

		self.btn_start = QPushButton("DEMARRER", self.option_group)
		self.btn_start.resize(200, 50)
		self.btn_start.clicked.connect(self.start_module)

		self.btn_record = QPushButton("", self.option_group)
		self.btn_record.setIcon(self.btn_record_icons[0])
		self.btn_record.setIconSize(QSize(45, 45))
		self.btn_record.resize(50, 50)
		self.btn_record.clicked.connect(self.start_recording_btn)

		self.btn_stop = QPushButton("", self.option_group)
		self.btn_stop.setIcon(self.btn_stop_icons[0])
		self.btn_stop.setIconSize(QSize(45, 45))
		self.btn_stop.resize(50, 50)
		self.btn_stop.clicked.connect(self.stop_recording)

		self.btn_restart = QPushButton("", self.option_group)
		self.btn_restart.setIcon(self.btn_restart_icons[0])
		self.btn_restart.setIconSize(QSize(45, 45))
		self.btn_restart.resize(50, 50)
		self.btn_restart.clicked.connect(self.restart_current_module_item)

		self.text_display = QLabel(self)
		self.text_display.setWordWrap(True)

		self.setPalette(self.parent.display_palette)

		self.progress_bar = QProgressBar(self.option_group)
		self.progress_bar.setMinimum(0)
		self.progress_bar.setMaximum(20)
		self.progress_bar.setValue(0)
		self.progress_bar.resize(520, 20)
		self.progress_bar.setTextVisible(False)
		self.progress_bar.raise_()

		self.progress_bar_label = QLabel("", self.option_group)
		self.progress_bar_label.resize(60, 20)
		self.progress_bar_label.setPalette(self.parent.display_palette)
		DisplayTools.set_font_size(self.progress_bar_label, "lab_module_progress_bar")

		self.showFullScreen()

		height = self.height()
		width = self.width()
		margin = round((width - 600) / 2)

		self.option_group.move(margin, height - 150)
		self.progress_bar.move(5, 15)
		self.progress_bar_label.move(530, 15)
		self.btn_quit.move(5, 40)
		self.btn_start.move(200, 40)
		self.btn_next.move(545, 40)
		self.btn_restart.move(200, 40)
		self.btn_stop.move(245, 40)
		self.btn_record.move(305, 40)

		text_margin = math.floor(width / 20.0)

		self.text_display.resize(width - (text_margin * 2), height - 160)
		self.text_display.move(text_margin, 0)
		self.text_display.setAlignment(Qt.AlignmentFlag.AlignCenter)
		self.text_display.setFont(self.parent.display_font)

		start_image = "./data/module/" + self.module_name + "/StartScreen.png"
		if os.path.isfile(start_image):
			DisplayTools.display_image(self.text_display, start_image)

		self.init_shortcuts()

	def init_shortcuts(self):
		"""
		Creates the navigation shortcuts
		:return: None
		"""

		self.btn_quit_shortcuts = [QShortcut(QKeySequence(Qt.Key.Key_Escape), self)]
		for short in self.btn_quit_shortcuts:
			short.activated.connect(self.end_module)
			short.setEnabled(False)
		self.btn_next_shortcuts = [
			QShortcut(QKeySequence(Qt.Key.Key_Space), self),
			QShortcut(QKeySequence(Qt.Key.Key_Right), self),
		]
		for short in self.btn_next_shortcuts:
			short.activated.connect(self.next_module_item)
			short.setEnabled(False)
		self.btn_record_shortcuts = [
			QShortcut(QKeySequence(Qt.Key.Key_Enter), self),
			QShortcut(QKeySequence(Qt.Key.Key_Return), self),
			QShortcut(QKeySequence(Qt.Key.Key_Tab), self),
		]
		for short in self.btn_record_shortcuts:
			short.activated.connect(self.start_recording_btn)
			short.setEnabled(False)
		self.btn_stop_shortcuts = [
			QShortcut(QKeySequence(Qt.Key.Key_Enter), self),
			QShortcut(QKeySequence(Qt.Key.Key_Return), self),
			QShortcut(QKeySequence(Qt.Key.Key_Tab), self),
		]
		for short in self.btn_stop_shortcuts:
			short.activated.connect(self.stop_recording)
			short.setEnabled(False)

	def display_buttons(self, mode):
		"""
		Decides which buttons to show or hide based on which sequence of the module we are in
		:param mode: sequence of the module
		:return: None
		"""
		if mode == "next":
			self.btn_next.setVisible(True)
			self.btn_start.setVisible(False)
			self.btn_record.setVisible(True)
			self.btn_stop.setVisible(True)
			self.btn_restart.setVisible(True)
			self.btn_quit.setVisible(True)
			self.btn_next.setEnabled(True)
			for short in self.btn_next_shortcuts:
				short.setEnabled(True)
			self.btn_next.setIcon(self.btn_next_icons[0])
			self.btn_start.setEnabled(False)
			self.btn_record.setEnabled(True)
			for short in self.btn_record_shortcuts:
				short.setEnabled(True)
			self.btn_record.setIcon(self.btn_record_icons[0])
			self.btn_stop.setEnabled(False)
			self.btn_restart.setEnabled(False)
			for short in self.btn_stop_shortcuts:
				short.setEnabled(False)
			self.btn_stop.setIcon(self.btn_stop_icons[1])
			self.btn_restart.setIcon(self.btn_restart_icons[1])
			self.btn_quit.setEnabled(True)
			for short in self.btn_quit_shortcuts:
				short.setEnabled(True)
		elif mode == "consigne":
			self.btn_next.setVisible(True)
			self.btn_start.setVisible(False)
			self.btn_record.setVisible(True)
			self.btn_stop.setVisible(True)
			self.btn_restart.setVisible(True)
			self.btn_quit.setVisible(True)
			self.btn_next.setEnabled(True)
			for short in self.btn_next_shortcuts:
				short.setEnabled(True)
			self.btn_next.setIcon(self.btn_next_icons[0])
			self.btn_start.setEnabled(False)
			self.btn_record.setEnabled(False)
			for short in self.btn_record_shortcuts:
				short.setEnabled(False)
			self.btn_record.setIcon(self.btn_record_icons[1])
			self.btn_stop.setEnabled(False)
			self.btn_restart.setEnabled(False)
			for short in self.btn_stop_shortcuts:
				short.setEnabled(False)
			self.btn_stop.setIcon(self.btn_stop_icons[1])
			self.btn_restart.setIcon(self.btn_restart_icons[1])
			self.btn_quit.setEnabled(True)
			for short in self.btn_quit_shortcuts:
				short.setEnabled(True)
		elif mode == "record":
			self.btn_next.setVisible(True)
			self.btn_start.setVisible(False)
			self.btn_record.setVisible(True)
			self.btn_stop.setVisible(True)
			self.btn_restart.setVisible(True)
			self.btn_quit.setVisible(True)
			self.btn_next.setEnabled(True)
			for short in self.btn_next_shortcuts:
				short.setEnabled(True)
			self.btn_next.setIcon(self.btn_next_icons[0])
			self.btn_start.setEnabled(False)
			self.btn_record.setEnabled(False)
			for short in self.btn_record_shortcuts:
				short.setEnabled(False)
			self.btn_record.setIcon(self.btn_record_icons[1])
			self.btn_stop.setEnabled(True)
			self.btn_restart.setEnabled(True)
			for short in self.btn_stop_shortcuts:
				short.setEnabled(True)
			self.btn_stop.setIcon(self.btn_stop_icons[0])
			self.btn_restart.setIcon(self.btn_restart_icons[0])
			self.btn_quit.setEnabled(True)
			for short in self.btn_quit_shortcuts:
				short.setEnabled(True)
		elif mode == "longrecord":
			self.btn_next.setVisible(True)
			self.btn_start.setVisible(False)
			self.btn_record.setVisible(False)
			self.btn_stop.setVisible(False)
			self.btn_restart.setVisible(False)
			self.btn_quit.setVisible(True)
			self.btn_next.setEnabled(True)
			for short in self.btn_next_shortcuts:
				short.setEnabled(True)
			self.btn_next.setIcon(self.btn_next_icons[0])
			self.btn_start.setEnabled(False)
			self.btn_record.setEnabled(False)
			for short in self.btn_record_shortcuts:
				short.setEnabled(False)
			self.btn_record.setIcon(self.btn_record_icons[1])
			self.btn_stop.setEnabled(False)
			self.btn_restart.setEnabled(False)
			for short in self.btn_stop_shortcuts:
				short.setEnabled(False)
			self.btn_stop.setIcon(self.btn_stop_icons[1])
			self.btn_restart.setIcon(self.btn_restart_icons[1])
			self.btn_quit.setEnabled(True)
			for short in self.btn_quit_shortcuts:
				short.setEnabled(True)
		elif mode == "stop":
			self.btn_next.setVisible(True)
			self.btn_start.setVisible(False)
			self.btn_record.setVisible(True)
			self.btn_stop.setVisible(True)
			self.btn_restart.setVisible(True)
			self.btn_quit.setVisible(True)
			self.btn_next.setEnabled(True)
			for short in self.btn_next_shortcuts:
				short.setEnabled(True)
			self.btn_next.setIcon(self.btn_next_icons[0])
			self.btn_start.setEnabled(False)
			self.btn_record.setEnabled(True)
			for short in self.btn_record_shortcuts:
				short.setEnabled(True)
			self.btn_record.setIcon(self.btn_record_icons[0])
			self.btn_stop.setEnabled(False)
			self.btn_restart.setEnabled(True)
			for short in self.btn_stop_shortcuts:
				short.setEnabled(False)
			self.btn_stop.setIcon(self.btn_stop_icons[1])
			self.btn_restart.setIcon(self.btn_restart_icons[0])
			self.btn_quit.setEnabled(True)
			for short in self.btn_quit_shortcuts:
				short.setEnabled(True)
		else:
			self.btn_next.setVisible(False)
			self.btn_start.setVisible(True)
			self.btn_record.setVisible(False)
			self.btn_restart.setVisible(False)
			self.btn_stop.setVisible(False)
			self.btn_quit.setVisible(True)
			self.btn_next.setEnabled(False)
			for short in self.btn_next_shortcuts:
				short.setEnabled(False)
			self.btn_next.setIcon(self.btn_next_icons[1])
			self.btn_start.setEnabled(True)
			self.btn_record.setEnabled(False)
			for short in self.btn_record_shortcuts:
				short.setEnabled(False)
			self.btn_record.setIcon(self.btn_record_icons[1])
			self.btn_stop.setEnabled(False)
			for short in self.btn_stop_shortcuts:
				short.setEnabled(False)
			self.btn_stop.setIcon(self.btn_stop_icons[1])
			self.btn_restart.setIcon(self.btn_restart_icons[1])
			self.btn_quit.setEnabled(True)
			for short in self.btn_quit_shortcuts:
				short.setEnabled(True)

	def start_recording_btn(self):
		"""
		Handle the start recording button click.

		Stops any ongoing audio recording and starts a new recording session.
		"""
		AudioManager.stop()
		self.start_recording()

	def start_recording(self):
		"""
		Start recording microphone input to file
		:return: None
		"""
		to_record = self.items[self.current_module_index]
		duration = float(to_record[5].replace(",", "."))

		if to_record[0] in ("s", "p"):
			if duration >= 300:
				self.display_buttons("longrecord")
			else:
				self.display_buttons("record")
			# filenames = [
			# 	self.session_path + self.participant_code + "_" + self.session_date + "_" + self.session_affix +
			# 	self.module_name + "_" + to_record[4].strip() + ".wav"]
			filenames = [
				ParticipantManager.full_session_path
				+ ParticipantManager.filename_prefix
				+ to_record[4].strip()
				+ ".wav"
			]

			i = 7
			while i < len(to_record):
				if to_record[i] != "":
					filenames.append(
						ParticipantManager.full_session_path
						+ ParticipantManager.filename_prefix
						+ to_record[i].strip()
						+ ".wav"
					)
				else:
					break
				i += 1

			simultaneous_playback_file = None
			if to_record[0] == "p" and to_record[1] != "":
				# we have a playback wave we want to play while we record
				# v2.0.0 no longer supported
				simultaneous_playback_file = (
					"./data/module/" + self.module_name + "/" + to_record[1]
				)

			try:
				lab = self.progress_bar_label
				if simultaneous_playback_file is not None:
					lab = None
				AudioManager.record_wave(
					filenames,
					duration,
					self.progress_bar,
					lab,
					self.option_group,
					simultaneous_playback_file,
				)

			except Exception as e:
				GeneralTools.alert_box(self, repr(e))

	def stop_recording(self):
		"""
		Stop recording microphone input
		:return: None
		"""
		AudioManager.stop()
		self.display_buttons("stop")

	def start_module(self):
		"""
		Initialize module then calling next_module_item() to display first item
		:return:
		"""
		self.prepare_directory()
		self.current_module_index = 0
		self.next_module_item()

	def next_module_item(self):
		"""
		Advance to the next module item in the session.

		Stops any ongoing audio recording based on the type of the current item (e.g., "s", "p", or "c" with non-empty content),
		then increments the current module index and loads the corresponding item.
		"""
		if self.current_module_index < len(self.items) and self.items[
			self.current_module_index
		][0] in ("s", "p"):
			AudioManager.stop()
		else:
			if (
				self.current_module_index < len(self.items)
				and self.items[self.current_module_index][0] == "c"
				and self.items[self.current_module_index][1] != ""
			):
				AudioManager.stop()

		self.current_module_index += 1
		self.current_module_item()

	def restart_current_module_item(self):
		"""
		Restarts the current module item.

		Stops the ongoing recording and reloads the current item to allow reprocessing or re-recording.
		"""
		self.stop_recording()
		self.current_module_item()

	def current_module_item(self):
		"""
		Display current item in the module. It can be a text, an image, play a wave, and it can warrant recording or not
		:return: None
		"""
		self.setPalette(self.parent.display_palette)
		AudioManager.stop()

		try:
			to_play = self.items[self.current_module_index]
			img = str(to_play[2])
			if img != "":
				DisplayTools.display_image(
					self.text_display, "./data/module/" + self.module_name + "/" + img
				)
			else:
				self.text_display.setText(str(to_play[3]).replace("-NL-", "\n"))
				DisplayTools.set_font_size(
					self.text_display, None, True, self.parent.display_font.pointSize()
				)

			self.text_display.show()
			self.progress_bar.reset()
			self.progress_bar.setValue(0)
			self.progress_bar_label.setText("")
			self.repaint()

			# Storing current index before starting to process application events, to check for overlap
			current_index = self.current_module_index

			# noinspection PyArgumentList
			QApplication.processEvents()
			if to_play[0] == "c":
				if current_index != self.current_module_index:
					return False
				self.display_buttons("consigne")

			if Options.is_enabled(Options.Option.SCREENS):
				DisplayTools.take_screenshot()

			if to_play[1] != "" and to_play[0] in ("c", "s"):
				# Test to avoid overlapping playing wave when skipping
				if current_index != self.current_module_index:
					return False
				try:
					AudioManager.play_accentuated_wave(
						"./data/module/" + self.module_name + "/",
						self.accent,
						to_play[1],
						None,
						None,
						None,
					)
				except ValueError as e:
					logger.error(e)
					GeneralTools.alert_box(self, e.args[0])
			# AudioManager.play_wave("./data/module/" + self.module_name + "/" + to_play[1], None, None)
			if to_play[0] in ("s", "p"):
				if int(to_play[6]) == 0:
					# Test to avoid overlapping recording when skipping
					if current_index != self.current_module_index:
						return False

					self.start_recording()
				else:
					if current_index != self.current_module_index:
						return False
					self.display_buttons("stop")

		except IndexError:
			self.end_module()

		return True

	def end_module(self):
		"""
		Ending module / quitting
		:return: None
		"""
		AudioManager.stop()
		self.parent.show()
		self.close()
