from _typeshed import Unused
from datetime import datetime as _datetime
from typing import Final, NoReturn, TypeAlias, TypedDict, overload, type_check_only
from typing_extensions import Self, deprecated, disjoint_base

_DateInitType: TypeAlias = (
    Date
    | float
    | str
    | tuple[int]
    | tuple[int, int]
    | tuple[int, int, float]
    | tuple[int, int, float, float]
    | tuple[int, int, float, float, float]
    | tuple[int, int, float, float, float, float]
    | _datetime
)

@type_check_only
class _DateDescriptor:
    @overload
    def __get__(self, obj: None, objtype: type | None = None) -> Self: ...
    @overload
    def __get__(self, obj: object, objtype: type | None = None) -> Date: ...

    def __set__(self, obj: object, value: _DateInitType) -> None: ...

@type_check_only
class _AngleDescriptorRadiansHours:
    @overload
    def __get__(self, obj: None, objtype: type | None = None) -> Self: ...
    @overload
    def __get__(self, obj: object, objtype: type | None = None) -> Angle: ...

    def __set__(self, obj: object, value: float | str) -> None: ...

@type_check_only
class _AngleDescriptorRadiansDegrees:
    @overload
    def __get__(self, obj: None, objtype: type | None = None) -> Self: ...
    @overload
    def __get__(self, obj: object, objtype: type | None = None) -> Angle: ...

    def __set__(self, obj: object, value: float | str) -> None: ...

@type_check_only
class _AngleDescriptorDegreesRadians:
    @overload
    def __get__(self, obj: None, objtype: type | None = None) -> Self: ...
    @overload
    def __get__(self, obj: object, objtype: type | None = None) -> Angle: ...

    @overload
    @deprecated("Do not pass Angle objects! The radian value will be incorrectly interpreted as degrees.")
    def __set__(self, obj: object, value: Angle) -> None: ...
    @overload
    def __set__(self, obj: object, value: float | str) -> None: ...

J2000: Final[float]
MJD0: Final[float]
earth_radius: Final[float]
meters_per_au: Final[float]
moon_radius: Final[float]
sun_radius: Final[float]

@disjoint_base
class Angle(float):  # type: ignore[type-var]
    def __new__(cls, *args: Unused, **kwargs: Unused) -> NoReturn: ...
    @property
    def norm(self) -> Angle: ...
    @property
    def znorm(self) -> Angle: ...

class Date(float):
    @overload
    def __new__(cls) -> Date: ...
    @overload
    def __new__(cls, date: _DateInitType, /) -> Date: ...

    def triple(self) -> tuple[int, int, float]: ...
    def tuple(self) -> tuple[int, int, int, int, int, float]: ...
    def datetime(self) -> _datetime: ...

@disjoint_base
class Observer:
    lat: _AngleDescriptorRadiansDegrees
    lon: _AngleDescriptorRadiansDegrees
    long: _AngleDescriptorRadiansDegrees
    elevation: float
    elev: float
    temp: float
    temperature: float
    pressure: float
    horizon: _AngleDescriptorRadiansDegrees
    epoch: _DateDescriptor
    date: _DateDescriptor

    def __init__(self) -> None: ...
    def sidereal_time(self) -> Angle: ...
    def radec_of(self, az: float | str, alt: float | str) -> tuple[Angle, Angle]: ...

@disjoint_base
class Body:
    @property
    def name(self) -> str | None: ...
    @property
    def a_ra(self) -> Angle: ...
    @property
    def a_dec(self) -> Angle: ...
    @property
    def a_epoch(self) -> Date: ...
    @property
    def ra(self) -> Angle: ...
    @property
    def dec(self) -> Angle: ...
    @property
    def g_ra(self) -> Angle: ...
    @property
    def g_dec(self) -> Angle: ...
    @property
    def elong(self) -> Angle: ...
    @property
    def mag(self) -> float: ...
    @property
    def size(self) -> float: ...
    @property
    def radius(self) -> Angle: ...
    @property
    def alt(self) -> Angle: ...
    @property
    def az(self) -> Angle: ...
    @property
    def ha(self) -> Angle: ...
    @property
    def rise_time(self) -> Date | None: ...
    @property
    def rise_az(self) -> Angle | None: ...
    @property
    def transit_time(self) -> Date | None: ...
    @property
    def transit_alt(self) -> Angle | None: ...
    @property
    def set_time(self) -> Date | None: ...
    @property
    def set_az(self) -> Angle | None: ...
    @property
    def circumpolar(self) -> bool: ...
    @property
    def neverup(self) -> bool: ...
    def __init__(self, *args: Unused, **kwargs: Unused) -> None: ...
    def __copy__(self) -> Self: ...

    @overload
    def compute(self, observer: Observer, /) -> None: ...
    @overload
    def compute(self, when: _DateInitType = ..., epoch: _DateInitType = ...) -> None: ...

    def copy(self) -> Self: ...
    def writedb(self) -> str: ...
    def parallactic_angle(self) -> Angle: ...

