from typing import List, Optional, Union

from axipy._internal._decorator import _deprecated_by
from axipy.cpp_core_core import ShadowFloatFormatter
from PySide2.QtCore import QLocale

from .coord_formatter import _Coord

__all__: List[str] = [
    "FloatFormatter",
    "FloatCoord",
]


class FloatCoord(_Coord):
    """
    Класс представляет собой координату в формате числа с плавающей точкой (float).

    Для угловой координаты используется класс :class:`axipy.AngleCoord`.
    """

    def as_string(
        self,
        *,
        precision: int = 15,
        locale: Optional[Union[QLocale, QLocale.Language]] = None,
        omit_group_separator: bool = True,
        group_separator: Optional[str] = None,
        decimal_point: Optional[str] = None,
        suppress_trailing_zeros: bool = True,
    ) -> str:
        """
        Возвращает число в виде строки.

        Args:
            precision: Необходимое число знаков после запятой.
            locale: Локаль в которой нужно вывести значение. По умолчанию используется текущая локаль: ``QLocale()``.
            omit_group_separator: Исключить разделитель разрядов.
            group_separator: Использовать другой разделитель разрядов.
            decimal_point: Использовать другой десятичный разделитель.
            suppress_trailing_zeros: Не показывать завершающие нули.
        """
        if locale is None:
            locale = QLocale()
        else:  # Копия создается, чтобы не модифицировать переданную локаль
            locale = QLocale(locale)

        if omit_group_separator:
            locale.setNumberOptions(QLocale.OmitGroupSeparator)

        if not suppress_trailing_zeros:
            locale.setNumberOptions(QLocale.IncludeTrailingZeroesAfterDot)

        result = ShadowFloatFormatter.to_localized_string_round(self._value, precision, locale)  # type: str

        decimal_point_rpos = result.rfind(locale.decimalPoint())
        index_from_end = len(result) - decimal_point_rpos

        if not omit_group_separator and group_separator is not None:
            result = result.replace(locale.groupSeparator(), group_separator)

        if decimal_point is not None:
            result = result[:-index_from_end] + decimal_point + result[-index_from_end + 1 :]

        return result

    def as_float_round(self, precision: int) -> float:
        """
        Округляет число до заданной точности.

        Args:
            precision: Количество знаков после запятой.
        """
        return ShadowFloatFormatter.float_round(self._value, precision)

    def as_float_round_signific(self, digits: int = 15) -> float:
        """
        Округляет число с указанием количества значащих цифр.

        Args:
            digits: Количество значащих цифр.
        """
        return ShadowFloatFormatter.float_round_signific(self._value, digits)

    def _repr_arg(self) -> str:
        return f"{self.value}"


class FloatFormatter:

    @staticmethod
    @_deprecated_by("axipy.FloatCoord.as_string")
    def to_localized_string(value: float, locale: Optional[QLocale] = None) -> str:
        """
        Возвращает число в виде строки форматированный с учетом переданной локали.

        Args:
            value: Значение которое нужно представить в виде строки.
            locale: Локаль в которой нужно вывести значение. По умолчанию текущая локаль.
        """
        if locale is None:
            locale = QLocale()
        return ShadowFloatFormatter.to_localized_string(value, locale)

    @staticmethod
    @_deprecated_by("axipy.FloatCoord.as_string")
    def to_localized_string_round(value: float, precision: int, locale: Optional[QLocale] = None) -> str:
        """
        Возвращает число в виде строки. Количество знаков после запятой задается
        параметром precision.

        Args:
            value: Значение которое нужно представить в виде строки.
            precision: Необходимое число знаков после запятой.
            locale: Локаль в которой нужно вывести значение. По умолчанию используется текущая локаль: QLocale().
        """
        if locale is None:
            locale = QLocale()
        return ShadowFloatFormatter.to_localized_string_round(value, precision, locale)

    @staticmethod
    @_deprecated_by("axipy.FloatCoord.as_string")
    def float_to_str(value: float, use_delimeter: bool = False, precision: int = 15) -> str:
        """
        Представляет значение типа float в виде строки с заданными параметрами.

        Args:
            value: Входное значение
            use_delimeter: Если True, то использовать разделитель разрядов
            precision: Количество знаков после запятой, если необходимо округление

        .. literalinclude:: /../../tests/doc_examples/utl/test_example_float_formatter.py
            :caption: Пример.
            :pyobject: test_run_example_float_formatter
            :start-after: # start
            :end-before: # finish
            :dedent: 4
        """
        return ShadowFloatFormatter.float_to_str(value, use_delimeter, precision)

    @staticmethod
    @_deprecated_by("axipy.FloatCoord.as_float_round")
    def float_round(value: float, precision: int) -> float:
        """
        Округляет число до заданной точности.

        Args:
            value: Входное значение
            precision: Количество знаков после запятой

        .. literalinclude:: /../../tests/doc_examples/utl/test_example_float_formatter.py
            :caption: Пример.
            :pyobject: test_run_example_float_round
            :start-after: # start round
            :end-before: # finish round
            :dedent: 4
        """
        return ShadowFloatFormatter.float_round(value, precision)

    @staticmethod
    @_deprecated_by("axipy.FloatCoord.as_float_round_signific")
    def float_round_signific(value: float, digits: int = 15) -> float:
        """
        Округляет число с указанием количества значащих цифр.

        Args:
            value: Входное значение
            digits: Количество значащих цифр

        .. literalinclude:: /../../tests/doc_examples/utl/test_example_float_formatter.py
            :caption: Пример.
            :pyobject: test_run_example_float_round
            :start-after: # start signific
            :end-before: # finish signific
            :dedent: 4
        """
        return ShadowFloatFormatter.float_round_signific(value, digits)
