#ifndef TEMPOCH_FFI_H
#define TEMPOCH_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>
/* QttyQuantity and UnitId definitions come from qtty_ffi.h */
#include "qtty_ffi.h"


// Status codes returned by tempoch-ffi functions.
//
// Callers must inspect this value before reading any output parameters.
//
// # ABI Contract
//
// Discriminant values are frozen; new variants may only be added at the end.
//
enum tempoch_status_t
#ifdef __cplusplus
  : int32_t
#endif // __cplusplus
 {
  // Operation completed successfully.
  TEMPOCH_STATUS_T_OK = 0,
  // A required output pointer was null.
  TEMPOCH_STATUS_T_NULL_POINTER = 1,
  // UTC conversion failed (date out of range or invalid).
  TEMPOCH_STATUS_T_UTC_CONVERSION_FAILED = 2,
  // The period is invalid (start > end).
  TEMPOCH_STATUS_T_INVALID_PERIOD = 3,
  // The two periods do not intersect.
  TEMPOCH_STATUS_T_NO_INTERSECTION = 4,
  // The provided scale ID is not a recognized `TempochScale` discriminant.
  TEMPOCH_STATUS_T_INVALID_SCALE_ID = 5,
  // The quantity's unit is not a time-compatible duration unit.
  TEMPOCH_STATUS_T_INVALID_DURATION_UNIT = 6,
  // A Rust panic was caught at the FFI boundary.
  //
  // This indicates a bug in the underlying library; the panic payload is
  // discarded.  Domain errors (`UtcConversionFailed`, `InvalidPeriod`, etc.)
  // are never reported via this variant.
  TEMPOCH_STATUS_T_INTERNAL_PANIC = 7,
  // A UT1 / ΔT conversion was requested for a date outside the compiled
  // ΔT data horizon.  The output value has not been written.
  TEMPOCH_STATUS_T_UT1_HORIZON_EXCEEDED = 8,
  // The period list is not sorted by start time.
  TEMPOCH_STATUS_T_PERIOD_LIST_UNSORTED = 9,
  // The period list has overlapping intervals.
  TEMPOCH_STATUS_T_PERIOD_LIST_OVERLAPPING = 10,
  // A generic time conversion failed.
  TEMPOCH_STATUS_T_CONVERSION_FAILED = 11,
  // The provided format ID is not a recognized `TempochFormatTag`.
  TEMPOCH_STATUS_T_INVALID_FORMAT_ID = 12,
};
#ifndef __cplusplus
typedef int32_t tempoch_status_t;
#endif // __cplusplus

// Format tags used by the split-instant C ABI.
//
enum tempoch_format_tag_t
#ifdef __cplusplus
  : int32_t
#endif // __cplusplus
 {
  // Julian Day.
  TEMPOCH_FORMAT_TAG_T_JD = 0,
  // Modified Julian Day.
  TEMPOCH_FORMAT_TAG_T_MJD = 1,
  // SI seconds since J2000 on the source scale axis.
  TEMPOCH_FORMAT_TAG_T_J2000_SECONDS = 2,
  // POSIX / Unix seconds on the UTC axis.
  TEMPOCH_FORMAT_TAG_T_UNIX = 3,
  // GPS seconds on the TAI axis.
  TEMPOCH_FORMAT_TAG_T_GPS = 4,
};
#ifndef __cplusplus
typedef int32_t tempoch_format_tag_t;
#endif // __cplusplus

// Time scale identifier for generic dispatch functions.
//
// In the C ABI, callers pass raw `int32_t` values and must validate them
// before dispatch.
//
enum tempoch_scale_id_t
#ifdef __cplusplus
  : int32_t
