#include "tempoch_ffi.h"


#ifndef SIDERUST_FFI_H
#define SIDERUST_FFI_H

/* Warning: this file is auto-generated by cbindgen. Do not modify manually. */

#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>

// Crossing event direction.
enum siderust_crossing_direction_t
#ifdef __cplusplus
  : int32_t
#endif // __cplusplus
 {
  // The body is crossing upward through the threshold.
  SIDERUST_CROSSING_DIRECTION_T_RISING = 0,
  // The body is crossing downward through the threshold.
  SIDERUST_CROSSING_DIRECTION_T_SETTING = 1,
};
#ifndef __cplusplus
typedef int32_t siderust_crossing_direction_t;
#endif // __cplusplus

// Culmination event kind.
enum siderust_culmination_kind_t
#ifdef __cplusplus
  : int32_t
#endif // __cplusplus
 {
  // Upper culmination (maximum altitude).
  SIDERUST_CULMINATION_KIND_T_MAX = 0,
  // Lower culmination (minimum altitude).
  SIDERUST_CULMINATION_KIND_T_MIN = 1,
};
#ifndef __cplusplus
typedef int32_t siderust_culmination_kind_t;
#endif // __cplusplus

// Azimuth extremum kind (maximum or minimum bearing).
enum siderust_azimuth_extremum_kind_t
#ifdef __cplusplus
  : int32_t
#endif // __cplusplus
 {
  // Maximum azimuth (easternmost bearing).
  SIDERUST_AZIMUTH_EXTREMUM_KIND_T_MAX = 0,
  // Minimum azimuth (westernmost bearing).
  SIDERUST_AZIMUTH_EXTREMUM_KIND_T_MIN = 1,
};
#ifndef __cplusplus
typedef int32_t siderust_azimuth_extremum_kind_t;
#endif // __cplusplus

// Status codes returned by every siderust-ffi function.
//
// Callers must inspect this value before reading any output parameters.
enum siderust_status_t
#ifdef __cplusplus
  : int32_t
#endif // __cplusplus
 {
  // Success.
  SIDERUST_STATUS_T_OK = 0,
  // A required output pointer was null.
  SIDERUST_STATUS_T_NULL_POINTER = 1,
  // The requested coordinate frame is unsupported or invalid.
  SIDERUST_STATUS_T_INVALID_FRAME = 2,
  // The requested coordinate center is unsupported or invalid.
  SIDERUST_STATUS_T_INVALID_CENTER = 3,
  // Coordinate transformation failed.
  SIDERUST_STATUS_T_TRANSFORM_FAILED = 4,
  // Unknown or invalid body identifier.
  SIDERUST_STATUS_T_INVALID_BODY = 5,
  // Star name not found in the built-in catalog.
  SIDERUST_STATUS_T_UNKNOWN_STAR = 6,
  // Period bounds are invalid (start > end).
  SIDERUST_STATUS_T_INVALID_PERIOD = 7,
  // Memory allocation failed.
  SIDERUST_STATUS_T_ALLOCATION_FAILED = 8,
  // One or more arguments are out of range or otherwise invalid.
  SIDERUST_STATUS_T_INVALID_ARGUMENT = 9,
  // A Rust panic was caught at the FFI boundary.
  //
  // This should never happen in normal operation; it indicates a bug in the
  // underlying library.  The panic payload is discarded.
  SIDERUST_STATUS_T_INTERNAL_PANIC = 10,
  // A data-loading error occurred (I/O, download, integrity, or parse failure).
  //
  // Returned by runtime ephemeris functions when BSP file loading or
  // parsing fails.
  SIDERUST_STATUS_T_DATA_ERROR = 11,
  // A quantity has an incompatible physical dimension.
  //
  // Returned by qtty-aware functions when a quantity's dimension doesn't
  // match the expected type (e.g., passing a length where an angle is expected).
  SIDERUST_STATUS_T_INVALID_DIMENSION = 12,
  // A requested epoch lies outside the covered ephemeris or EOP data range.
  SIDERUST_STATUS_T_OUT_OF_RANGE = 13,
  // Required Earth Orientation Parameters are unavailable for the epoch.
  SIDERUST_STATUS_T_NO_EOP_DATA = 14,
};
#ifndef __cplusplus
typedef int32_t siderust_status_t;
#endif // __cplusplus

// Proper motion RA convention.
enum siderust_ra_convention_t
#ifdef __cplusplus
  : int32_t
#endif // __cplusplus
 {
  // True RA rate µα (deg/yr).
  SIDERUST_RA_CONVENTION_T_MU_ALPHA = 0,
  // Catalog rate µα★ = µα cos(δ) (deg/yr).
  SIDERUST_RA_CONVENTION_T_MU_ALPHA_STAR = 1,
};
#ifndef __cplusplus
typedef int32_t siderust_ra_convention_t;
#endif // __cplusplus

// Runtime Earth-orientation / nutation model preset.
enum siderust_earth_orientation_model_t
#ifdef __cplusplus
  : int32_t
#endif // __cplusplus
 {
  // Full IAU 2000A nutation.
  SIDERUST_EARTH_ORIENTATION_MODEL_T_IAU2000_A = 0,
  // Abridged IAU 2000B nutation.
  SIDERUST_EARTH_ORIENTATION_MODEL_T_IAU2000_B = 1,
  // IAU 2006 precession-only profile (no nutation terms).
  SIDERUST_EARTH_ORIENTATION_MODEL_T_IAU2006 = 2,
  // IAU 2006A high-precision default profile.
  SIDERUST_EARTH_ORIENTATION_MODEL_T_IAU2006_A = 3,
};
#ifndef __cplusplus
typedef int32_t siderust_earth_orientation_model_t;
#endif // __cplusplus

// Reference frame identifier for C interop.
enum siderust_frame_t
#ifdef __cplusplus
  : int32_t
#endif // __cplusplus
 {
  // International Celestial Reference System.
  SIDERUST_FRAME_T_ICRS = 1,
  // Mean ecliptic of J2000.0.
  SIDERUST_FRAME_T_ECLIPTIC_MEAN_J2000 = 2,
  // Mean equatorial of J2000.0.
  SIDERUST_FRAME_T_EQUATORIAL_MEAN_J2000 = 3,
  // Mean equatorial of date.
  SIDERUST_FRAME_T_EQUATORIAL_MEAN_OF_DATE = 4,
  // True equatorial of date (includes nutation).
  SIDERUST_FRAME_T_EQUATORIAL_TRUE_OF_DATE = 5,
  // Local horizontal (azimuth/altitude).
  SIDERUST_FRAME_T_HORIZONTAL = 6,
  // Earth-Centred Earth-Fixed.
  SIDERUST_FRAME_T_ECEF = 7,
  // Galactic coordinate system.
  SIDERUST_FRAME_T_GALACTIC = 8,
  // Geocentric Celestial Reference System.
  SIDERUST_FRAME_T_GCRS = 9,
  // Ecliptic of date.
  SIDERUST_FRAME_T_ECLIPTIC_OF_DATE = 10,
  // True ecliptic of date.
  SIDERUST_FRAME_T_ECLIPTIC_TRUE_OF_DATE = 11,
  // Celestial Intermediate Reference System.
  SIDERUST_FRAME_T_CIRS = 12,
  // Terrestrial Intermediate Reference System.
  SIDERUST_FRAME_T_TIRS = 13,
  // International Terrestrial Reference Frame.
  SIDERUST_FRAME_T_ITRF = 14,
  // International Celestial Reference Frame.
  SIDERUST_FRAME_T_ICRF = 15,
};
#ifndef __cplusplus
typedef int32_t siderust_frame_t;
#endif // __cplusplus

