"""Type stubs for the native Rust extension module."""

from __future__ import annotations

import datetime
from collections.abc import Callable, Iterator
from typing import Any

from pintrs.context import Context
from pintrs.group import Group
from pintrs.system import System

class PintError(ValueError): ...
class DimensionalityError(PintError): ...
class UndefinedUnitError(PintError): ...
class OffsetUnitCalculusError(PintError): ...
class DefinitionSyntaxError(PintError): ...
class RedefinitionError(PintError): ...

class Unit:
    def __init__(self, units: str) -> None: ...
    @property
    def dimensionality(self) -> str: ...
    @property
    def dimensionless(self) -> bool: ...
    def is_compatible_with(self, other: Unit | str) -> bool: ...
    def compatible_units(self) -> list[str]: ...
    def from_(self, quantity: Quantity) -> Quantity: ...
    def m_from(self, quantity: Quantity) -> float: ...
    @property
    def systems(self) -> list[str]: ...
    def compare(self, other: Unit, op: str) -> bool: ...
    def _units_str(self) -> str: ...
    def _units_dict(self) -> list[tuple[str, float]]: ...
    def __repr__(self) -> str: ...
    def __str__(self) -> str: ...
    def __mul__(self, other: Any) -> Unit | Quantity: ...
    def __rmul__(self, other: Any) -> Unit | Quantity: ...
    def __truediv__(self, other: Any) -> Unit | Quantity: ...
    def __rtruediv__(self, other: Any) -> Quantity: ...
    def __pow__(self, exp: float) -> Unit: ...
    def __eq__(self, other: object) -> bool: ...
    def __hash__(self) -> int: ...
    def __copy__(self) -> Unit: ...
    def __deepcopy__(self, memo: object) -> Unit: ...
    def __reduce__(self) -> tuple[type, tuple[str]]: ...
    def format_babel(self, locale: str = "en") -> str: ...

class Quantity:
    def __init__(
        self,
        value: float | str | Quantity,
        units: str | None = None,
    ) -> None: ...
    @property
    def magnitude(self) -> float: ...
    @property
    def m(self) -> float: ...
    @property
    def units(self) -> Unit: ...
    @property
    def u(self) -> Unit: ...
    @property
    def dimensionality(self) -> str: ...
    @property
    def dimensionless(self) -> bool: ...
    @property
    def unitless(self) -> bool: ...
    def m_as(self, units: str) -> float: ...
    def to(self, units: str) -> Quantity: ...
    def ito(self, units: str) -> None: ...
    def to_base_units(self) -> Quantity: ...
    def to_root_units(self) -> Quantity: ...
    def ito_base_units(self) -> None: ...
    def ito_root_units(self) -> None: ...
    def to_compact(self) -> Quantity: ...
    def to_reduced_units(self) -> Quantity: ...
    def ito_reduced_units(self) -> None: ...
    def to_preferred(
        self,
        preferred_units: list[str] | None = None,
    ) -> Quantity: ...
    def ito_preferred(
        self,
        preferred_units: list[str] | None = None,
    ) -> None: ...
    def to_unprefixed(self) -> Quantity: ...
    def ito_unprefixed(self) -> None: ...
    def to_tuple(self) -> tuple[float, list[tuple[str, float]]]: ...
    @staticmethod
    def from_tuple(
        tup: tuple[float, list[tuple[str, float]]],
    ) -> Quantity: ...
    def unit_items(self) -> list[tuple[str, float]]: ...
    def compare(self, other: Quantity, op: str) -> bool: ...
    def to_timedelta(self) -> datetime.timedelta: ...
    def plus_minus(self, error: float) -> Any: ...
    def check(self, dimension: str) -> bool: ...
    def is_compatible_with(
        self,
        other: Quantity | Unit | str,
    ) -> bool: ...
    def compatible_units(self) -> list[str]: ...
    def _units_str(self) -> str: ...
    def _units_dict(self) -> list[tuple[str, float]]: ...
    def __repr__(self) -> str: ...
    def __str__(self) -> str: ...
    def __format__(self, spec: str) -> str: ...
    def __float__(self) -> float: ...
    def __int__(self) -> int: ...
    def __bool__(self) -> bool: ...
    def __neg__(self) -> Quantity: ...
    def __abs__(self) -> Quantity: ...
    def __round__(self, ndigits: int | None = None) -> Quantity: ...
    def __add__(self, other: Quantity | float) -> Quantity: ...
    def __radd__(self, other: Quantity | float) -> Quantity: ...
    def __sub__(self, other: Quantity | float) -> Quantity: ...
    def __rsub__(self, other: Quantity | float) -> Quantity: ...
    def __mul__(self, other: Quantity | Unit | float) -> Quantity: ...
    def __rmul__(self, other: Quantity | Unit | float) -> Quantity: ...
    def __truediv__(
        self,
        other: Quantity | Unit | float,
    ) -> Quantity: ...
    def __rtruediv__(self, other: float) -> Quantity: ...
    def __pow__(self, exp: float) -> Quantity: ...
    def __eq__(self, other: object) -> bool: ...
    def __ne__(self, other: object) -> bool: ...
    def __lt__(self, other: Quantity) -> bool: ...
    def __le__(self, other: Quantity) -> bool: ...
    def __gt__(self, other: Quantity) -> bool: ...
    def __ge__(self, other: Quantity) -> bool: ...
    def __hash__(self) -> int: ...
    def __copy__(self) -> Quantity: ...
    def __deepcopy__(self, memo: object) -> Quantity: ...
    def __reduce__(self) -> tuple[type, tuple[float, str]]: ...
    # Monkey-patched numpy-like properties
    @property
    def ndim(self) -> int: ...
    @property
    def shape(self) -> tuple[int, ...]: ...
    @property
    def dtype(self) -> Any: ...
    @property
    def real(self) -> Quantity: ...
    @property
    def imag(self) -> Quantity: ...
    @property
    def T(self) -> Quantity: ...  # noqa: N802
    @property
    def flat(self) -> Iterator[Quantity]: ...
    force_ndarray: bool
    force_ndarray_like: bool
    def clip(self, min: Any = None, max: Any = None) -> Quantity: ...  # noqa: A002
    def dot(self, other: Any) -> Quantity: ...
    def prod(self, axis: Any = None) -> Quantity: ...
    def fill(self, value: Any) -> None: ...
    def put(self, indices: Any, values: Any) -> None: ...
    def searchsorted(self, v: Any, side: str = "left") -> Any: ...
    def tolist(self) -> Any: ...
    @classmethod
    def from_list(cls, lst: list[Any], units: str | None = None) -> Quantity: ...
    @classmethod
    def from_sequence(cls, seq: Any, units: str | None = None) -> Quantity: ...
    def compute(self, **kwargs: Any) -> Quantity: ...
    def persist(self, **kwargs: Any) -> Quantity: ...
    def visualize(self, **kwargs: Any) -> Any: ...
    def format_babel(self, locale: str = "en") -> str: ...
    UnitsContainer: Any