#endif // __cplusplus
 {
  // Julian Date (TT), expressed in days.
  TEMPOCH_SCALE_ID_T_JD = 0,
  // Modified Julian Date (TT), expressed in days.
  TEMPOCH_SCALE_ID_T_MJD = 1,
  // Barycentric Dynamical Time, expressed as Julian days on the TDB axis.
  TEMPOCH_SCALE_ID_T_TDB = 2,
  // Terrestrial Time, expressed as Julian days on the TT axis.
  TEMPOCH_SCALE_ID_T_TT = 3,
  // International Atomic Time, expressed as Julian days on the TAI axis.
  TEMPOCH_SCALE_ID_T_TAI = 4,
  // Geocentric Coordinate Time, expressed as Julian days on the TCG axis.
  TEMPOCH_SCALE_ID_T_TCG = 5,
  // Barycentric Coordinate Time, expressed as Julian days on the TCB axis.
  TEMPOCH_SCALE_ID_T_TCB = 6,
  // GPS time, expressed in days since the GPS epoch.
  TEMPOCH_SCALE_ID_T_GPS = 7,
  // Universal Time UT1, expressed as Julian days on the UT1 axis.
  TEMPOCH_SCALE_ID_T_UT = 8,
  // Julian Ephemeris Date, numerically equal to JD(TT) in this ABI.
  TEMPOCH_SCALE_ID_T_JDE = 9,
  // Unix / POSIX time in seconds since 1970-01-01T00:00:00 UTC.
  TEMPOCH_SCALE_ID_T_UNIX_TIME = 10,
};
#ifndef __cplusplus
typedef int32_t tempoch_scale_id_t;
#endif // __cplusplus

// Scale tags used by the split-instant C ABI.
//
enum tempoch_scale_tag_t
#ifdef __cplusplus
  : int32_t
#endif // __cplusplus
 {
  // Terrestrial Time.
  TEMPOCH_SCALE_TAG_T_TT = 0,
  // International Atomic Time.
  TEMPOCH_SCALE_TAG_T_TAI = 1,
  // Coordinated Universal Time stored on its continuous instant axis.
  TEMPOCH_SCALE_TAG_T_UTC = 2,
  // Universal Time 1.
  TEMPOCH_SCALE_TAG_T_UT1 = 3,
  // Barycentric Dynamical Time.
  TEMPOCH_SCALE_TAG_T_TDB = 4,
  // Geocentric Coordinate Time.
  TEMPOCH_SCALE_TAG_T_TCG = 5,
  // Barycentric Coordinate Time.
  TEMPOCH_SCALE_TAG_T_TCB = 6,
};
#ifndef __cplusplus
typedef int32_t tempoch_scale_tag_t;
#endif // __cplusplus

// Opaque FFI time-conversion context.
typedef struct tempoch_context_t tempoch_context_t;

// Interpolated IERS Earth Orientation Parameter values at a UTC MJD.
//
// All scalar fields use the units from the upstream IERS `finals2000A.all`
// file.  Fields that the upstream file leaves blank for the requested epoch
// are encoded as `NaN`; check with `isnan()` before using them.
//
// # Fields
// - `mjd_utc` — query epoch rounded to the nearest data point boundary.
// - `pm_xp_arcsec` / `pm_yp_arcsec` — polar-motion components (arcseconds).
// - `ut1_minus_utc` — DUT1 = UT1 − UTC (seconds of time).
// - `lod_milliseconds` — excess length-of-day (milliseconds of time).
// - `dx_milliarcsec` / `dy_milliarcsec` — IAU 2000A celestial-pole offsets
//   (milliarcseconds).
// - `ut1_observed` — `1` when both bracketing rows carry observed (`I`) data.
//
typedef struct tempoch_eop_values_t {
  // UTC MJD of the interpolation result.
  double mjd_utc;
  // Polar motion X component (arcseconds). `NaN` if absent.
  double pm_xp_arcsec;
  // Polar motion Y component (arcseconds). `NaN` if absent.
  double pm_yp_arcsec;
  // DUT1 = UT1 − UTC (seconds of time).
  double ut1_minus_utc;
  // Excess LOD (milliseconds of time). `NaN` if absent.
  double lod_milliseconds;
  // ΔX celestial-pole offset (milliarcseconds). `NaN` if absent.
  double dx_milliarcsec;
  // ΔY celestial-pole offset (milliarcseconds). `NaN` if absent.
  double dy_milliarcsec;
  // Non-zero when both bracketing rows carry observed (`I`) data.
  uint8_t ut1_observed;
} tempoch_eop_values_t;