// Reference center identifier for C interop.
enum siderust_center_t
#ifdef __cplusplus
  : int32_t
#endif // __cplusplus
 {
  // Solar-system barycentre.
  SIDERUST_CENTER_T_BARYCENTRIC = 1,
  // Sun centre.
  SIDERUST_CENTER_T_HELIOCENTRIC = 2,
  // Earth centre.
  SIDERUST_CENTER_T_GEOCENTRIC = 3,
  // Observer site on the Earth's surface.
  SIDERUST_CENTER_T_TOPOCENTRIC = 4,
  // Centre of a specific body.
  SIDERUST_CENTER_T_BODYCENTRIC = 5,
};
#ifndef __cplusplus
typedef int32_t siderust_center_t;
#endif // __cplusplus

// Length unit for coordinate positions.
//
// Specifies the unit of measure for coordinate distances (x, y, z components
// in Cartesian positions, or distance in spherical positions).
enum SiderustLengthUnit
#ifdef __cplusplus
  : int32_t
#endif // __cplusplus
 {
  // Astronomical Units (≈149.6 million km).
  SIDERUST_LENGTH_UNIT_AU = 0,
  // Kilometres.
  SIDERUST_LENGTH_UNIT_KM = 1,
  // Light-years.
  SIDERUST_LENGTH_UNIT_LIGHT_YEAR = 2,
  // Parsecs.
  SIDERUST_LENGTH_UNIT_PARSEC = 3,
  // Metres.
  SIDERUST_LENGTH_UNIT_METER = 4,
};
#ifndef __cplusplus
typedef int32_t SiderustLengthUnit;
#endif // __cplusplus

// Principal lunar phase kind.
enum siderust_phase_kind_t
#ifdef __cplusplus
  : int32_t
#endif // __cplusplus
 {
  // New Moon.
  SIDERUST_PHASE_KIND_T_NEW_MOON = 0,
  // First Quarter.
  SIDERUST_PHASE_KIND_T_FIRST_QUARTER = 1,
  // Full Moon.
  SIDERUST_PHASE_KIND_T_FULL_MOON = 2,
  // Last Quarter.
  SIDERUST_PHASE_KIND_T_LAST_QUARTER = 3,
};
#ifndef __cplusplus
typedef int32_t siderust_phase_kind_t;
#endif // __cplusplus

// Named phase label (includes intermediate phases).
enum siderust_moon_phase_label_t
#ifdef __cplusplus
  : int32_t
#endif // __cplusplus
 {
  // New Moon.
  SIDERUST_MOON_PHASE_LABEL_T_NEW_MOON = 0,
  // Waxing Crescent.
  SIDERUST_MOON_PHASE_LABEL_T_WAXING_CRESCENT = 1,
  // First Quarter.
  SIDERUST_MOON_PHASE_LABEL_T_FIRST_QUARTER = 2,
  // Waxing Gibbous.
  SIDERUST_MOON_PHASE_LABEL_T_WAXING_GIBBOUS = 3,
  // Full Moon.
  SIDERUST_MOON_PHASE_LABEL_T_FULL_MOON = 4,
  // Waning Gibbous.
  SIDERUST_MOON_PHASE_LABEL_T_WANING_GIBBOUS = 5,
  // Last Quarter.
  SIDERUST_MOON_PHASE_LABEL_T_LAST_QUARTER = 6,
  // Waning Crescent.
  SIDERUST_MOON_PHASE_LABEL_T_WANING_CRESCENT = 7,
};
#ifndef __cplusplus
typedef int32_t siderust_moon_phase_label_t;
#endif // __cplusplus

// Subject kind discriminant for [`SiderustSubject`].
enum siderust_subject_kind_t
#ifdef __cplusplus
  : int32_t
#endif // __cplusplus
 {
  // Solar-system body (the `body` field is valid).
  SIDERUST_SUBJECT_KIND_T_BODY = 0,
  // Star opaque handle (the `star_handle` field is valid).
  SIDERUST_SUBJECT_KIND_T_STAR = 1,
  // Fixed ICRS direction (the `icrs_dir` field is valid).
  SIDERUST_SUBJECT_KIND_T_ICRS = 2,
  // Generic target opaque handle (the `generic_target_handle` field is valid).
  SIDERUST_SUBJECT_KIND_T_GENERIC_TARGET = 3,
};
#ifndef __cplusplus
typedef int32_t siderust_subject_kind_t;
#endif // __cplusplus

// Solar-system body identifier for generic altitude/azimuth dispatch.
//
// Each variant maps to a concrete unit type in `siderust::bodies::solar_system`.
enum SiderustBody
#ifdef __cplusplus
  : int32_t
#endif // __cplusplus
 {
  // The Sun.
  SIDERUST_BODY_SUN = 0,
  // Earth's Moon.
  SIDERUST_BODY_MOON = 1,
  // Mercury.
  SIDERUST_BODY_MERCURY = 2,
  // Venus.
  SIDERUST_BODY_VENUS = 3,
  // Mars.
  SIDERUST_BODY_MARS = 4,
  // Jupiter.
  SIDERUST_BODY_JUPITER = 5,
  // Saturn.
  SIDERUST_BODY_SATURN = 6,
  // Uranus.
  SIDERUST_BODY_URANUS = 7,
  // Neptune.
  SIDERUST_BODY_NEPTUNE = 8,
};
#ifndef __cplusplus
typedef int32_t SiderustBody;
#endif // __cplusplus

// Coordinate kind discriminant for [`SiderustTargetCoord`].
//
// Specifies which coordinate representation is stored in the target.
enum SiderustTargetCoordKind
#ifdef __cplusplus
  : int32_t
#endif // __cplusplus
 {
  // Spherical direction (RA/Dec) without distance.
  SIDERUST_TARGET_COORD_KIND_SPHERICAL_DIR = 0,
  // Spherical position with distance.
  SIDERUST_TARGET_COORD_KIND_SPHERICAL_POS = 1,
  // Cartesian position (x, y, z).
  SIDERUST_TARGET_COORD_KIND_CARTESIAN_POS = 2,
};
#ifndef __cplusplus
typedef int32_t SiderustTargetCoordKind;
#endif // __cplusplus

// Sky condition derived from the Sun's altitude.
//
// Boundaries are inclusive on the upper (brighter) side, following the
// IAU/USNO convention: the Sun exactly at `0°` is [`Civil`], exactly at
// `-6°` is [`Nautical`], etc.
//
// [`Civil`]: SiderustTwilightPhase::Civil
// [`Nautical`]: SiderustTwilightPhase::Nautical
enum siderust_twilight_phase_t
#ifdef __cplusplus
  : int32_t
#endif // __cplusplus
 {
  // Sun above the horizon: altitude > 0°.
  SIDERUST_TWILIGHT_PHASE_T_DAY = 0,
  // Civil twilight: -6° < altitude ≤ 0°.
  SIDERUST_TWILIGHT_PHASE_T_CIVIL = 1,
  // Nautical twilight: -12° < altitude ≤ -6°.
  SIDERUST_TWILIGHT_PHASE_T_NAUTICAL = 2,
  // Astronomical twilight: -18° < altitude ≤ -12°.
  SIDERUST_TWILIGHT_PHASE_T_ASTRONOMICAL = 3,
  // Full darkness: altitude ≤ -18°.
  SIDERUST_TWILIGHT_PHASE_T_DARK = 4,
};
#ifndef __cplusplus
typedef int32_t siderust_twilight_phase_t;
#endif // __cplusplus

