# encoding=utf-8
__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 cotation.acoustic.display.io_widget.int_input import IntInput
from cotation.acoustic.display.io_widget.ui_line_with_input import UILineWithInput
from cotation.acoustic.struct.analysis.cotation_acoustic_analysis import (
	CotationAcousticAnalysis,
)
from typing import Union
from cotation.acoustic.display.io_widget.info import InfoBox
from cotation.acoustic.display.io_widget.output import Output
from cotation.acoustic.display.io_widget.info import Info

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

# @property transparantly have getter and setter.
# class.x instead of class.(get,set)_x()

DEFAULT_SOUND_FILE_PATTERN = "{}_{}_Module{}.wav"


class Week(CotationAcousticAnalysis):
	"""
	Analyzes weekly data by counting the number of days within a given time interval.

	This class tracks the number of counted days in a session and calculates a
	rate representing the number of days per second over the selected interval.

	It also provides user interface components for inputting the number of days
	and displaying the calculated weekly rate.

	Attributes:
	    _counted_days (int): Number of days counted in the interval.
	    nb_days (IntInput): UI input field for the user to enter counted days.
	    week_rate_output (Output): UI output field displaying the calculated weekly rate.
	"""

	_counted_days: int = 0

	def __init__(
		self,
		speaker_code: str,
		session_date: str,
	):
		super().__init__(
			speaker_code,
			"Semaine_jours_semaine",
			session_date,
		)
		self.week_rate_output = Output("rate series", "")
		self.is_signal_selection_movable = True
		self.is_signal_selection_manually_resizable = True
		self.signal_selection_min_length = 0.1
		self.signal_selection_max_length = 100

		self._counted_days = 0
		self.nb_days = None  # Will be initialized in io()

	def get_counted_days(self) -> int:
		"""
		Returns the counted number of days.

		This number is stored internally and can be used for calculating the weekly rate.
		"""

		return self._counted_days

	def set_counted_days(self, counted_days: int):
		"""
		Sets the counted number of days.

		Raises an error if the provided number is less than or equal to 0.
		"""

		if counted_days <= 0:
			ValueError("Le nombre de jours compté doit être supérieur à 0")
		self._counted_days = counted_days

	# Read only
	def get_week_rate(self) -> float:
		"""
		Calculates the rate of days relative to the interval duration.

		This rate represents the counted number of days divided by the analyzed duration.
		Raises an error if no days have been counted.
		"""

		if self.get_counted_days() <= 0:
			ValueError("Le nombre de jours compté doit être supérieur à 0")

		return float(self.get_counted_days()) / self.get_interval_duration()

	@override
	def get_default_interval_duration(self) -> float:
		"""
		Returns the default interval duration for this analysis.

		Here, the duration is set to 20 seconds.
		"""

		return 20

	@override
	def get_results(self) -> dict[str, Union[float, str]]:
		"""
		Generates the analysis results as a dictionary.

		Includes the interval duration, the weekly rate (days per second),
		and the counted number of days.
		"""

		return {
			"mpt_candidate_week": self.get_interval_duration(),
			"rate_series": self.get_week_rate(),
			"counted_days": self.get_counted_days(),
		}

	def set_counted_days_from_input_value(self):
		"""
		Updates the counted number of days from the value entered in the user interface.

		If the entered value is valid (> 0), it is saved in the internal state.
		"""

		if self.nb_days.get_input_value() > 0:
			self.set_counted_days(self.nb_days.get_input_value())

	@override
	def get_io(self) -> Info:
		"""
		Initializes and returns the user interface elements for the "week" segmentation.

		Creates an info box containing an input field for the number of days and another
		for displaying the weekly rate. Restores previously saved values if they exist.
		"""

		# Only initialize IntInput if it hasn't been initialized yet
		if self.nb_days is None:
			self.nb_days = IntInput(0)

		uilineinput = UILineWithInput("Jours dans l'intervalle", "jours", self.nb_days)
		# If we have a valid value from previous state, restore it
		if self._counted_days > 0:
			self.nb_days.set_input_value(self._counted_days)

		# We set a SECOND callback in the INPUT itself as to what to do when the value is changed
		self.nb_days.set_value_changed_data_callback(
			self.set_counted_days_from_input_value
		)

		info_box = InfoBox(
			"Segmentation Semaine",
			"Ajuster la frontière, pour qu'elle corresponde précisément au début du 1er 'lundi' "
			+ "Ajuster la frontière droite de l'intervalle 'jours de la semaine. La déplacer vers la droite afin que "
			+ "le dernier mot/jour ne soit pas coupé par la frontière.",
			[uilineinput],
		)

		resultats = InfoBox("Résultats", dynamic_content=[self.week_rate_output])

		info = Info()
		info.add_infobox(info_box)
		info.add_infobox(resultats)

		return info

	@override
	def update_io(self):
		"""
		Updates the user interface elements with the current internal data.

		Synchronizes the input field for the number of days and updates the displayed weekly rate.
		"""

		# Update the output display with the current rate
		self.week_rate_output.update_value(self.get_week_rate())

		# Always ensure the input field reflects the stored value
		# This ensures state consistency between stored data and UI
		if self.get_counted_days() > 0:
			self.nb_days.set_input_value(self.get_counted_days())