class Planet(Body):
    @property
    def hlon(self) -> Angle: ...
    @property
    def hlat(self) -> Angle: ...
    @property
    def sun_distance(self) -> float: ...
    @property
    def earth_distance(self) -> float: ...
    @property
    def phase(self) -> float: ...
    @property
    def hlong(self) -> Angle: ...

    @overload
    def __init__(self, observer: Observer, /) -> None: ...
    @overload
    def __init__(self, when: _DateInitType, /, epoch: _DateInitType = ...) -> None: ...
    @overload
    def __init__(self, *args: Unused, **kwargs: Unused) -> None: ...

@disjoint_base
class Moon(Planet):
    @property
    def libration_lat(self) -> Angle: ...
    @property
    def libration_long(self) -> Angle: ...
    @property
    def colong(self) -> Angle: ...
    @property
    def moon_phase(self) -> float: ...
    @property
    def subsolar_lat(self) -> Angle: ...

@disjoint_base
class Jupiter(Planet):
    @property
    def cmlI(self) -> Angle: ...
    @property
    def cmlII(self) -> Angle: ...

@disjoint_base
class Saturn(Planet):
    @property
    def earth_tilt(self) -> Angle: ...
    @property
    def sun_tilt(self) -> Angle: ...

@disjoint_base
class PlanetMoon:
    @property
    def name(self) -> str: ...
    @property
    def a_ra(self) -> Angle: ...
    @property
    def a_dec(self) -> Angle: ...
    @property
    def ra(self) -> Angle: ...
    @property
    def dec(self) -> Angle: ...
    @property
    def g_ra(self) -> Angle: ...
    @property
    def g_dec(self) -> Angle: ...
    @property
    def alt(self) -> Angle: ...
    @property
    def az(self) -> Angle: ...
    @property
    def x(self) -> float: ...
    @property
    def y(self) -> float: ...
    @property
    def z(self) -> float: ...
    @property
    def earth_visible(self) -> float: ...
    @property
    def sun_visible(self) -> float: ...

    @overload
    def __init__(self, observer: Observer, /) -> None: ...
    @overload
    def __init__(self, when: _DateInitType, /, epoch: _DateInitType = ...) -> None: ...
    @overload
    def __init__(self, **kwargs: Unused) -> None: ...

    def __copy__(self) -> Self: ...

    @overload
    def compute(self, observer: Observer, /) -> None: ...
    @overload
    def compute(self, when: _DateInitType = ..., epoch: _DateInitType = ...) -> None: ...

    def copy(self) -> Self: ...
    def writedb(self) -> str: ...
    def parallactic_angle(self) -> Angle: ...

class FixedBody(Body):
    name: str | None
    mag: float
    _spect: str
    _ratio: float
    _pa: _AngleDescriptorRadiansDegrees
    _epoch: _DateDescriptor
    _ra: _AngleDescriptorRadiansHours
    _dec: _AngleDescriptorRadiansDegrees
    _pmra: float
    _pmdec: float
    _class: str

    def __init__(self) -> None: ...

class EllipticalBody(Planet):
    name: str | None
    _inc: _AngleDescriptorDegreesRadians
    _Om: _AngleDescriptorDegreesRadians
    _om: _AngleDescriptorDegreesRadians
    _M: _AngleDescriptorDegreesRadians
    _epoch_M: _DateDescriptor
    _epoch: _DateDescriptor
    _H: float
    _G: float
    _g: float
    _k: float
    _a: float
    _size: float
    _e: float

    def __init__(self, *args: Unused, **kwargs: Unused) -> None: ...