// Opaque FFI context used by model-sensitive transform entry points.
typedef struct siderust_context_t siderust_context_t;

// Opaque handle representing a generic celestial target.
//
// This mirrors Rust's `CoordinateWithPM<T>`, supporting:
// - direction-only coordinates,
// - spherical positions with distance metadata,
// - cartesian positions with frame/center/unit metadata,
// - and optional proper motion payloads.
typedef struct SiderustGenericTarget SiderustGenericTarget;

// Opaque handle to a `RuntimeEphemeris`.
//
// Created via `siderust_runtime_ephemeris_load_bsp`, `_load_bytes`, or
// `_ensure`. Must be freed with `siderust_runtime_ephemeris_free`.
typedef struct siderust_runtime_ephemeris_t siderust_runtime_ephemeris_t;

// Opaque handle to a Star. Created via `siderust_star_*` functions, freed
// with `siderust_star_free`.
typedef struct SiderustStar SiderustStar;

// A threshold-crossing event.
typedef struct siderust_crossing_event_t {
  // Time of the crossing (Modified Julian Date).
  double mjd;
  // Direction of the crossing.
  siderust_crossing_direction_t direction;
} siderust_crossing_event_t;

// A culmination (local extremum in altitude) event.
typedef struct siderust_culmination_event_t {
  // Time of the culmination (Modified Julian Date).
  double mjd;
  // Altitude at the extremum in degrees.
  double altitude_deg;
  // Kind of extremum.
  siderust_culmination_kind_t kind;
} siderust_culmination_event_t;

// An azimuth bearing-crossing event.
typedef struct siderust_azimuth_crossing_event_t {
  // Time of the event (Modified Julian Date).
  double mjd;
  // Crossing direction.
  siderust_crossing_direction_t direction;
  // Padding bytes for alignment; must be zeroed.
  uint8_t _pad[4];
} siderust_azimuth_crossing_event_t;

// An azimuth extremum (minimum or maximum bearing).
typedef struct siderust_azimuth_extremum_t {
  // Time of the extremum (Modified Julian Date).
  double mjd;
  // Azimuth at the extremum, in degrees.
  double azimuth_deg;
  // Kind of extremum.
  siderust_azimuth_extremum_kind_t kind;
  // Padding bytes for alignment; must be zeroed.
  uint8_t _pad[4];
} siderust_azimuth_extremum_t;

// Proper motion of a star (equatorial).
typedef struct siderust_proper_motion_t {
  // RA proper motion in degrees per Julian year.
  double pm_ra_deg_yr;
  // Dec proper motion in degrees per Julian year.
  double pm_dec_deg_yr;
  // Convention for `pm_ra`.
  siderust_ra_convention_t ra_convention;
} siderust_proper_motion_t;

// Keplerian orbital elements.
typedef struct siderust_orbit_t {
  // Semi-major axis in astronomical units.
  double semi_major_axis_au;
  // Orbital eccentricity.
  double eccentricity;
  // Orbital inclination in degrees.
  double inclination_deg;
  // Longitude of the ascending node in degrees.
  double lon_ascending_node_deg;
  // Argument of periapsis in degrees.
  double arg_periapsis_deg;
  // Mean anomaly at epoch in degrees.
  double mean_anomaly_deg;
  // Epoch as a Julian Date.
  double epoch_jd;
} siderust_orbit_t;

// Planet data (value type, copyable).
typedef struct siderust_planet_t {
  // Planet mass in kilograms.
  double mass_kg;
  // Mean equatorial radius in kilometres.
  double radius_km;
  // Keplerian orbital elements.
  struct siderust_orbit_t orbit;
} siderust_planet_t;

// Spherical direction (lon/lat or RA/Dec) in degrees.
typedef struct siderust_spherical_dir_t {
  // Polar angle / latitude in degrees.
  double polar_deg;
  // Azimuth / longitude / right ascension in degrees.
  double azimuth_deg;
  // Reference frame.
  siderust_frame_t frame;
} siderust_spherical_dir_t;

// Geodetic position (WGS84) for C interop.
typedef struct siderust_geodetic_t {
  // Longitude in degrees (east positive).
  double lon_deg;
  // Latitude in degrees (north positive).
  double lat_deg;
  // Height above ellipsoid in metres.
  double height_m;
} siderust_geodetic_t;

// Cartesian position (x, y, z + metadata).
typedef struct siderust_cartesian_pos_t {
  // X coordinate in the specified length unit.
  double x;
  // Y coordinate in the specified length unit.
  double y;
  // Z coordinate in the specified length unit.
  double z;
  // Reference frame.
  siderust_frame_t frame;
  // Reference centre.
  siderust_center_t center;
  // Length unit for x, y, z coordinates.
  SiderustLengthUnit length_unit;
} siderust_cartesian_pos_t;

// Bodycentric reference center: which standard center the orbit is relative to.
// Must match `OrbitReferenceCenter` in siderust: Barycentric=0, Heliocentric=1, Geocentric=2.
typedef uint8_t SiderustOrbitRefCenter;

// Mean-motion-driven elliptic orbital elements.
typedef struct siderust_mean_motion_orbit_t {
  // Semi-major axis in astronomical units.
  double semi_major_axis_au;
  // Orbital eccentricity.
  double eccentricity;
  // Orbital inclination in degrees.
  double inclination_deg;
  // Longitude of the ascending node in degrees.
  double lon_ascending_node_deg;
  // Argument of periapsis in degrees.
  double arg_periapsis_deg;
  // Mean motion in degrees per day.
  double mean_motion_deg_per_day;
  // Epoch as a Julian Date. Mean anomaly is defined to be zero at this epoch.
  double epoch_jd;
} siderust_mean_motion_orbit_t;

// Unified conic elements expressed using periapsis distance.
typedef struct siderust_conic_orbit_t {
  // Periapsis distance in astronomical units.
  double periapsis_distance_au;
  // Orbital eccentricity.
  double eccentricity;
  // Orbital inclination in degrees.
  double inclination_deg;
  // Longitude of the ascending node in degrees.
  double lon_ascending_node_deg;
  // Argument of periapsis in degrees.
  double arg_periapsis_deg;
  // Mean anomaly at epoch in degrees.
  double mean_anomaly_deg;
  // Epoch as a Julian Date.
  double epoch_jd;
} siderust_conic_orbit_t;

// Opaque handle to a validated, precomputed Keplerian orbit.
//
// Created via [`siderust_prepared_orbit_create`], used for repeated
// propagation via [`siderust_prepared_orbit_position`], and freed via
// [`siderust_prepared_orbit_destroy`].
//
// This avoids per-call reconstruction, validation, and trig precomputation
// when propagating the same orbit at many epochs.
typedef void *SiderustPreparedOrbitHandle;