// A time period expressed in Modified Julian Date, suitable for C interop.
typedef struct tempoch_period_mjd_t {
  // Start of the period (MJD).
  double start_mjd;
  // End of the period (MJD).
  double end_mjd;
} tempoch_period_mjd_t;

// UTC date-time breakdown for C interop.
typedef struct tempoch_utc_t {
  // Calendar year (e.g. 2026).
  int32_t year;
  // Month of the year (1–12).
  uint8_t month;
  // Day of the month (1–31).
  uint8_t day;
  // Hour of the day (0–23).
  uint8_t hour;
  // Minute of the hour (0–59).
  uint8_t minute;
  // Second of the minute (0–60). `60` denotes a positive leap second.
  uint8_t second;
  // Sub-second component in nanoseconds (0–999_999_999).
  uint32_t nanosecond;
} tempoch_utc_t;

// Split J2000-second instant on a scale-specific axis.
typedef struct tempoch_time_t {
  // High part of the compensated J2000-second pair.
  double hi_seconds;
  // Low residual part of the compensated J2000-second pair.
  double lo_seconds;
} tempoch_time_t;

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

// Returns the tempoch-ffi ABI version (major*10000 + minor*100 + patch).
//
// Current ABI line: 0.4.x -> 400
 uint32_t tempoch_ffi_version(void);

// J2000.0 epoch as JD(TT) — 2 451 545.0.
 double tempoch_const_j2000_jd_tt(void);

// One Julian year in days — 365.25.
 double tempoch_const_julian_year_days(void);

// First MJD covered by the built-in UTC-TAI segment table (1961-01-01).
 double tempoch_const_utc_defined_from_mjd(void);

// GPS epoch as a Julian Day on the UTC axis (1980-01-06T00:00:00 UTC).
 double tempoch_const_gps_epoch_jd_utc(void);

// GPS epoch expressed as a Julian Day on the TAI axis.
 double tempoch_const_gps_epoch_jd_tai(void);

// Exact TAI − UTC offset at the GPS epoch, in seconds (19.0).
 double tempoch_const_gps_epoch_tai_minus_utc_seconds(void);

// MJD of the last date for which a ΔT prediction (not extrapolation) is
// available from the compiled USNO data.
 double tempoch_const_delta_t_prediction_horizon_mjd(void);

// First MJD covered by the compiled IERS EOP series.
 double tempoch_const_eop_start_mjd(void);

// Last MJD covered by the compiled IERS EOP series.
 double tempoch_const_eop_end_mjd(void);

// Last MJD with *observed* (Bulletin C04) EOP data in the compiled series.
 double tempoch_const_eop_observed_end_mjd(void);

// Last MJD with modern observed ΔT data (post-1955 atomic-clock era).
 double tempoch_const_modern_delta_t_observed_end_mjd(void);

// Create a default context backed by the monthly ΔT model.
//
// # Safety
// `out` must be a valid, non-null pointer to writable storage for a context handle.
 tempoch_status_t tempoch_context_create_default(struct tempoch_context_t **out);

// Create a context that prefers the compiled builtin EOP path for UT1.
//
// # Safety
// `out` must be a valid, non-null pointer to writable storage for a context handle.
 tempoch_status_t tempoch_context_create_with_builtin_eop(struct tempoch_context_t **out);

// Derive a new context that permits pre-1961 UTC extrapolation.
//
// # Safety
// `handle` must be a valid, non-null context pointer produced by this crate, and `out` must be
// a valid, non-null pointer to writable storage for a context handle.

