from typing import Any, Callable, Optional

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

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

from PySide6.QtWidgets import (
	QDoubleSpinBox,
	QWidget,
)

DEFAULT_VALUE_TEXT = "Veuillez selectionner une valeur."


class FloatInput(QDoubleSpinBox, InputInterface):
	"""
	A custom QDoubleSpinBox widget for floating-point input with validation and callback support.
	FloatInput extends QDoubleSpinBox and implements the InputInterface to provide a specialized input field for floating-point numbers. It supports marking a default value as invalid, displaying a special value text, and handling value change callbacks.
	Attributes:
		default_invalid_value (float): The value considered invalid if `default_is_invalid` is True.
		_value_changed_callback (Optional[Callable[[], Any]]): Optional callback to be invoked when the value changes.
	"""

	default_invalid_value: float
	_value_changed_callback: Optional[Callable[[], Any]]

	def __init__(
		self,
		default_is_invalid: bool = True,
		default_value: float = -1,
		default_value_text: str = DEFAULT_VALUE_TEXT,
	):
		super().__init__()

		self.default_is_invalid = default_is_invalid
		self.default_value = default_value
		# self._value_changed_callback = None

		if default_is_invalid:
			self.setSpecialValueText(default_value_text)
		self.setMinimum(default_value)
		self.setValue(default_value)

		# Connect internal Qt signal to our callback handler using lambda to avoid connection warnings
		self.valueChanged.connect(lambda _: self._handle_value_changed())

	@override
	def get_widget(self) -> QWidget:
		"""
		Returns the current instance of the widget.

		Returns:
			QWidget: The widget instance itself.
		"""
		return self

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

		Args:
			callback (Callable[[int], Any]): A function that takes an integer (typically representing the new size)
				and returns any value. This function will be called when a resize event is detected.

		Note:
			For FloatInput, resize events are not emitted, so this method does not perform any action.
		"""
		# FloatInput doesn't emit resize events
		pass

	def get_input_value(self):
		"""
		Retrieves the current value from the input widget.

		Returns:
			float: The current value entered in the input field.
		"""
		return self.value()

	def set_input_value(self, value: float):
		"""
		Sets the input field's value to the specified float.

		Args:
			value (float): The value to set in the input field.

		Raises:
			ValueError: If the provided value cannot be converted to a float.

		This method updates the widget's displayed value to the given float, ensuring the input is properly formatted.
		"""
		self.setValue(float(value))

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

		Returns:
			bool: True if the input is filled (i.e., the default value is valid or the current value differs from the default value), False otherwise.
		"""
		return not self.default_is_invalid or self.value() != self.default_value
