# encoding=utf-8
"""
Used to import acoustical cotation results from a result file generated by Veronique Delvaux's praat script
It was used in MonPaGe prior to the 2.1 version where acoustical cotation is now embeded in the software.
The file was marked deprecated but not deleted for retro compatibility issues

This class is not intended to be used at all in the MonPaGe software as of now.

file for the CotationWindow top object
"""

__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 os
import re
from typing import Optional

from PySide6.QtCore import QDir
from PySide6.QtWidgets import (
	QFileDialog,
	QGroupBox,
	QLabel,
	QProgressBar,
	QPushButton,
	QWidget,
)

from tools.csv_manager import CSVManager
from tools.db_manager import DBManager
from tools.display_tools import DisplayTools
from tools.general_tools import GeneralTools
from tools.participant_manager import ParticipantManager
from tools.preferences_tools import PreferencesTools

logger = logging.getLogger(__name__)

logger.critical(
	"Deprecated 'PraatImportWindow'"
)  # La cotation acoustique est maintenant internalisée


class PraatImportWindow(QWidget):
	entry_file: QLabel
	cotation_db: DBManager
	result_dbs: dict[str, DBManager]
	pbar: QProgressBar
	files: dict[str, dict[str, str]] = {}

	def __init__(self, parent):
		super(PraatImportWindow, self).__init__()
		self.parent = parent
		self.init_result_dbs()
		self.init_ui()
		# self.load_file_list()
		# self.load_participant_list()
		# self.load_script_list()
		self.show()

	def init_ui(self):
		"""
		Initialize the UI
		:return: None
		"""
		self.setGeometry(80, 80, 600, 90)
		self.setFixedSize(600, 90)
		self.setWindowTitle("MonPaGe Import depuis Praat")
		# self.connect(self, QtCore.SIGNAL('triggered()'), self.closeEvent)

		gtmp = QGroupBox("Fichier à importer", self)
		gtmp.resize(580, 40)
		gtmp.move(10, 10)

		self.entry_file = QLabel("", gtmp)
		self.entry_file.resize(520, 20)
		self.entry_file.move(10, 10)
		# DisplayTools.set_font_size(self.output_dir, "lab_export_directory")

		tmp = QPushButton("...", gtmp)
		tmp.move(530, 10)
		tmp.resize(40, 20)
		tmp.setToolTip("Choisir le fichier à importer")
		DisplayTools.set_font_size(tmp, "lab_import_browsebtn")
		tmp.clicked.connect(self.change_entry_file)

		self.pbar = QProgressBar(self)
		self.pbar.setMinimum(0)
		self.pbar.setMaximum(20)
		self.pbar.setValue(0)
		self.pbar.resize(480, 20)
		self.pbar.setTextVisible(False)
		self.pbar.raise_()
		self.pbar.move(10, 60)

		tmp = QPushButton("Importer", self)
		tmp.move(500, 60)
		tmp.resize(90, 20)
		DisplayTools.set_font_size(tmp, "lab_import_gobtn")
		tmp.clicked.connect(self.import_from_praat)

	def init_result_dbs(self):
		"""
		Initialize the result databases for each participant.

		- Retrieves the list of participants.
		- Sets the current participant context.
		- Creates and stores a user-specific cotation database for each participant.
		"""
		self.result_dbs = {}
		tmp = DisplayTools.get_participant_list()
		self.cotation_db = DBManager.get_cotation_db()
		for d in tmp:
			dirname = d[0]
			ParticipantManager.set_current_participant(dirname)
			self.result_dbs[dirname] = self.cotation_db.create_user_cotation_db(
				ParticipantManager.cotation_db_filename
			)

	def change_entry_file(self):
		"""
		Opens a file dialog to allow the user to select a text file for import.

		Starts browsing from a preferred directory path saved in user preferences.
		If a file is selected, updates the entry field with the chosen filename and
		updates the preference directory path accordingly.

		Returns:
			None
		"""
		base_dir = PreferencesTools.get_preference_directory_path(
			"praat_import_pref_path"
		)
		filename = str(
			QDir.toNativeSeparators(
				QFileDialog.getOpenFileName(
					self,
					"Choisir le fichier à importer",
					base_dir,
					"*.txt;; Results_diadoco.txt;; Results_prosody_Phrase.txt;; "
					"Results_SpeechRate_Semaine_Simple.txt;; Results_SpeechRate_Text.txt;; "
					"Results_coarticulation.txt;; Results_vowels.txt;; Results_a_max.txt;; "
					"Results_VoiceReport.txt",
				)
			)
		)

		if filename != "":
			self.entry_file.setText(filename)
			PreferencesTools.set_preference_directory_path_from_filename(
				"praat_import_pref_path", filename
			)

	def import_from_praat(self):
		"""
		Imports data from a Praat-exported text file into the database.

		This method reads the specified file, determines the data type based on the filename,
		prepares corresponding SQL queries depending on the expected columns,
		and executes these queries on the database.

		It updates a progress bar during import and shows an alert indicating
		the number of imported results or notifies if no relevant data was found.

		Returns:
			bool: False if no file was specified, True otherwise.
		"""
		filename = str(self.entry_file.text())
		if len(filename) == 0:
			return False

		queries: Optional[list[str]] = None
		PraatImportWindow.load_import_filelist()
		data = CSVManager.read_file(filename)

		if filename.endswith("Results_diadoco.txt"):
			internal_indexes = {"filename": 3}
			fields_indexes = {
				"label": 7,
				"comment": 8,
				"start": 9,
				"end": 10,
				"meanF0": 12,
				"medianF0": 13,
				"sdF0": 14,
				"meanIntensity": 16,
				"medianIntensity": 17,
				"sdIntensity": 18,
			}
			queries = PraatImportWindow.prepare_sql_for_praat_qa(
				self.cotation_db, data[1:], internal_indexes, fields_indexes, True
			)

		if filename.endswith("Results_prosody_Phrase.txt"):
			internal_indexes = {"filename": 3}
			fields_indexes = {
				"label": 7,
				"comment": 8,
				"start": 9,
				"end": 10,
				"medianF0_2nd": 12,
				"medianF0_3rd": 13,
				"sdF0_2nd": 15,
				"sdF0_3rd": 16,
			}
			queries = PraatImportWindow.prepare_sql_for_praat_qa(
				self.cotation_db, data[1:], internal_indexes, fields_indexes, True
			)

		if filename.endswith("Results_SpeechRate_Semaine_Simple.txt"):
			internal_indexes = {"filename": 3}
			fields_indexes = {
				"label": 6,
				"comment": 7,
				"start": 8,
				"end": 9,
				"weekRate": 11,
				"twoDaySyllableRate": 12,
			}
			queries = PraatImportWindow.prepare_sql_for_praat_qa(
				self.cotation_db, data[1:], internal_indexes, fields_indexes, True
			)

		if filename.endswith("Results_SpeechRate_Text.txt"):
			internal_indexes = {"filename": 3}
			fields_indexes = {"label": 7, "comment": 8, "start": 9, "end": 10}
			queries = PraatImportWindow.prepare_sql_for_praat_qa(
				self.cotation_db, data[1:], internal_indexes, fields_indexes, True
			)

		if filename.endswith("Results_coarticulation.txt"):
			internal_indexes = {"filename": 3}
			fields_indexes = {
				"label": 7,
				"comment": 8,
				"start": 9,
				"end": 10,
				"meanF0": 12,
				"meanF1": 17,
				"meanF2": 21,
				"meanF3": 25,
				"medianF0": 13,
				"medianF1": 18,
				"medianF2": 22,
				"medianF3": 26,
				"sdF0": 14,
				"sdF1": 19,
				"sdF2": 23,
				"sdF3": 27,
				"formantMeasures": 16,
				"F0_Start": 29,
				"F1_Start": 40,
				"F2_Start": 51,
				"F3_Start": 62,
				"F0_End": 39,
				"F1_End": 50,
				"F2_End": 61,
				"F3_End": 72,
				"F0_10p": 30,
				"F0_20p": 31,
				"F0_30p": 32,
				"F0_40p": 33,
				"F0_50p": 34,
				"F0_60p": 35,
				"F0_70p": 36,
				"F0_80p": 37,
				"F0_90p": 38,
				"F1_10p": 41,
				"F1_20p": 42,
				"F1_30p": 43,
				"F1_40p": 44,
				"F1_50p": 45,
				"F1_60p": 46,
				"F1_70p": 47,
				"F1_80p": 48,
				"F1_90p": 49,
				"F2_10p": 52,
				"F2_20p": 53,
				"F2_30p": 54,
				"F2_40p": 55,
				"F2_50p": 56,
				"F2_60p": 57,
				"F2_70p": 58,
				"F2_80p": 59,
				"F2_90p": 60,
				"F3_10p": 63,
				"F3_20p": 64,
				"F3_30p": 65,
				"F3_40p": 66,
				"F3_50p": 67,
				"F3_60p": 68,
				"F3_70p": 69,
				"F3_80p": 70,
				"F3_90p": 71,
				"cog_1st_half": 73,
				"cog_2nd_half": 74,
				"cog_1st_quarter": 76,
				"cog_4th_quarter": 77,
				"cog_1st_third": 79,
				"cog_3rd_third": 80,
				"sd_1st_half": 82,
				"sd_2nd_half": 83,
				"sd_1st_quarter": 84,
				"sd_4th_quarter": 85,
				"sd_1st_third": 86,
				"sd_3rd_third": 87,
				"ske_1st_half": 88,
				"ske_2nd_half": 89,
				"ske_1st_quarter": 90,
				"ske_4th_quarter": 91,
				"ske_1st_third": 92,
				"ske_3rd_third": 93,
				"kur_1st_half": 94,
				"kur_2nd_half": 95,
				"kur_1st_quarter": 96,
				"kur_4th_quarter": 97,
				"kur_1st_third": 98,
				"kur_3rd_third": 99,
			}
			queries = PraatImportWindow.prepare_sql_for_praat_pw(
				self.cotation_db, data[1:], internal_indexes, fields_indexes, True
			)

		if filename.endswith("Results_vowels.txt"):
			internal_indexes = {"filename": 3, "ai_change": 5}
			fields_indexes = {
				"label": 7,
				"comment": 8,
				"start": 9,
				"end": 10,
				"meanF0": 12,
				"meanF1": 17,
				"meanF2": 21,
				"meanF3": 25,
				"medianF0": 13,
				"medianF1": 18,
				"medianF2": 22,
				"medianF3": 26,
				"sdF0": 14,
				"sdF1": 19,
				"sdF2": 23,
				"sdF3": 27,
				"formantMeasures": 16,
				"F0_10p": 29,
				"F0_20p": 30,
				"F0_30p": 31,
				"F0_40p": 32,
				"F0_50p": 33,
				"F0_60p": 34,
				"F0_70p": 35,
				"F0_80p": 36,
				"F0_90p": 37,
				"F1_10p": 38,
				"F1_20p": 39,
				"F1_30p": 40,
				"F1_40p": 41,
				"F1_50p": 42,
				"F1_60p": 43,
				"F1_70p": 44,
				"F1_80p": 45,
				"F1_90p": 46,
				"F2_10p": 47,
				"F2_20p": 48,
				"F2_30p": 49,
				"F2_40p": 50,
				"F2_50p": 51,
				"F2_60p": 52,
				"F2_70p": 53,
				"F2_80p": 54,
				"F2_90p": 55,
				"F3_10p": 56,
				"F3_20p": 57,
				"F3_30p": 58,
				"F3_40p": 59,
				"F3_50p": 60,
				"F3_60p": 61,
				"F3_70p": 62,
				"F3_80p": 63,
				"F3_90p": 64,
				"meanIntensity": 65,
				"medianIntensity": 66,
				"sdIntensity": 67,
				"meanHNR": 69,
				"sdHNR": 70,
			}
			queries = PraatImportWindow.prepare_sql_for_praat_pw(
				self.cotation_db, data[1:], internal_indexes, fields_indexes, True
			)

		if filename.endswith("Results_a_max.txt"):
			internal_indexes = {"filename": 3}
			fields_indexes = {"label": 7, "comment": 8, "start": 9, "end": 10}
			queries = PraatImportWindow.prepare_sql_for_praat_qa(
				self.cotation_db, data[1:], internal_indexes, fields_indexes, True
			)

		if filename.endswith("Results_VoiceReport.txt"):
			internal_indexes = {"filename": 3}
			fields_indexes = {
				"label": 7,
				"comment": 8,
				"start": 9,
				"end": 10,
				"meanF0": 13,
				"medianF0": 12,
				"sdF0": 14,
				"fractionOfLocallyUnvoicedFrames": 16,
				"numberOfVoiceBreaks": 17,
				"jitter_local": 18,
				"shimmer_local": 19,
				"meanHNR": 20,
			}
			queries = PraatImportWindow.prepare_sql_for_praat_qa(
				self.cotation_db, data[1:], internal_indexes, fields_indexes, True
			)

		if queries is not None and len(queries) > 0:
			self.pbar.setMaximum(len(queries) - 1 + len(self.result_dbs))
			for q in queries:
				if PraatImportWindow.files[q[0]]["participant"] in self.result_dbs:
					self.result_dbs[
						PraatImportWindow.files[q[0]]["participant"]
					].execute(q[1], q[2])
				self.pbar.setValue(self.pbar.value() + 1)

			for db in self.result_dbs.values():
				db.commit()
				self.pbar.setValue(self.pbar.value() + 1)

			GeneralTools.alert_box(
				self,
				str(len(queries))
				+ " résultat(s) importé(s) depuis le fichier "
				+ filename,
			)

			self.close()

		else:
			GeneralTools.alert_box(
				self,
				"Aucune information correspondant aux data MonPaGe trouvée dans le fichier "
				+ filename,
				None,
				True,
			)

	@staticmethod
	def prepare_sql_for_praat_qa(
		cotation_db,
		datas: list,
		internal_indexes: dict,
		fields_indexes: dict,
		simple=True,
	):
		"""
		Prepare SQL queries for importing Praat QA data.

		Fetches stimulus file IDs from the database, maps filenames to their IDs,
		and calls the generic SQL preparation method with this mapping and
		provided data and field indexes.

		Args:
			cotation_db: Database connection object.
			datas: List of data rows to import.
			internal_indexes: Dictionary mapping internal field names to column indexes.
			fields_indexes: Dictionary mapping database field names to column indexes.
			simple (bool): Whether to use the simple import mode (default: True).

		Returns:
			list: A list of prepared SQL queries ready for execution.
		"""
		sql = "select file, id from stimuli"
		vals = cotation_db.execute(sql).fetchall()
		stimulis = {}
		for val in vals:
			stimulis[val[0]] = int(val[1])

		return PraatImportWindow.prepare_sql_for_praat(
			stimulis,
			"stimuli_id",
			"results_praat_qa",
			datas,
			internal_indexes,
			fields_indexes,
			simple,
		)

	@staticmethod
	def prepare_sql_for_praat_pw(
		cotation_db,
		datas: list,
		internal_indexes: dict,
		fields_indexes: dict,
		simple=True,
	):
		"""
		Prepares SQL queries for importing Praat data related to pseudo-words.

		Fetches pseudo-word IDs from the database, creates a dictionary mapping the
		filename (without extension) to its ID, then calls the generic SQL preparation
		method using this mapping and the provided data.

		Args:
			cotation_db: Database connection object.
			datas: List of data rows to import.
			internal_indexes: Dictionary mapping internal field names to column indices.
			fields_indexes: Dictionary mapping database field names to column indices.
			simple (bool): Indicates whether to perform a simple import (default is True).

		Returns:
			list: List of prepared SQL queries ready for execution.
		"""
		sql = "select type|| '-' || filename as fname, id from pseudo_word"
		vals = cotation_db.execute(sql).fetchall()
		pws = {}
		for val in vals:
			fname = val[0].split(".")[0]
			pws[fname] = int(val[1])

		return PraatImportWindow.prepare_sql_for_praat(
			pws,
			"pseudo_word_id",
			"results_praat_pw",
			datas,
			internal_indexes,
			fields_indexes,
			simple,
		)

	@staticmethod
	def prepare_sql_for_praat(
		tomatch: dict[str, int],
		id_field_name: str,
		table_name: str,
		datas: list,
		internal_indexes: dict,
		fields_indexes: dict,
		simple=True,
	):
		"""
		Prepares SQL insertion queries from Praat data.

		This function sorts the imported data by filename and start time,
		then generates SQL insertion queries for the specified table.
		It uses a mapping of filenames to IDs to link the data correctly.

		Args:
			tomatch (dict): Dictionary mapping filenames to database IDs.
			id_field_name (str): Name of the foreign key field in the target table.
			table_name (str): Name of the table to insert data into.
			datas (list): List of data rows extracted from the Praat file.
			internal_indexes (dict): Indexes of internal columns (e.g., {"filename": idx}).
			fields_indexes (dict): Indexes of fields to insert (e.g., {"start": idx, "end": idx}).
			simple (bool): Simple import mode (default is True).

		Returns:
			list: List of tuples (imported_filename, SQL query, values) ready to execute.
		"""
		module_reg = re.compile("Module[^_]*_")
		ret = []

		sorted_data = {}
		for line in datas:
			filename = GeneralTools.praat_type_cast(line[internal_indexes["filename"]])
			start = GeneralTools.praat_type_cast(line[fields_indexes["start"]])

			if filename is not None and start is not None:
				if filename not in sorted_data:
					sorted_data[filename] = {}
				if start not in sorted_data[filename]:
					sorted_data[filename][start] = line

		for fname in sorted_data.keys():
			starts = sorted(sorted_data[fname].keys())
			tmp = module_reg.split(fname)
			filename = tmp[1]
			db_id: Optional[int] = None
			if filename in tomatch:
				db_id = int(tomatch[filename])
			imported_file = (
				sorted_data[fname][starts[0]][internal_indexes["filename"]] + ".wav"
			)
			if imported_file in PraatImportWindow.files:
				interval_number = 1
				for start in starts:
					line = sorted_data[fname][start]
					values = {
						"start": None,
						"end": None,
						id_field_name: db_id,
						"interval_number": interval_number,
						"session_path": PraatImportWindow.files[imported_file][
							"session_path"
						],
						"participant": PraatImportWindow.files[imported_file][
							"participant"
						],
					}
					for key in fields_indexes:
						try:
							val = GeneralTools.praat_type_cast(
								line[fields_indexes[key]]
							)
						except IndexError:
							val = None

						if val is not None:
							values[key] = GeneralTools.praat_type_cast(val)

					if values["end"] is not None:
						sql = DBManager.generate_table_insertion_query_with_bindings_sql_from_dict(
							values, table_name
						)
						vals = tuple(values.values())
						ret.append((imported_file, sql, vals))

					interval_number += 1
			else:
				logger.error(
					f"Pas pu trouver de fichier correspondant à {imported_file}"
				)

		return ret

	@staticmethod
	def load_import_filelist():
		"""
		Loads the list of importable files from the data directory.

		This function scans the './data/participant' directory recursively to find
		.wav files organized by participant, date, and session. It populates the
		`PraatImportWindow.files` dictionary with metadata for each audio file.

		The dictionary keys are filenames, and values contain participant name,
		module name (extracted from session), session path, and date.

		No return value.

		Raises:
			None
		"""
		PraatImportWindow.files = {}
		base_path = "./data/participant"
		if os.path.isdir(base_path):
			for participant_name in os.listdir(base_path):
				tmp = base_path + "/" + participant_name
				if os.path.isdir(tmp):
					for date in os.listdir(tmp):
						tmp = base_path + "/" + participant_name + "/" + date
						if os.path.isdir(tmp):
							for session_name in os.listdir(tmp):
								tmp = (
									base_path
									+ "/"
									+ participant_name
									+ "/"
									+ date
									+ "/"
									+ session_name
								)
								if os.path.isdir(tmp):
									tmp2 = session_name.split("_")
									module_name = tmp2[0]
									for filename in os.listdir(tmp):
										if filename.endswith(".wav"):
											if filename in PraatImportWindow.files:
												logger.warning(
													f"Entry already found for {filename}"
												)
											else:
												PraatImportWindow.files[filename] = {
													"participant": participant_name,
													"module": module_name,
													"session_path": date
													+ "/"
													+ session_name
													+ "/",
													"date": date,
												}