tempoch_status_t tempoch_context_allow_pre_definition_utc(const struct tempoch_context_t *handle,
                                                          struct tempoch_context_t **out);

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

// Returns `true` when [`tempoch_eop_at`] would succeed for `mjd_utc`.
 bool tempoch_eop_covers(double mjd_utc);

// Interpolate IERS EOP values at `mjd_utc` (UTC Modified Julian Date).
//
// Returns `Ok` and writes the result into `*out` on success.
// Returns `Ut1HorizonExceeded` when `mjd_utc` is outside the compiled EOP
// range.
//
// # Safety
// `out` must be a valid, writable pointer to `TempochEopValues`.
 tempoch_status_t tempoch_eop_at(double mjd_utc, struct tempoch_eop_values_t *out);

// Create a new MJD period. Returns `InvalidPeriod` if the endpoints are
// non-finite or `start_mjd > end_mjd`.
//
// # Safety
// `out` must be a valid, writable pointer to `TempochPeriodMjd`.

tempoch_status_t tempoch_period_mjd_new(double start_mjd,
                                        double end_mjd,
                                        struct tempoch_period_mjd_t *out);

// Compute the duration of a period in days (end − start).
 double tempoch_period_mjd_duration_days(struct tempoch_period_mjd_t period);

// Compute the duration of a period as a `QttyQuantity` in days.
 qtty_quantity_t tempoch_period_mjd_duration_qty(struct tempoch_period_mjd_t period);

// Compute the intersection of two MJD periods.
//
// Returns `InvalidPeriod` if either input period is malformed and
// `NoIntersection` if the periods do not overlap.
//
// # Safety
// `out` must be a valid, writable pointer to `TempochPeriodMjd`.

tempoch_status_t tempoch_period_mjd_intersection(struct tempoch_period_mjd_t a,
                                                 struct tempoch_period_mjd_t b,
                                                 struct tempoch_period_mjd_t *out);

// Free a `TempochPeriodMjd` array allocated by a tempoch-ffi function.
//
// Passing a null pointer is safe (no-op).
//
// # Safety
// `ptr` and `count` must have been returned by the same function call and
// must not be used after this call.
 void tempoch_period_mjd_free(struct tempoch_period_mjd_t *ptr, uintptr_t count);

// Return `true` when `mjd` is within the half-open interval `[start, end)`.
 bool tempoch_period_mjd_contains(struct tempoch_period_mjd_t period, double mjd);

// Compute the union of two MJD periods.
//
// Overlapping or touching periods are merged into one; disjoint periods
// produce two entries.  The result is written into the caller-provided
// two-element array `out[0..2]`; `*out_count` is set to 1 or 2.
//
// Returns `InvalidPeriod` if either input period is malformed.
//
// # Safety
// `out` must point to at least two writable `TempochPeriodMjd` values.
// `out_count` must be a valid writable pointer to `uintptr_t`.

tempoch_status_t tempoch_period_mjd_union(struct tempoch_period_mjd_t a,
                                          struct tempoch_period_mjd_t b,
                                          struct tempoch_period_mjd_t *out,
                                          uintptr_t *out_count);

// Validate that a period list is sorted, non-overlapping, and each
// `start <= end`.
//
// Returns `Ok` if the list is valid, `InvalidPeriod` for malformed
// intervals, `PeriodListUnsorted` for ordering violations, and
// `PeriodListOverlapping` for overlapping intervals.
//
// Passing a null pointer with `count == 0` is valid and returns `Ok`.
//
// # Safety
// `periods` must point to `count` valid, initialized `TempochPeriodMjd`
// values (or be null when `count == 0`).

tempoch_status_t tempoch_period_list_validate(const struct tempoch_period_mjd_t *periods,
                                              uintptr_t count);

