from typing import Iterable, Tuple
from ._internal import Distance, Angle

# Since they are essential, we will copy them from math
def degrees(x: float, /) -> float: ...
def radians(x: float, /) -> float: ...

# Trigonometric functions
def alpha(dx: Distance, dy: Distance) -> Angle: ...
def alpha_cos(dx: Distance, h: Distance) -> Angle: ...
def alpha_sin(dy: Distance, h: Distance) -> Angle: ...
def h(dx: Distance, dy: Distance) -> Distance: ...
def dx(dy: Distance, alpha: Angle) -> Distance: ...
def dy(dx: Distance, alpha: Angle) -> Distance: ...
def h_cos(dx: Distance, alpha: Angle) -> Distance: ...
def h_sin(dy: Distance, alpha: Angle) -> Distance: ...
def dx_h(dy: Distance, h: Distance) -> Distance: ...
def dy_h(dx: Distance, h: Distance) -> Distance: ...
def dx_h2(alpha: Angle, h: Distance) -> Distance: ...
def dy_h2(alpha: Angle, h: Distance) -> Distance: ...

# Others
def distance(dx: Distance, dy: Distance) -> Distance: ...
def step(x: Distance, factor: float) -> Distance: ...

# basic helpers / polar/cartesian conversion
def distance_sq(dx: Distance, dy: Distance) -> Distance: ...
def to_polar(dx: Distance, dy: Distance) -> Tuple[Distance, Angle]: ...
def from_polar(r: Distance, alpha: Angle) -> Tuple[Distance, Distance]: ...

# angle math
def wrap_angle(alpha: Angle) -> Angle: ...
def angle_diff(alpha1: Angle, alpha2: Angle) -> Angle: ...
def mean_angle(angles: Iterable[Angle]) -> Angle: ...
def angle_between(v1x: Distance, v1y: Distance, v2x: Distance, v2y: Distance) -> Angle: ...

# vector operations
def dot(dx1: Distance, dy1: Distance, dx2: Distance, dy2: Distance) -> float: ...
def cross(dx1: Distance, dy1: Distance, dx2: Distance, dy2: Distance) -> float: ...
def norm2(dx: Distance, dy: Distance) -> float: ...            # squared distance
def normalize(dx: Distance, dy: Distance) -> Tuple[Distance, Distance]: ...
def scale_to(dx: Distance, dy: Distance, length: Distance) -> Tuple[Distance, Distance]: ...
def rotate(dx: Distance, dy: Distance, alpha: Angle) -> Tuple[Distance, Distance]: ...

# projections & distances
def project_point_on_line(px: Distance, py: Distance,
                          ax: Distance, ay: Distance,
                          bx: Distance, by: Distance) -> Tuple[Distance, Distance]: ...
def distance_point_to_segment(px: Distance, py: Distance,
                              ax: Distance, ay: Distance,
                              bx: Distance, by: Distance) -> Distance: ...

# interpolation / stepping
def lerp(a: float, b: float, t: float) -> float: ...
def lerp_point(ax: Distance, ay: Distance, bx: Distance, by: Distance, t: float) -> Tuple[Distance, Distance]: ...
def step_towards(current: Distance, target: Distance, max_step: float) -> Distance: ...

# numeric helpers
def clamp(x: float, a: float, b: float) -> float: ...
def sign(x: float) -> int: ...

def lerp_angle(a1: Angle, a2: Angle, t: float) -> Angle: ...
def shortest_rotation(a_from: Angle, a_to: Angle) -> Angle: ...
def is_angle_close(a1: Angle, a2: Angle, tol: float) -> bool: ...