// Parameters for a body-centric coordinate system.
//
// Pairs Keplerian orbital elements with the reference center of those elements.
// Corresponds to `siderust::coordinates::centers::BodycentricParams`.
typedef struct SiderustBodycentricParams {
  // Keplerian orbital elements of the body.
  struct siderust_orbit_t orbit;
  // Reference center: 0=Barycentric, 1=Heliocentric, 2=Geocentric.
  SiderustOrbitRefCenter orbit_center;
  // Padding bytes for alignment; must be zeroed.
  uint8_t _pad[7];
} SiderustBodycentricParams;

// A principal lunar phase event.
typedef struct siderust_phase_event_t {
  // Time of the event (Modified Julian Date).
  double mjd;
  // Phase kind.
  siderust_phase_kind_t kind;
  // Padding bytes for alignment; must be zeroed.
  uint8_t _pad[4];
} siderust_phase_event_t;

// Moon phase geometry at a given instant.
typedef struct siderust_moon_phase_geometry_t {
  // Phase angle in radians.
  double phase_angle_rad;
  // Fraction of the Moon's disk that is illuminated (0–1).
  double illuminated_fraction;
  // Elongation in radians.
  double elongation_rad;
  // Non-zero if waxing, zero if waning.
  uint8_t waxing;
  // Padding bytes for alignment; must be zeroed.
  uint8_t _pad[7];
} siderust_moon_phase_geometry_t;

// Search options for altitude computations.
typedef struct siderust_search_opts_t {
  // Time tolerance in days (default: ~1 µs = 1e-9 days).
  double time_tolerance_days;
  // Scan step in days. Set to 0 or negative to use the body's default.
  double scan_step_days;
  // Whether `scan_step_days` is valid (non-zero).
  bool has_scan_step;
} siderust_search_opts_t;

// Cartesian velocity (vx, vy, vz + frame metadata).
typedef struct siderust_cartesian_vel_t {
  // X velocity component (AU/day).
  double vx;
  // Y velocity component (AU/day).
  double vy;
  // Z velocity component (AU/day).
  double vz;
  // Reference frame.
  siderust_frame_t frame;
} siderust_cartesian_vel_t;

// Unified subject for altitude / azimuth / tracking computations.
//
// A tagged struct that can represent any entity on which altitude and
// azimuth queries can be performed: solar-system bodies, catalog stars,
// fixed ICRS directions, or generic target handles.
//
// Only the field corresponding to `kind` is valid:
//
// | `kind`           | Valid field(s)           |
// |------------------|--------------------------|
// | `Body`           | `body`                   |
// | `Star`           | `star_handle`            |
// | `Icrs`           | `icrs_dir`               |
// | `GenericTarget`  | `generic_target_handle`  |
typedef struct siderust_subject_t {
  // Discriminant selecting which field is active.
  siderust_subject_kind_t kind;
  // Solar-system body discriminant.  Valid when `kind == Body`.
  SiderustBody body;
  // Opaque star handle (non-null).  Valid when `kind == Star`.
  const struct SiderustStar *star_handle;
  // ICRS spherical direction.  Valid when `kind == Icrs`.
  struct siderust_spherical_dir_t icrs_dir;
  // Opaque generic target handle.  Valid when `kind == GenericTarget`.
  const struct SiderustGenericTarget *generic_target_handle;
} siderust_subject_t;

// Altitude computation query parameters.
typedef struct siderust_altitude_query_t {
  // Observer location.
  struct siderust_geodetic_t observer;
  // Start of the search window (Modified Julian Date).
  double start_mjd;
  // End of the search window (Modified Julian Date).
  double end_mjd;
  // Minimum altitude threshold in degrees.
  double min_altitude_deg;
  // Maximum altitude threshold in degrees.
  double max_altitude_deg;
} siderust_altitude_query_t;

// Spherical position (direction + distance).
typedef struct siderust_spherical_pos_t {
  // Longitude in degrees.
  double lon_deg;
  // Latitude in degrees.
  double lat_deg;
  // Distance in the unit appropriate for the context (AU, km, ly, etc.).
  double distance;
  // Reference frame.
  siderust_frame_t frame;
  // Reference centre.
  siderust_center_t center;
  // Length unit for the distance component.
  SiderustLengthUnit length_unit;
} siderust_spherical_pos_t;

// Union of coordinate types for [`SiderustGenericTargetData`].
//
// Callers must check `kind` to determine which field is valid.
// Only the field corresponding to `kind` contains valid data:
//
// | `kind`        | Valid field    |
// |---------------|----------------|
// | `SphericalDir`| `spherical_dir`|
// | `SphericalPos`| `spherical_pos`|
// | `CartesianPos`| `cartesian_pos`|
typedef union SiderustTargetCoordUnion {
  // Spherical direction (valid when kind == SphericalDir).
  struct siderust_spherical_dir_t spherical_dir;
  // Spherical position (valid when kind == SphericalPos).
  struct siderust_spherical_pos_t spherical_pos;
  // Cartesian position (valid when kind == CartesianPos).
  struct siderust_cartesian_pos_t cartesian_pos;
} SiderustTargetCoordUnion;

// Generic target data, stored as a flat struct for FFI.
//
// Represents a point in celestial coordinates at a specific epoch,
// optionally with proper motion. This struct mirrors the Rust
// `CoordinateWithPM<T>` type but in a C-compatible form.
typedef struct SiderustGenericTargetData {
  // Which coordinate representation is stored.
  SiderustTargetCoordKind kind;
  // Padding for alignment.
  uint8_t _pad1[4];
  // The coordinate data (union, check `kind` to determine which field).
  union SiderustTargetCoordUnion coord;
  // Epoch as a Julian Date.
  double epoch_jd;
  // Whether proper motion is present.
  bool has_proper_motion;
  // Padding for alignment.
  uint8_t _pad2[7];
  // Proper motion (valid only when `has_proper_motion` is true).
  struct siderust_proper_motion_t proper_motion;
} SiderustGenericTargetData;