// Compute the complement of `periods` within `outer`: the gaps inside
// `outer` that are not covered by any period in the list.
//
// `periods` must be sorted and non-overlapping.  The result is heap-
// allocated; the caller must free it with `tempoch_period_mjd_free`.
//
// Returns `InvalidPeriod` for malformed inputs, `PeriodListUnsorted` or
// `PeriodListOverlapping` for invalid list structure.
//
// # Safety
// - `periods` must point to `count` valid `TempochPeriodMjd` values (or be
//   null when `count == 0`).
// - `out` and `out_count` must be valid writable pointers.

tempoch_status_t tempoch_period_list_complement(struct tempoch_period_mjd_t outer,
                                                const struct tempoch_period_mjd_t *periods,
                                                uintptr_t count,
                                                struct tempoch_period_mjd_t **out,
                                                uintptr_t *out_count);

// Intersect two sorted, non-overlapping period lists.
//
// The result is heap-allocated; the caller must free it with
// `tempoch_period_mjd_free`.
//
// Returns `InvalidPeriod`, `PeriodListUnsorted`, or `PeriodListOverlapping`
// when either input list is invalid.
//
// # Safety
// - `a` / `b` must point to `a_count` / `b_count` valid periods (or be null
//   when the corresponding count is 0).
// - `out` and `out_count` must be valid writable pointers.

tempoch_status_t tempoch_period_list_intersect(const struct tempoch_period_mjd_t *a,
                                               uintptr_t a_count,
                                               const struct tempoch_period_mjd_t *b,
                                               uintptr_t b_count,
                                               struct tempoch_period_mjd_t **out,
                                               uintptr_t *out_count);

// Merge two period lists, combining overlapping and adjacent intervals.
//
// The inputs do not need to be pre-sorted or non-overlapping; the output
// is always sorted and non-overlapping.  The result is heap-allocated; the
// caller must free it with `tempoch_period_mjd_free`.
//
// Returns `InvalidPeriod` if any input period is malformed.
//
// # Safety
// - `a` / `b` must point to `a_count` / `b_count` valid periods (or be null
//   when the corresponding count is 0).
// - `out` and `out_count` must be valid writable pointers.

tempoch_status_t tempoch_period_list_union(const struct tempoch_period_mjd_t *a,
                                           uintptr_t a_count,
                                           const struct tempoch_period_mjd_t *b,
                                           uintptr_t b_count,
                                           struct tempoch_period_mjd_t **out,
                                           uintptr_t *out_count);

// Sort and merge overlapping or adjacent intervals in a period list.
//
// The result is heap-allocated; the caller must free it with
// `tempoch_period_mjd_free`.
//
// Returns `InvalidPeriod` if any input period is malformed.
//
// # Safety
// - `periods` must point to `count` valid periods (or be null when
//   `count == 0`).
// - `out` and `out_count` must be valid writable pointers.

tempoch_status_t tempoch_period_list_normalize(const struct tempoch_period_mjd_t *periods,
                                               uintptr_t count,
                                               struct tempoch_period_mjd_t **out,
                                               uintptr_t *out_count);

// Create a Julian Date from a raw `double`.
 double tempoch_jd_new(double value);

// Return the J2000.0 epoch as a Julian Date (2451545.0).
 double tempoch_jd_j2000(void);

// Convert a Julian Date to a Modified Julian Date.
 double tempoch_jd_to_mjd(double jd);

// Create a Julian Date from a UTC date-time.
//
// # Safety
// `out` must be a valid, writable pointer to `double`.
 tempoch_status_t tempoch_jd_from_utc(struct tempoch_utc_t utc, double *out);

// Convert a Julian Date to a UTC breakdown.
//
// # Safety
// `out` must be a valid, writable pointer to `TempochUtc`.
 tempoch_status_t tempoch_jd_to_utc(double jd, struct tempoch_utc_t *out);

// Create a Modified Julian Date from a raw `double`.
 double tempoch_mjd_new(double value);