# Use _Q and _U aliases inside UnitRegistry to avoid mypy confusing
# the Quantity/Unit method names with the Quantity/Unit class types.
_Q = Quantity
_U = Unit

class UnitRegistry:
    def __init__(self) -> None: ...
    def Quantity(  # noqa: N802
        self,
        value: float | str | _Q | Any,
        units: str | None = None,
    ) -> _Q: ...
    def Unit(self, units: str) -> _U: ...  # noqa: N802
    def parse_expression(self, expr: str) -> _Q: ...
    def parse_units(self, units: str) -> _U: ...
    def convert(self, value: float, src: str, dst: str) -> float: ...
    def define(self, definition: str) -> None: ...
    def get_compatible_units(self, unit: str) -> list[str]: ...
    def get_base_units(self, unit: str) -> tuple[float, _U]: ...
    def get_root_units(self, unit: str) -> tuple[float, _U]: ...
    def get_dimensionality(self, unit: str) -> str: ...
    def get_name(self, unit: str) -> str: ...
    def get_symbol(self, unit: str) -> str: ...
    def is_compatible_with(self, unit1: str, unit2: str) -> bool: ...
    def parse_unit_name(
        self,
        unit: str,
    ) -> list[tuple[str, str, str]]: ...
    def load_definitions(self, definition: str) -> None: ...
    @property
    def default_format(self) -> str: ...
    @property
    def auto_reduce_dimensions(self) -> bool: ...
    def _scalar_quantity(self, value: Any, units: str | None = None) -> _Q: ...
    def _f64_quantity(self, value: float, units: str | None = None) -> _Q: ...
    def _get_conversion_factor(self, src: str, dst: str) -> float: ...
    def _get_root_units(self, unit: str) -> tuple[float, str]: ...
    def _get_dimensionality(self, unit: str) -> str: ...
    def _format_units(self, unit: str) -> str: ...
    def _get_prefixes(self) -> list[tuple[str, float]]: ...
    def __contains__(self, item: str) -> bool: ...
    def __iter__(self) -> Iterator[str]: ...
    def __getattr__(self, name: str) -> _Q: ...
    # Monkey-patched methods
    def wraps(
        self,
        ret: str | _U | None,
        args: tuple[str | _U | None, ...] | None = None,
        strict: bool = True,
    ) -> Callable[[Callable[..., Any]], Callable[..., Any]]: ...
    def check(
        self,
        *args: str | None,
    ) -> Callable[[Callable[..., Any]], Callable[..., Any]]: ...
    def Measurement(  # noqa: N802
        self,
        value: float,
        error: float,
        units: str | None = None,
    ) -> Any: ...
    def setup_matplotlib(self, enable: bool = True) -> None: ...
    def context(self, *contexts: str | Context, **kwargs: Any) -> Any: ...
    def add_context(self, context: Context) -> None: ...
    def remove_context(self, name: str) -> None: ...
    def enable_contexts(self, *names: str, **kwargs: Any) -> None: ...
    def disable_contexts(self, *names: str) -> None: ...
    def with_context(self, *names: str, **kwargs: Any) -> Any: ...
    def get_group(self, name: str) -> Group: ...
    def get_system(self, name: str) -> System: ...
    def parse_units_as_container(self, units: str) -> dict[str, float]: ...
    def parse_pattern(self, pattern: str, input_string: str) -> Any: ...
    def pi_theorem(self, quantities: dict[str, str]) -> list[dict[str, float]]: ...
    def set_fmt_locale(self, locale: str | None) -> None: ...
    # Config flags
    autoconvert_offset_to_baseunit: bool
    autoconvert_to_preferred: bool
    cache_folder: str | None
    case_sensitive: bool
    default_as_delta: bool
    default_system: str
    fmt_locale: str | None
    force_ndarray: bool
    force_ndarray_like: bool
    non_int_type: type
    separate_format_defaults: bool | None
    preprocessors: list[Any]
    mpl_formatter: str
    # Class references
    Context: type[Context]
    Group: type[Group]
    System: type[System]
    UnitsContainer: Any
    @property
    def sys(self) -> Any: ...
    @property
    def formatter(self) -> Any: ...
