import math


def yaw_pitch_to_3d(yaw: float, pitch: float, radius: float = 100) -> tuple:
    """
    Convert yaw and pitch (in degrees) to a 3D point on the sphere surface.

    Yaw: rotation around vertical axis (0-360, 0 = forward)
    Pitch: elevation angle (-90 = straight down, 0 = horizon, 90 = straight up)
    """
    yaw_rad = math.radians(yaw)
    pitch_rad = math.radians(pitch)

    x = radius * math.cos(pitch_rad) * math.sin(yaw_rad)
    y = radius * math.sin(pitch_rad)
    z = radius * math.cos(pitch_rad) * math.cos(yaw_rad)

    return (x, y, z)


def calculate_reverse_yaw(yaw: float) -> float:
    """Calculate the reverse yaw (opposite direction) of a given yaw."""
    return (yaw + 180.0) % 360.0


def angle_difference(a: float, b: float) -> float:
    """
    Calculate the smallest angle between two yaw values.
    Returns a value between 0 and 180 degrees.
    """
    diff = abs(a - b) % 360.0
    return min(diff, 360.0 - diff)


def spherical_distance(
    yaw1: float, pitch1: float, yaw2: float, pitch2: float
) -> float:
    """
    Calculate the angular distance (in degrees) between two points on a sphere
    given their yaw and pitch coordinates.
    """
    yaw1_rad = math.radians(yaw1)
    pitch1_rad = math.radians(pitch1)
    yaw2_rad = math.radians(yaw2)
    pitch2_rad = math.radians(pitch2)

    # Haversine formula adapted for sphere coordinates
    sin_yaw = math.sin((yaw2_rad - yaw1_rad) / 2.0)
    sin_pitch = math.sin((pitch2_rad - pitch1_rad) / 2.0)

    a = (
        sin_pitch ** 2
        + math.cos(pitch1_rad)
        * math.cos(pitch2_rad)
        * sin_yaw ** 2
    )
    c = 2.0 * math.atan2(math.sqrt(a), math.sqrt(1.0 - a))

    return math.degrees(c)