// Convert a Modified Julian Date to a Julian Date.
 double tempoch_mjd_to_jd(double mjd);

// Create a Modified Julian Date from a UTC date-time.
//
// # Safety
// `out` must be a valid, writable pointer to `double`.
 tempoch_status_t tempoch_mjd_from_utc(struct tempoch_utc_t utc, double *out);

// Convert a Modified Julian Date to a UTC breakdown.
//
// # Safety
// `out` must be a valid, writable pointer to `TempochUtc`.
 tempoch_status_t tempoch_mjd_to_utc(double mjd, struct tempoch_utc_t *out);

// Compute the difference between two Julian Dates in days (jd1 − jd2).
 double tempoch_jd_difference(double jd1, double jd2);

// Add a duration in days to a Julian Date.
 double tempoch_jd_add_days(double jd, double days);

// Compute the difference between two Modified Julian Dates in days (mjd1 − mjd2).
 double tempoch_mjd_difference(double mjd1, double mjd2);

// Add a duration in days to a Modified Julian Date.
 double tempoch_mjd_add_days(double mjd, double days);

// Compute Julian centuries since J2000 for a given Julian Date.
 double tempoch_jd_julian_centuries(double jd);

// Compute the difference between two Julian Dates as a `QttyQuantity` in days.
 qtty_quantity_t tempoch_jd_difference_qty(double jd1, double jd2);

// Add a `QttyQuantity` duration (time-compatible) to a Julian Date.
//
// Returns `InvalidDurationUnit` if the quantity cannot be converted to days.
//
// # Safety
// `out` must be a valid, writable pointer to `double`.
 tempoch_status_t tempoch_jd_add_qty(double jd, qtty_quantity_t duration, double *out);

// Compute the difference between two Modified Julian Dates as a `QttyQuantity` in days.
 qtty_quantity_t tempoch_mjd_difference_qty(double mjd1, double mjd2);

// Add a `QttyQuantity` duration (time-compatible) to a Modified Julian Date.
//
// Returns `InvalidDurationUnit` if the quantity cannot be converted to days.
//
// # Safety
// `out` must be a valid, writable pointer to `double`.
 tempoch_status_t tempoch_mjd_add_qty(double mjd, qtty_quantity_t duration, double *out);

// Compute Julian centuries since J2000 as a `QttyQuantity`.
 qtty_quantity_t tempoch_jd_julian_centuries_qty(double jd);

// Convert a Julian Date (TT) to TDB.
 double tempoch_jd_to_tdb(double jd);

// Convert TDB back to Julian Date (TT).
 double tempoch_tdb_to_jd(double tdb);

// Convert a Julian Date (TT) to TT (identity).
 double tempoch_jd_to_tt(double jd);

// Convert TT back to Julian Date (TT).
 double tempoch_tt_to_jd(double tt);

// Convert a Julian Date (TT) to TAI.
 double tempoch_jd_to_tai(double jd);

// Convert TAI back to Julian Date (TT).
 double tempoch_tai_to_jd(double tai);

// Convert a Julian Date (TT) to TCG.
 double tempoch_jd_to_tcg(double jd);

// Convert TCG back to Julian Date (TT).
 double tempoch_tcg_to_jd(double tcg);

// Convert a Julian Date (TT) to TCB.
 double tempoch_jd_to_tcb(double jd);

// Convert TCB back to Julian Date (TT).
 double tempoch_tcb_to_jd(double tcb);

// Convert a Julian Date (TT) to GPS Time.
 double tempoch_jd_to_gps(double jd);

// Convert GPS Time back to Julian Date (TT).
 double tempoch_gps_to_jd(double gps);

// Convert a Julian Date (TT) to Universal Time UT1.
 double tempoch_jd_to_ut(double jd);

// Convert Universal Time UT1 back to Julian Date (TT).
 double tempoch_ut_to_jd(double ut);

