from typing import Any, Callable, Optional

from cotation.acoustic.display.io_widget.input_interface import InputInterface
from cotation.acoustic.display.io_widget.io_widget import IOWidget

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

from PySide6.QtWidgets import (
	QHBoxLayout,
	QLabel,
	QWidget,
)

DEFAULT_VALUE_TEXT = "Veuillez selectionner une valeur."


class UILineWithInput(QWidget):
	label: QLabel
	label_name: str
	unit_name: str
	input_widget: InputInterface

	is_display_valid: bool = False
	invalid_display_color: str
	valid_display_color: str

	_value_changed_callback: Optional[Callable[[], Any]]
	_resize_callback: Optional[Callable[[int], Any]]

	def __init__(
		self,
		label_name: str,
		unit_name: str,
		input_widget: InputInterface,
		invalid_display_color: str = "red",
		valid_display_color: str = "green",
	):
		super().__init__()
		self.io_widget = IOWidget()

		self.label_name = label_name
		self.unit_name = unit_name
		self.input_widget = input_widget
		self._value_changed_callback = None
		self._resize_callback = None

		self.invalid_display_color = invalid_display_color
		self.valid_display_color = valid_display_color

		# Connect to widget callbacks
		self.input_widget.set_value_changed_ui_callback(self.on_value_changed)
		self.input_widget.set_resize_callback(self._handle_resize)

		layout = QHBoxLayout()

		self.label = QLabel()

		unit = QLabel()
		unit.setText(self.unit_name)

		if input_widget.get_is_filled():
			self.display_valid()
		else:
			self.display_invalid()

		layout.addWidget(self.label)
		layout.addWidget(input_widget.get_widget())
		layout.addWidget(unit)

		layout.addStretch()
		layout.setContentsMargins(0, 0, 0, 0)

		self.setLayout(layout)

	def set_resize_callback(self, callback: Callable[[int], Any]) -> None:
		"""
		Sets a callback function to be invoked when a resize event occurs.

		The callback should accept a single integer argument (typically representing a new size)
		and can return any type.

		Parameters:
			callback (Callable[[int], Any]): The function to call on resize events.

		Returns:
			None
		"""
		self._resize_callback = callback

	def _handle_resize(self, value: int) -> None:
		"""
		Invokes the resize callback with the given value, if a callback has been set.

		Parameters:
			value (int): The value to pass to the resize callback, typically representing a new size.

		Returns:
			None
		"""
		if self._resize_callback:
			self._resize_callback(value)

	# Function called when the input inside
	def on_value_changed(self):
		"""
		Handles changes in the input widget's value and updates the display accordingly.

		If the current filled state matches the previously displayed valid state, no action is taken.
		Otherwise, updates the label to reflect either a valid or invalid state based on the input,
		and stores the new state.

		Returns nothing.
		"""
		if self.input_widget.get_is_filled() == self.is_display_valid:
			return

		if self.input_widget.get_is_filled():
			self.display_valid()
		else:
			self.display_invalid()

		self.is_display_valid = self.input_widget.get_is_filled()
		#
		# if self._value_changed_callback:
		# 	self._value_changed_callback()

	def display_valid(self):
		"""
		Updates the label text by applying bold and underlined rich text formatting to the label name,
		and sets the text color to indicate a valid state.

		Uses an external method `bolded_underlined_richtext` for text styling.

		Returns nothing.
		"""
		self.label.setText(self.io_widget.bolded_underlined_richtext(self.label_name))
		self.label.setStyleSheet(f"color: {self.valid_display_color}")

	def display_invalid(self):
		"""
		Marks the input label as invalid by appending an asterisk (*) and changing its text color.

		This visually indicates that the associated input is required or invalid.
		"""
		self.label.setText(
			self.io_widget.bolded_underlined_richtext(self.label_name + "*")
		)
		self.label.setStyleSheet(f"color: {self.invalid_display_color}")

	def get_is_filled(self) -> bool:
		"""
		Checks whether the input field has been filled.

		:return: True if the input contains a value, False otherwise.
		:rtype: bool
		"""
		return self.input_widget.get_is_filled()