class ParabolicBody(Planet):
    name: str | None
    _epoch: _DateDescriptor
    _epoch_p: _DateDescriptor
    _inc: _AngleDescriptorDegreesRadians
    _om: _AngleDescriptorDegreesRadians
    _Om: _AngleDescriptorDegreesRadians
    _q: float
    _g: float
    _k: float
    _size: float

    def __init__(self, *args: Unused, **kwargs: Unused) -> None: ...

class HyperbolicBody(Planet):
    name: str | None
    _epoch: _DateDescriptor
    _epoch_p: _DateDescriptor
    _inc: _AngleDescriptorDegreesRadians
    _Om: _AngleDescriptorDegreesRadians
    _om: _AngleDescriptorDegreesRadians
    _e: float
    _q: float
    _g: float
    _k: float
    _size: float

    def __init__(self, *args: Unused, **kwargs: Unused) -> None: ...

@disjoint_base
class EarthSatellite(Body):
    name: str | None
    epoch: _DateDescriptor
    _epoch: _DateDescriptor
    _inc: _AngleDescriptorDegreesRadians
    _raan: _AngleDescriptorDegreesRadians
    _ap: _AngleDescriptorDegreesRadians
    _M: _AngleDescriptorDegreesRadians
    n: float
    inc: float
    raan: float
    e: float
    ap: float
    M: float
    decay: float
    drag: float
    orbit: float
    _n: float
    _e: float
    _decay: float
    _drag: float
    _orbit: int
    catalog_number: str | None

    @property
    def sublat(self) -> Angle: ...
    @property
    def sublong(self) -> Angle: ...
    @property
    def elevation(self) -> float: ...
    @property
    def range(self) -> float: ...
    @property
    def range_velocity(self) -> float: ...
    @property
    def eclipsed(self) -> bool: ...

@type_check_only
class _MoonPhases(TypedDict):
    new: Date
    full: Date

def builtin_planets() -> list[tuple[int, str, str]]: ...
def degrees(angle: float | str, /) -> Angle: ...
def hours(angle: float | str, /) -> Angle: ...
def now() -> Date: ...
def separation(
    obj1: tuple[float | str, float | str] | Body | Observer, obj2: tuple[float | str, float | str] | Body | Observer, /
) -> Angle: ...
def readdb(db_line: str, /) -> Body: ...
def readtle(name: str, line1: str, line2: str, /) -> EarthSatellite: ...
def unrefract(pressure: float, temperature: float, apparent_alt: float, /) -> Angle: ...
def uranometria(ra: float | str, dec: float | str, /) -> int: ...
def uranometria2000(ra: float | str, dec: float | str, /) -> int: ...
def millennium_atlas(ra: float | str, dec: float | str, /) -> int: ...

@overload
def constellation(position: Body) -> tuple[str, str]: ...
@overload
def constellation(position: tuple[Angle | float, Angle | float], epoch: Date | float = ...) -> tuple[str, str]: ...

def julian_date(date: _DateInitType | Observer = ..., /) -> float: ...
def delta_t(date: _DateInitType | Observer = ..., /) -> float: ...
def moon_phases(date: _DateInitType | Observer = ...) -> _MoonPhases: ...
def eq_ecl(epoch: Date | float, ra: Angle | float, dec: Angle | float, /) -> tuple[Angle, Angle]: ...
def ecl_eq(epoch: Date | float, lon: Angle | float, lat: Angle | float, /) -> tuple[Angle, Angle]: ...
def eq_gal(epoch: Date | float, ra: Angle | float, dec: Angle | float, /) -> tuple[Angle, Angle]: ...
def gal_eq(epoch: Date | float, glon: Angle | float, glat: Angle | float, /) -> tuple[Angle, Angle]: ...
def precess(epoch1: Date | float, epoch2: Date | float, ra: Angle | float, dec: Angle | float, /) -> tuple[Angle, Angle]: ...
def _next_pass(
    observer: Observer, body: Body, /
) -> tuple[Date | None, Angle | None, Date | None, Angle | None, Date | None, Angle | None]: ...