// Convert a Julian Date (TT) to Julian Ephemeris Date.
 double tempoch_jd_to_jde(double jd);

// Convert Julian Ephemeris Date back to Julian Date (TT).
 double tempoch_jde_to_jd(double jde);

// Convert a Julian Date (TT) to Unix time in **seconds** since 1970-01-01T00:00:00 UTC.
//
// The result is a standard Unix timestamp suitable for passing to C `gmtime()`,
// Python `datetime.fromtimestamp()`, etc. Internally the conversion routes
// through the compiled UTC-TAI history.
//
// Round-tripping `Unix -> JD -> Unix` is expected to stay within a few
// microseconds. Callers should not assume nanosecond-exact reversibility
// through the JD(TT) axis.
//
// Returns `NaN` if `jd` is non-finite or cannot be represented by the
// compiled UTC civil-time model.
 double tempoch_jd_to_unix(double jd);

// Convert Unix time in **seconds** since 1970-01-01T00:00:00 UTC back to Julian Date (TT).
//
// Accepts a standard Unix timestamp (seconds, not days). The conversion
// uses the compiled UTC-TAI history for leap-second handling.
//
// Round-tripping `Unix -> JD -> Unix` is expected to stay within a few
// microseconds. Callers should not assume nanosecond-exact reversibility
// through the JD(TT) axis.
//
// Returns `NaN` if `unix_ts` is non-finite or outside the supported UTC civil range.
 double tempoch_unix_to_jd(double unix_ts);

// Create a Unix timestamp from seconds since 1970-01-01T00:00:00 UTC.
//
// This is a convenience identity for the C ABI: the returned `double` is
// the same value, confirming that the FFI Unix convention is **seconds**.
// Use [`tempoch_unix_to_jd`] when you need the corresponding Julian Date.
 double tempoch_unix_from_seconds(double seconds);

// Extract the Unix timestamp in seconds from a value previously obtained
// via [`tempoch_jd_to_unix`] or [`tempoch_unix_from_seconds`].
//
// This is also a convenience identity confirming the seconds convention.
 double tempoch_unix_to_seconds(double unix_ts);

// Return ΔT = TT − UT1 in seconds for a Julian Date.
//
// For dates within the compiled data range this is the observed/predicted
// value from USNO data. For dates beyond [`tempoch::DELTA_T_PREDICTION_HORIZON_MJD`]
// the result is a quadratic tail-fit extrapolation; accuracy degrades
// rapidly past the horizon. The value is never `NaN`; non-finite `jd`
// (infinity or NaN) returns `0.0`.
 double tempoch_delta_t_seconds(double jd);

// Return ΔT = TT − UT1 in seconds for a Julian Date, without unsupported
// extrapolation.
//
// # Safety
// `out` must be a valid, writable pointer to `double`.
 tempoch_status_t tempoch_delta_t_seconds_checked(double jd, double *out);

// Convert a `double` time value from one scale to another.
//
// # Safety
// `out` must be a valid, writable pointer to `double`.

tempoch_status_t tempoch_time_convert(double value,
                                      int32_t from_scale_id,
                                      int32_t to_scale_id,
                                      double *out);

// Convert a UTC date-time to a value in any supported scale.
//
// # Safety
// `out` must be a valid, writable pointer to `double`.
 tempoch_status_t tempoch_time_from_utc(struct tempoch_utc_t utc, int32_t scale_id, double *out);

// Convert a time value in any supported scale to UTC.
//
// # Safety
// `out` must be a valid, writable pointer to `TempochUtc`.
 tempoch_status_t tempoch_time_to_utc(double value, int32_t scale_id, struct tempoch_utc_t *out);

// Compute a same-scale duration in days.
//
// # Safety
// `out` must be a valid, writable pointer to `double`.

tempoch_status_t tempoch_time_difference_days(double lhs,
                                              double rhs,
                                              int32_t scale_id,
                                              double *out);

