# encoding=utf-8
"""
Class used to encapsulate some calculations in parselmouth
"""

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

import parselmouth  # type: ignore

from typing import Iterator
from cotation.acoustic.struct.praat.markers import IntervalMarker

PRAAT_FULL_FILE: float = 0.0
PITCH_UNIT: str = "Hertz"
MINIMUM_INTERPOLATION_TYPE: str = "Parabolic"


class ParselmouthVoiceReport:
	"""
	Generates a detailed voice report from Parselmouth Sound and Pitch objects over a specified interval.

	Attributes:
	    data (str): Raw voice report data string generated by Parselmouth.
	"""

	data: str

	def __init__(
		self,
		sound: parselmouth.Sound,
		pitch: parselmouth.Pitch,
		min_f0_range: float,
		max_f0_range: float,
		interval: IntervalMarker,
	):
		pulses = parselmouth.praat.call([sound, pitch], "To PointProcess (cc)")
		self.data = parselmouth.praat.call(
			[sound, pitch, pulses],
			"Voice report",
			float(interval.start_time),
			float(interval.end_time),
			min_f0_range,
			max_f0_range,
			1.3,
			1.6,
			0.03,
			0.45,
		)

	def get_harmonics_to_noise_ratio(self) -> float:
		"""
		Extract the mean harmonics-to-noise ratio (HNR) value from the report data.

		Returns:
		    float: Mean harmonics-to-noise ratio value.
		"""
		value, _ = ParselmouthVoiceReport.extract_number(
			self.data, "Mean harmonics-to-noise ratio"
		)
		return value

	"""
	@Returns: (value, value unit)
	"""

	@staticmethod
	def extract_numbers(
		praat_object: str, labels: list[str]
	) -> Iterator[tuple[float, str]]:
		"""
		Extract multiple numerical values along with their units from a Praat text output.

		Args:
		    praat_object (str): Multiline string output from Praat.
		    labels (list[str]): List of labels to look for.

		Returns:
		    Iterator[tuple[float, str]]: Iterator over tuples of (value, unit).
		"""
		lines = praat_object.split("\n")
		selected_lines = filter(
			lambda value: value.strip().split(":")[0] in labels, lines
		)

		selected_values_raw_str: map[list[str]] = map(
			lambda value: value.split(":")[-1].strip().split(" "), selected_lines
		)
		selected_values: map[tuple[float, str]] = map(
			lambda value: (float(value[0]), value[1]), selected_values_raw_str
		)
		return selected_values

	@staticmethod
	def extract_number(praat_object: str, label: str) -> tuple[float, str]:
		"""
		Extract a single numerical value and unit for a given label from Praat output.

		Args:
		    praat_object (str): Multiline string output from Praat.
		    label (str): Label to find.

		Returns:
		    tuple[float, str]: Extracted (value, unit) tuple.

		Raises:
		    StopIteration: If the label is not found.
		"""
		return next(ParselmouthVoiceReport.extract_numbers(praat_object, [label]))