#ifdef __cplusplus
extern "C" {
#endif // __cplusplus

// Returns the siderust-ffi ABI version (major*10000 + minor*100 + patch).
 uint32_t siderust_ffi_version(void);

// Free an array of MJD periods.
//
// # Safety
//
// * `ptr` must have been returned by a siderust FFI function that allocates
//   `TempochPeriodMjd` arrays.
// * `count` must be the element count returned alongside `ptr`.
// * The pointer must not have been freed before, and must not be used after
//   this call.
 void siderust_periods_free(tempoch_period_mjd_t *ptr, uintptr_t count);

// Free an array of crossing events.
//
// # Safety
//
// * `ptr` must have been returned by a siderust FFI function that allocates
//   `SiderustCrossingEvent` arrays.
// * `count` must be the element count returned alongside `ptr`.
// * The pointer must not have been freed before, and must not be used after
//   this call.
 void siderust_crossings_free(struct siderust_crossing_event_t *ptr, uintptr_t count);

// Free an array of culmination events.
//
// # Safety
//
// * `ptr` must have been returned by a siderust FFI function that allocates
//   `SiderustCulminationEvent` arrays.
// * `count` must be the element count returned alongside `ptr`.
// * The pointer must not have been freed before, and must not be used after
//   this call.
 void siderust_culminations_free(struct siderust_culmination_event_t *ptr, uintptr_t count);

// Free an array of azimuth crossing events.
//
// # Safety
//
// * `ptr` must have been returned by a siderust FFI function that allocates
//   `SiderustAzimuthCrossingEvent` arrays.
// * `count` must be the element count returned alongside `ptr`.
// * The pointer must not have been freed before, and must not be used after
//   this call.

void siderust_azimuth_crossings_free(struct siderust_azimuth_crossing_event_t *ptr,
                                     uintptr_t count);

// Free an array of azimuth extrema.
//
// # Safety
//
// * `ptr` must have been returned by a siderust FFI function that allocates
//   `SiderustAzimuthExtremum` arrays.
// * `count` must be the element count returned alongside `ptr`.
// * The pointer must not have been freed before, and must not be used after
//   this call.
 void siderust_azimuth_extrema_free(struct siderust_azimuth_extremum_t *ptr, uintptr_t count);

// Look up a star from the built-in catalog by name.
//
// Supported names: "VEGA", "SIRIUS", "POLARIS", "CANOPUS", "ARCTURUS",
// "RIGEL", "BETELGEUSE", "PROCYON", "ALDEBARAN", "ALTAIR".
//
// On success, `*out` receives a newly allocated handle.
// The caller must free it with `siderust_star_free`.
 siderust_status_t siderust_star_catalog(const char *name, struct SiderustStar **out);

// Create a custom star.
//
// `name`, UTF-8 null-terminated string.
// `ra_deg`, `dec_deg`, J2000 equatorial coordinates in degrees.
// `distance_ly`, distance in light-years.
// `epoch_jd`, epoch of the given coordinates (Julian Date).
// `proper_motion`, optional: pass null for a fixed star.

siderust_status_t siderust_star_create(const char *name,
                                       double distance_ly,
                                       double mass_solar,
                                       double radius_solar,
                                       double luminosity_solar,
                                       double ra_deg,
                                       double dec_deg,
                                       double epoch_jd,
                                       const struct siderust_proper_motion_t *proper_motion,
                                       struct SiderustStar **out);

// Free a Star handle.
//
// # Safety
// The handle must have been allocated by `siderust_star_catalog` or
// `siderust_star_create`, and must not be used after this call.
 void siderust_star_free(struct SiderustStar *handle);

// Get the star's name. Copies into `buf` up to `buf_len` bytes (including NUL).
// Sets `*written` to the number of bytes written (excluding NUL).
// Returns InvalidArgument if the buffer is too small.

siderust_status_t siderust_star_name(const struct SiderustStar *handle,
                                     char *buf,
                                     uintptr_t buf_len,
                                     uintptr_t *written);

// Get the star's distance in light-years.
 double siderust_star_distance_ly(const struct SiderustStar *handle);

// Get the star's mass in solar masses.
 double siderust_star_mass_solar(const struct SiderustStar *handle);

// Get the star's radius in solar radii.
 double siderust_star_radius_solar(const struct SiderustStar *handle);

// Get the star's luminosity in solar luminosities.
 double siderust_star_luminosity_solar(const struct SiderustStar *handle);

// Get Mercury's orbital and physical parameters.
 siderust_status_t siderust_planet_mercury(struct siderust_planet_t *out);

// Get Venus's orbital and physical parameters.
 siderust_status_t siderust_planet_venus(struct siderust_planet_t *out);

// Get Earth's orbital and physical parameters.
 siderust_status_t siderust_planet_earth(struct siderust_planet_t *out);

// Get Mars's orbital and physical parameters.
 siderust_status_t siderust_planet_mars(struct siderust_planet_t *out);

// Get Jupiter's orbital and physical parameters.
 siderust_status_t siderust_planet_jupiter(struct siderust_planet_t *out);

// Get Saturn's orbital and physical parameters.
 siderust_status_t siderust_planet_saturn(struct siderust_planet_t *out);

// Get Uranus's orbital and physical parameters.
 siderust_status_t siderust_planet_uranus(struct siderust_planet_t *out);

// Get Neptune's orbital and physical parameters.
 siderust_status_t siderust_planet_neptune(struct siderust_planet_t *out);

// Create a context using the default siderust transform model.
 siderust_status_t siderust_context_create_default(struct siderust_context_t **out);

// Create a context with an explicit Earth-orientation model preset.

siderust_status_t siderust_context_create_with_model(siderust_earth_orientation_model_t model,
                                                     struct siderust_context_t **out);

// Free a context handle previously returned by `siderust_context_create_*`.
//
// # Safety
// `handle` must be either null or a live pointer produced by this crate.
 void siderust_context_free(struct siderust_context_t *handle);

// Retrieve the model preset stored in a context handle.

siderust_status_t siderust_context_get_model(const struct siderust_context_t *handle,
                                             siderust_earth_orientation_model_t *out);

// Transform a spherical direction from one frame to another.
//
// `jd` is required for time-dependent frames (mean/true of date, horizontal).
// For time-independent transforms between fixed-epoch frames, the JD value
// is ignored but must still be provided.
//
// Supported source/target frames: ICRS, EclipticMeanJ2000, EquatorialMeanJ2000,
// EquatorialMeanOfDate, EquatorialTrueOfDate.
//
// For conversion to Horizontal, use `siderust_spherical_dir_to_horizontal`.

siderust_status_t siderust_spherical_dir_transform_frame(double polar_deg,
                                                         double azimuth_deg,
                                                         siderust_frame_t src_frame,
                                                         siderust_frame_t dst_frame,
                                                         double jd,
                                                         struct siderust_spherical_dir_t *out);

// Transform a spherical direction using an explicit transform context.

siderust_status_t siderust_spherical_dir_transform_frame_with_context(double polar_deg,
                                                                      double azimuth_deg,
                                                                      siderust_frame_t src_frame,
                                                                      siderust_frame_t dst_frame,
                                                                      double jd,
                                                                      const struct siderust_context_t *context,
                                                                      struct siderust_spherical_dir_t *out);

// Transform a spherical direction to the horizontal (alt-az) frame.
//
// Requires an observer location (geodetic WGS84) and a Julian Date.
// Supported source frames: ICRS, EclipticMeanJ2000, EquatorialMeanJ2000,
// EquatorialMeanOfDate, EquatorialTrueOfDate.

siderust_status_t siderust_spherical_dir_to_horizontal(double polar_deg,
                                                       double azimuth_deg,
                                                       siderust_frame_t src_frame,
                                                       double jd,
                                                       struct siderust_geodetic_t observer,
                                                       struct siderust_spherical_dir_t *out);

// Convert a spherical direction to horizontal coordinates using explicit TT and UT1.

siderust_status_t siderust_spherical_dir_to_horizontal_precise(double polar_deg,
                                                               double azimuth_deg,
                                                               siderust_frame_t src_frame,
                                                               double jd_tt,
                                                               double jd_ut1,
                                                               struct siderust_geodetic_t observer,
                                                               struct siderust_spherical_dir_t *out);

// Convert a spherical direction to horizontal coordinates using an explicit
// transform context plus explicit TT and UT1.

siderust_status_t siderust_spherical_dir_to_horizontal_precise_with_context(double polar_deg,
                                                                            double azimuth_deg,
                                                                            siderust_frame_t src_frame,
                                                                            double jd_tt,
                                                                            double jd_ut1,
                                                                            struct siderust_geodetic_t observer,
                                                                            const struct siderust_context_t *context,
                                                                            struct siderust_spherical_dir_t *out);

// Transform a Cartesian unit-vector direction from one frame to another.
//
// The input (x, y, z) need not be normalised; the rotation preserves the
// vector length, so the output has the same magnitude as the input.
//
// Supported source/target frames: ICRS, EclipticMeanJ2000, EquatorialMeanJ2000,
// EquatorialMeanOfDate, EquatorialTrueOfDate.

siderust_status_t siderust_cartesian_dir_transform_frame(double x,
                                                         double y,
                                                         double z,
                                                         siderust_frame_t src_frame,
                                                         siderust_frame_t dst_frame,
                                                         double jd,
                                                         struct siderust_cartesian_pos_t *out);

// Transform a Cartesian direction using an explicit transform context.

siderust_status_t siderust_cartesian_dir_transform_frame_with_context(double x,
                                                                      double y,
                                                                      double z,
                                                                      siderust_frame_t src_frame,
                                                                      siderust_frame_t dst_frame,
                                                                      double jd,
                                                                      const struct siderust_context_t *context,
                                                                      struct siderust_cartesian_pos_t *out);

// Transform a Cartesian position from one frame to another (frame-only, same center).
//
// The rotation preserves the vector magnitude.  The `center` field of `pos`
// is copied unchanged to `out`.
//
// Supported source/target frames: ICRS, EclipticMeanJ2000, EquatorialMeanJ2000,
// EquatorialMeanOfDate, EquatorialTrueOfDate.

siderust_status_t siderust_cartesian_pos_transform_frame(struct siderust_cartesian_pos_t pos,
                                                         siderust_frame_t dst_frame,
                                                         double jd,
                                                         struct siderust_cartesian_pos_t *out);

// Transform a Cartesian position using an explicit transform context.

siderust_status_t siderust_cartesian_pos_transform_frame_with_context(struct siderust_cartesian_pos_t pos,
                                                                      siderust_frame_t dst_frame,
                                                                      double jd,
                                                                      const struct siderust_context_t *context,
                                                                      struct siderust_cartesian_pos_t *out);

// Create a geodetic position and convert to ECEF Cartesian.

siderust_status_t siderust_geodetic_to_cartesian_ecef(struct siderust_geodetic_t geodetic,
                                                      struct siderust_cartesian_pos_t *out);

// Transform a Cartesian position from one reference center to another
// (frame-only, same frame).
//
// Only works for EclipticMeanJ2000 frame positions.  The input frame must
// already be EclipticMeanJ2000; this function performs only the center shift.
//
// Supported centers: Barycentric, Heliocentric, Geocentric.

siderust_status_t siderust_cartesian_pos_transform_center(struct siderust_cartesian_pos_t pos,
                                                          siderust_center_t dst_center,
                                                          double jd,
                                                          struct siderust_cartesian_pos_t *out);

// Compute the Keplerian orbital position at a given Julian date, with
// explicit output center semantics.
//
// `orbit_center` specifies which reference center the orbit elements are
// relative to (0=Barycentric, 1=Heliocentric, 2=Geocentric). The `center`
// field of `out` will be set accordingly.

siderust_status_t siderust_kepler_position_ex(struct siderust_orbit_t orbit,
                                              SiderustOrbitRefCenter orbit_center,
                                              double jd,
                                              struct siderust_cartesian_pos_t *out);

// Compute the position of an explicit mean-motion orbit at a given Julian date.

siderust_status_t siderust_mean_motion_position(struct siderust_mean_motion_orbit_t orbit,
                                                double jd,
                                                struct siderust_cartesian_pos_t *out);

// Compute the position of a unified conic orbit at a given Julian date.

siderust_status_t siderust_conic_position(struct siderust_conic_orbit_t orbit,
                                          double jd,
                                          struct siderust_cartesian_pos_t *out);

// Create a validated, precomputed orbit handle from Keplerian elements.
//
// Returns `Ok` and writes a non-null handle on success. Returns
// `InvalidArgument` if the orbit is not a valid ellipse.

siderust_status_t siderust_prepared_orbit_create(struct siderust_orbit_t orbit,
                                                 SiderustPreparedOrbitHandle *out);

// Propagate a prepared orbit to a given Julian date.
//
// `handle` must have been created via [`siderust_prepared_orbit_create`].
// This is the fastest FFI propagation path: no validation, no reconstruction.

siderust_status_t siderust_prepared_orbit_position(SiderustPreparedOrbitHandle handle,
                                                   double jd,
                                                   struct siderust_cartesian_pos_t *out);

// Destroy a prepared orbit handle, freeing its memory.
//
// After this call, `handle` must not be used again.
 siderust_status_t siderust_prepared_orbit_destroy(SiderustPreparedOrbitHandle handle);

// Transform a Cartesian position to body-centric coordinates.
//
// Mirrors Rust's `ToBodycentricExt::to_bodycentric()`.
//
// `pos`    – source position in EclipticMeanJ2000 / AU.  Center must be
//            Geocentric, Heliocentric, or Barycentric.
// `params` – Keplerian orbit + reference center of the body.
// `jd`     – Julian Date for Keplerian propagation and center-shift.
// `out`    – relative position in EclipticMeanJ2000 / AU with center Bodycentric.

siderust_status_t siderust_to_bodycentric(struct siderust_cartesian_pos_t pos,
                                          struct SiderustBodycentricParams params,
                                          double jd,
                                          struct siderust_cartesian_pos_t *out);

// Transform a body-centric position back to geocentric coordinates.
//
// Mirrors Rust's `FromBodycentricExt::to_geocentric()`.
//
// `pos`    – body-centric position in EclipticMeanJ2000 / AU.
// `params` – same orbital parameters used during `siderust_to_bodycentric`.
// `jd`     – same Julian Date used during `siderust_to_bodycentric`.
// `out`    – recovered geocentric position in EclipticMeanJ2000 / AU.

siderust_status_t siderust_from_bodycentric(struct siderust_cartesian_pos_t pos,
                                            struct SiderustBodycentricParams params,
                                            double jd,
                                            struct siderust_cartesian_pos_t *out);

// Get the Sun's barycentric position (EclipticMeanJ2000, AU) via VSOP87.
 siderust_status_t siderust_vsop87_sun_barycentric(double jd, struct siderust_cartesian_pos_t *out);

// Get the Earth's barycentric position (EclipticMeanJ2000, AU) via VSOP87.

siderust_status_t siderust_vsop87_earth_barycentric(double jd,
                                                    struct siderust_cartesian_pos_t *out);

// Get the Earth's heliocentric position (EclipticMeanJ2000, AU) via VSOP87.

siderust_status_t siderust_vsop87_earth_heliocentric(double jd,
                                                     struct siderust_cartesian_pos_t *out);

// Get Mars's heliocentric position (EclipticMeanJ2000, AU) via VSOP87.

siderust_status_t siderust_vsop87_mars_heliocentric(double jd,
                                                    struct siderust_cartesian_pos_t *out);

// Get Mars's barycentric position (EclipticMeanJ2000, AU) via VSOP87.

siderust_status_t siderust_vsop87_mars_barycentric(double jd,
                                                   struct siderust_cartesian_pos_t *out);

// Get Venus's heliocentric position (EclipticMeanJ2000, AU) via VSOP87.

siderust_status_t siderust_vsop87_venus_heliocentric(double jd,
                                                     struct siderust_cartesian_pos_t *out);

// Get Mercury's heliocentric position (EclipticMeanJ2000, AU) via VSOP87.

siderust_status_t siderust_vsop87_mercury_heliocentric(double jd,
                                                       struct siderust_cartesian_pos_t *out);

// Get Mercury's barycentric position (EclipticMeanJ2000, AU) via VSOP87.

siderust_status_t siderust_vsop87_mercury_barycentric(double jd,
                                                      struct siderust_cartesian_pos_t *out);

// Venus barycentric VSOP87.

siderust_status_t siderust_vsop87_venus_barycentric(double jd,
                                                    struct siderust_cartesian_pos_t *out);

// Get Jupiter's heliocentric position (EclipticMeanJ2000, AU) via VSOP87.

siderust_status_t siderust_vsop87_jupiter_heliocentric(double jd,
                                                       struct siderust_cartesian_pos_t *out);

// Get Jupiter's barycentric position (EclipticMeanJ2000, AU) via VSOP87.

siderust_status_t siderust_vsop87_jupiter_barycentric(double jd,
                                                      struct siderust_cartesian_pos_t *out);

// Get Saturn's heliocentric position (EclipticMeanJ2000, AU) via VSOP87.

siderust_status_t siderust_vsop87_saturn_heliocentric(double jd,
                                                      struct siderust_cartesian_pos_t *out);

// Get Saturn's barycentric position (EclipticMeanJ2000, AU) via VSOP87.

siderust_status_t siderust_vsop87_saturn_barycentric(double jd,
                                                     struct siderust_cartesian_pos_t *out);

// Get Uranus's heliocentric position (EclipticMeanJ2000, AU) via VSOP87.

siderust_status_t siderust_vsop87_uranus_heliocentric(double jd,
                                                      struct siderust_cartesian_pos_t *out);

// Get Uranus's barycentric position (EclipticMeanJ2000, AU) via VSOP87.

siderust_status_t siderust_vsop87_uranus_barycentric(double jd,
                                                     struct siderust_cartesian_pos_t *out);

// Get Neptune's heliocentric position (EclipticMeanJ2000, AU) via VSOP87.

siderust_status_t siderust_vsop87_neptune_heliocentric(double jd,
                                                       struct siderust_cartesian_pos_t *out);

// Get Neptune's barycentric position (EclipticMeanJ2000, AU) via VSOP87.

siderust_status_t siderust_vsop87_neptune_barycentric(double jd,
                                                      struct siderust_cartesian_pos_t *out);

// Get the Moon's geocentric position (EclipticMeanJ2000, km) via ELP2000.
 siderust_status_t siderust_vsop87_moon_geocentric(double jd, struct siderust_cartesian_pos_t *out);

// Fill `out` with the Roque de los Muchachos observatory (La Palma, Spain).
 siderust_status_t siderust_observatory_roque_de_los_muchachos(struct siderust_geodetic_t *out);

// Fill `out` with the El Paranal observatory (Chile).
 siderust_status_t siderust_observatory_el_paranal(struct siderust_geodetic_t *out);

// Fill `out` with the Mauna Kea observatory (Hawaiʻi, USA).
 siderust_status_t siderust_observatory_mauna_kea(struct siderust_geodetic_t *out);

// Fill `out` with the La Silla observatory (Chile).
 siderust_status_t siderust_observatory_la_silla(struct siderust_geodetic_t *out);

// Create a custom geodetic position (WGS84/ECEF).

siderust_status_t siderust_geodetic_new(double lon_deg,
                                        double lat_deg,
                                        double height_m,
                                        struct siderust_geodetic_t *out);

// Free an array of phase events.
//
// # Safety
//
// * `ptr` must have been returned by `siderust_moon_phase_events`.
// * `count` must be the element count that was returned alongside `ptr`.
// * The pointer must not have been freed before, and must not be used after
//   this call.
 void siderust_phase_events_free(struct siderust_phase_event_t *ptr, uintptr_t count);

// Compute geocentric Moon phase geometry at `jd` (Julian Date).

siderust_status_t siderust_moon_phase_geocentric(double jd,
                                                 struct siderust_moon_phase_geometry_t *out);

// Compute topocentric Moon phase geometry at `jd` for `observer`.

siderust_status_t siderust_moon_phase_topocentric(double jd,
                                                  struct siderust_geodetic_t observer,
                                                  struct siderust_moon_phase_geometry_t *out);

// Map phase geometry to a named phase label.

siderust_status_t siderust_moon_phase_label(struct siderust_moon_phase_geometry_t geom,
                                            siderust_moon_phase_label_t *out);

// Find all principal lunar phase events in `window`.
//
// Results are sorted chronologically. The caller must free the array
// with [`siderust_phase_events_free`].

siderust_status_t siderust_find_phase_events(tempoch_period_mjd_t window,
                                             struct siderust_search_opts_t opts,
                                             struct siderust_phase_event_t **out,
                                             uintptr_t *count);

// Find windows where geocentric Moon illumination is above `k_min` ∈ [0,1].

siderust_status_t siderust_moon_illumination_above(tempoch_period_mjd_t window,
                                                   double k_min,
                                                   struct siderust_search_opts_t opts,
                                                   tempoch_period_mjd_t **out,
                                                   uintptr_t *count);

// Find windows where geocentric Moon illumination is below `k_max` ∈ [0,1].

siderust_status_t siderust_moon_illumination_below(tempoch_period_mjd_t window,
                                                   double k_max,
                                                   struct siderust_search_opts_t opts,
                                                   tempoch_period_mjd_t **out,
                                                   uintptr_t *count);

// Find windows where Moon illumination is within [k_min, k_max].

siderust_status_t siderust_moon_illumination_range(tempoch_period_mjd_t window,
                                                   double k_min,
                                                   double k_max,
                                                   struct siderust_search_opts_t opts,
                                                   tempoch_period_mjd_t **out,
                                                   uintptr_t *count);

// Load a runtime ephemeris from a BSP file on disk.
//
// `path` must be a valid, NUL-terminated UTF-8 path to a JPL DE4xx BSP file.
// On success, `*out` receives a newly allocated handle that must be freed
// with `siderust_runtime_ephemeris_free`.

siderust_status_t siderust_runtime_ephemeris_load_bsp(const char *path,
                                                      struct siderust_runtime_ephemeris_t **out);

// Load a runtime ephemeris from raw BSP bytes already in memory.
//
// `data` must point to `len` bytes of a valid JPL DE4xx BSP file.
// On success, `*out` receives a newly allocated handle.

siderust_status_t siderust_runtime_ephemeris_load_bytes(const uint8_t *data,
                                                        uintptr_t len,
                                                        struct siderust_runtime_ephemeris_t **out);

// Free a `SiderustRuntimeEphemeris` handle.
//
// # Safety
//
// The handle must have been allocated by one of the `siderust_runtime_ephemeris_*`
// constructors, and must not be used after this call.
 void siderust_runtime_ephemeris_free(struct siderust_runtime_ephemeris_t *handle);

// Sun's barycentric position (EclipticMeanJ2000, AU) via the runtime ephemeris.

siderust_status_t siderust_runtime_ephemeris_sun_barycentric(const struct siderust_runtime_ephemeris_t *handle,
                                                             double jd,
                                                             struct siderust_cartesian_pos_t *out);

// Earth's barycentric position (EclipticMeanJ2000, AU) via the runtime ephemeris.

siderust_status_t siderust_runtime_ephemeris_earth_barycentric(const struct siderust_runtime_ephemeris_t *handle,
                                                               double jd,
                                                               struct siderust_cartesian_pos_t *out);

// Earth's heliocentric position (EclipticMeanJ2000, AU) via the runtime ephemeris.

siderust_status_t siderust_runtime_ephemeris_earth_heliocentric(const struct siderust_runtime_ephemeris_t *handle,
                                                                double jd,
                                                                struct siderust_cartesian_pos_t *out);

// Earth's barycentric velocity (EclipticMeanJ2000, AU/day) via the runtime ephemeris.

siderust_status_t siderust_runtime_ephemeris_earth_barycentric_velocity(const struct siderust_runtime_ephemeris_t *handle,
                                                                        double jd,
                                                                        struct siderust_cartesian_vel_t *out);

// Moon's geocentric position (EclipticMeanJ2000, km) via the runtime ephemeris.

siderust_status_t siderust_runtime_ephemeris_moon_geocentric(const struct siderust_runtime_ephemeris_t *handle,
                                                             double jd,
                                                             struct siderust_cartesian_pos_t *out);

// Altitude of any subject at an instant (radians).

siderust_status_t siderust_altitude_at(struct siderust_subject_t subject,
                                       struct siderust_geodetic_t observer,
                                       double mjd,
                                       double *out_rad);

// Periods when a subject is above a threshold altitude.

siderust_status_t siderust_above_threshold(struct siderust_subject_t subject,
                                           struct siderust_geodetic_t observer,
                                           tempoch_period_mjd_t window,
                                           double threshold_deg,
                                           struct siderust_search_opts_t opts,
                                           tempoch_period_mjd_t **out,
                                           uintptr_t *count);

// Periods when a subject is below a threshold altitude.

siderust_status_t siderust_below_threshold(struct siderust_subject_t subject,
                                           struct siderust_geodetic_t observer,
                                           tempoch_period_mjd_t window,
                                           double threshold_deg,
                                           struct siderust_search_opts_t opts,
                                           tempoch_period_mjd_t **out,
                                           uintptr_t *count);

// Threshold-crossing events for a subject.

siderust_status_t siderust_crossings(struct siderust_subject_t subject,
                                     struct siderust_geodetic_t observer,
                                     tempoch_period_mjd_t window,
                                     double threshold_deg,
                                     struct siderust_search_opts_t opts,
                                     struct siderust_crossing_event_t **out,
                                     uintptr_t *count);

// Culmination (local extrema) events for a subject.

siderust_status_t siderust_culminations(struct siderust_subject_t subject,
                                        struct siderust_geodetic_t observer,
                                        tempoch_period_mjd_t window,
                                        struct siderust_search_opts_t opts,
                                        struct siderust_culmination_event_t **out,
                                        uintptr_t *count);

// Periods when a body's altitude is within [min, max].
//
// Only `Body` subjects support this operation. For `Star`, `Icrs`, and
// `GenericTarget`, `SIDERUST_STATUS_T_INVALID_ARGUMENT` is returned.

siderust_status_t siderust_altitude_periods(struct siderust_subject_t subject,
                                            struct siderust_altitude_query_t query,
                                            tempoch_period_mjd_t **out,
                                            uintptr_t *count);

// Azimuth of any subject at an instant (degrees, North-clockwise).

siderust_status_t siderust_azimuth_at(struct siderust_subject_t subject,
                                      struct siderust_geodetic_t observer,
                                      double mjd,
                                      double *out_deg);

// Azimuth bearing-crossing events for a subject.

siderust_status_t siderust_azimuth_crossings(struct siderust_subject_t subject,
                                             struct siderust_geodetic_t observer,
                                             tempoch_period_mjd_t window,
                                             double bearing_deg,
                                             struct siderust_search_opts_t opts,
                                             struct siderust_azimuth_crossing_event_t **out,
                                             uintptr_t *count);

// Azimuth extrema (northernmost / southernmost bearing) for a subject.

siderust_status_t siderust_azimuth_extrema(struct siderust_subject_t subject,
                                           struct siderust_geodetic_t observer,
                                           tempoch_period_mjd_t window,
                                           struct siderust_search_opts_t opts,
                                           struct siderust_azimuth_extremum_t **out,
                                           uintptr_t *count);

// Periods when a subject's azimuth is within [min_deg, max_deg].

siderust_status_t siderust_in_azimuth_range(struct siderust_subject_t subject,
                                            struct siderust_geodetic_t observer,
                                            tempoch_period_mjd_t window,
                                            double min_deg,
                                            double max_deg,
                                            struct siderust_search_opts_t opts,
                                            tempoch_period_mjd_t **out,
                                            uintptr_t *count);

// Periods when a subject's azimuth is outside [min_deg, max_deg].

siderust_status_t siderust_outside_azimuth_range(struct siderust_subject_t subject,
                                                 struct siderust_geodetic_t observer,
                                                 tempoch_period_mjd_t window,
                                                 double min_deg,
                                                 double max_deg,
                                                 struct siderust_search_opts_t opts,
                                                 tempoch_period_mjd_t **out,
                                                 uintptr_t *count);

// Create a generic target from the tagged target payload.
//
// This is the canonical constructor for the compact FFI target ABI. Existing
// convenience helpers remain available as compatibility shims and forward here.

siderust_status_t siderust_generic_target_create(struct SiderustGenericTargetData data,
                                                 struct SiderustGenericTarget **out);

// Create a generic target from an ICRS spherical direction.

siderust_status_t siderust_generic_target_create_icrs(double ra_deg,
                                                      double dec_deg,
                                                      double epoch_jd,
                                                      struct SiderustGenericTarget **out);

// Create a generic target from an ICRS direction with proper motion.

siderust_status_t siderust_generic_target_create_icrs_with_pm(double ra_deg,
                                                              double dec_deg,
                                                              double epoch_jd,
                                                              double pm_ra_deg_yr,
                                                              double pm_dec_deg_yr,
                                                              siderust_ra_convention_t ra_convention,
                                                              struct SiderustGenericTarget **out);

// Free a generic target handle.
//
// # Safety
// `handle` must have been allocated by a `siderust_generic_target_create*`
// function in this crate and must not have been freed before.
 void siderust_generic_target_free(struct SiderustGenericTarget *handle);

// Get the coordinate payload from a generic target.

siderust_status_t siderust_generic_target_get_data(const struct SiderustGenericTarget *handle,
                                                   struct SiderustGenericTargetData *out);

// Get the epoch (Julian Date) of a generic target.

siderust_status_t siderust_generic_target_epoch_jd(const struct SiderustGenericTarget *handle,
                                                   double *out);

// Classify the sky condition from the Sun's altitude in degrees.
//
// Writes the resulting phase to `out` and returns [`SiderustStatus::Ok`] on
// success. Returns [`SiderustStatus::NullPointer`] if `out` is null.
//
// The boundary convention follows IAU/USNO; see [`SiderustTwilightPhase`].

siderust_status_t siderust_twilight_classification_deg(double altitude_deg,
                                                       siderust_twilight_phase_t *out);

// Classify the sky condition from the Sun's altitude in radians.
//
// Writes the resulting phase to `out` and returns [`SiderustStatus::Ok`] on
// success. Returns [`SiderustStatus::NullPointer`] if `out` is null.

siderust_status_t siderust_twilight_classification_rad(double altitude_rad,
                                                       siderust_twilight_phase_t *out);

#ifdef __cplusplus
}  // extern "C"
#endif  // __cplusplus

#endif  /* SIDERUST_FFI_H */