// Compute a same-scale duration as a day-valued `QttyQuantity`.
//
// # Safety
// `out` must be a valid, writable pointer to `qtty_quantity_t`.

tempoch_status_t tempoch_time_difference_qty(double lhs,
                                             double rhs,
                                             int32_t scale_id,
                                             qtty_quantity_t *out);

// Add a same-scale duration in days.
//
// # Safety
// `out` must be a valid, writable pointer to `double`.
 tempoch_status_t tempoch_time_add_days(double value, int32_t scale_id, double days, double *out);

// Add a same-scale duration from a time-compatible `QttyQuantity`.
//
// # Safety
// `out` must be a valid, writable pointer to `double`.

tempoch_status_t tempoch_time_add_qty(double value,
                                      int32_t scale_id,
                                      qtty_quantity_t duration,
                                      double *out);

// Convert a Julian Date to any scale, writing the result into `out`.
//
// # Safety
// `out` must be a valid, writable pointer to `double`.
 tempoch_status_t tempoch_jd_to_scale(double jd, int32_t scale_id, double *out);

// Convert a value in any scale to a Julian Date, writing the result into `out`.
//
// # Safety
// `out` must be a valid, writable pointer to `double`.
 tempoch_status_t tempoch_scale_to_jd(double value, int32_t scale_id, double *out);

// Validate and normalize a split J2000-second pair.
//
// # Safety
// `out` must be a valid, writable pointer to `TempochTime`.

tempoch_status_t tempoch_time_new(double hi_seconds,
                                  double lo_seconds,
                                  struct tempoch_time_t *out);

// Convert a split instant from one scale to another.
//
// # Safety
// `out` must be a valid, writable pointer to `TempochTime`.

tempoch_status_t tempoch_time_scale_convert(struct tempoch_time_t value,
                                            int32_t from_scale,
                                            int32_t to_scale,
                                            const struct tempoch_context_t *context,
                                            struct tempoch_time_t *out);

// Encode a split instant in the requested public format.
//
// # Safety
// `out` must be a valid, writable pointer to `double`.

tempoch_status_t tempoch_time_to_format(struct tempoch_time_t value,
                                        int32_t scale,
                                        int32_t format,
                                        const struct tempoch_context_t *context,
                                        double *out);

// Decode a split instant from the requested public format.
//
// # Safety
// `out` must be a valid, writable pointer to `TempochTime`.

tempoch_status_t tempoch_time_from_format(double raw,
                                          int32_t scale,
                                          int32_t format,
                                          const struct tempoch_context_t *context,
                                          struct tempoch_time_t *out);

// Build a UTC-axis split instant from a civil calendar label.
//
// # Safety
// `out` must be a valid, writable pointer to `TempochTime`.

tempoch_status_t tempoch_time_from_civil(struct tempoch_utc_t civil,
                                         const struct tempoch_context_t *context,
                                         struct tempoch_time_t *out);

// Convert a split instant on the UTC axis to a civil calendar label.
//
// # Safety
// `out` must be a valid, writable pointer to `TempochUtc`.

tempoch_status_t tempoch_time_to_civil(struct tempoch_time_t value,
                                       const struct tempoch_context_t *context,
                                       struct tempoch_utc_t *out);

// Shift a split instant by a duration convertible to seconds.
//
// # Safety
// `out` must be a valid, writable pointer to `TempochTime`.

tempoch_status_t tempoch_time_add_seconds(struct tempoch_time_t value,
                                          qtty_quantity_t duration,
                                          struct tempoch_time_t *out);

// Return `lhs - rhs` in SI seconds.
//
// # Safety
// `out` must be a valid, writable pointer to `double`.

tempoch_status_t tempoch_time_difference_seconds(struct tempoch_time_t lhs,
                                                 struct tempoch_time_t rhs,
                                                 double *out);

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

#endif  /* TEMPOCH_FFI_H */
