-- pg_orrery 0.5.0 -> 0.6.0 migration
--
-- Adds range rate fitting, per-observation weights, and
-- angles-only orbit determination (Gauss method).
--
-- Range rate and weights change the input signatures of
-- tle_from_eci and tle_from_topocentric (added trailing
-- DEFAULT parameters), which requires DROP + re-CREATE.

-- ============================================================
-- Drop old OD function signatures
-- ============================================================

DROP FUNCTION IF EXISTS tle_from_eci(eci_position[], timestamptz[], tle, boolean, int4);
DROP FUNCTION IF EXISTS tle_from_topocentric(topocentric[], timestamptz[], observer, tle, boolean, int4);
DROP FUNCTION IF EXISTS tle_from_topocentric(topocentric[], timestamptz[], observer[], int4[], tle, boolean, int4);

-- ============================================================
-- Re-create with range_rate + weights parameters
-- ============================================================

-- Fit TLE from ECI position/velocity ephemeris
-- weights: per-observation weighting (NULL = uniform)

CREATE FUNCTION tle_from_eci(
    positions eci_position[], times timestamptz[],
    seed tle DEFAULT NULL, fit_bstar boolean DEFAULT false,
    max_iter int4 DEFAULT 15,
    weights float8[] DEFAULT NULL,
    OUT fitted_tle tle, OUT iterations int4,
    OUT rms_final float8, OUT rms_initial float8, OUT status text,
    OUT condition_number float8, OUT covariance float8[], OUT nstate int4
) RETURNS RECORD
    AS 'MODULE_PATHNAME' LANGUAGE C STABLE PARALLEL SAFE;
COMMENT ON FUNCTION tle_from_eci(eci_position[], timestamptz[], tle, boolean, int4, float8[]) IS
    'Fit a TLE from ECI position/velocity observations via differential correction. Optional per-observation weights for heterogeneous sensor fusion. Returns fitted TLE, RMS residuals, convergence status, condition number, and formal covariance matrix.';

-- Fit TLE from topocentric observations (az/el/range) — single observer
-- fit_range_rate: include range_rate as 4th residual component
-- weights: per-observation weighting (NULL = uniform)

CREATE FUNCTION tle_from_topocentric(
    observations topocentric[], times timestamptz[],
    obs observer,
    seed tle DEFAULT NULL, fit_bstar boolean DEFAULT false,
    max_iter int4 DEFAULT 15,
    fit_range_rate boolean DEFAULT false,
    weights float8[] DEFAULT NULL,
    OUT fitted_tle tle, OUT iterations int4,
    OUT rms_final float8, OUT rms_initial float8, OUT status text,
    OUT condition_number float8, OUT covariance float8[], OUT nstate int4
) RETURNS RECORD
    AS 'MODULE_PATHNAME' LANGUAGE C STABLE PARALLEL SAFE;
COMMENT ON FUNCTION tle_from_topocentric(topocentric[], timestamptz[], observer, tle, boolean, int4, boolean, float8[]) IS
    'Fit a TLE from topocentric (az/el/range) observations via differential correction. Optional range_rate fitting and per-observation weights. Returns fitted TLE, RMS residuals, convergence status, condition number, and formal covariance matrix.';

-- Fit TLE from topocentric observations — multiple observers

CREATE FUNCTION tle_from_topocentric(
    observations topocentric[], times timestamptz[],
    observers observer[], observer_ids int4[],
    seed tle DEFAULT NULL, fit_bstar boolean DEFAULT false,
    max_iter int4 DEFAULT 15,
    fit_range_rate boolean DEFAULT false,
    weights float8[] DEFAULT NULL,
    OUT fitted_tle tle, OUT iterations int4,
    OUT rms_final float8, OUT rms_initial float8, OUT status text,
    OUT condition_number float8, OUT covariance float8[], OUT nstate int4
) RETURNS RECORD
    AS 'MODULE_PATHNAME', 'tle_from_topocentric_multi'
    LANGUAGE C STABLE PARALLEL SAFE;
COMMENT ON FUNCTION tle_from_topocentric(topocentric[], timestamptz[], observer[], int4[], tle, boolean, int4, boolean, float8[]) IS
    'Fit a TLE from topocentric observations collected by multiple ground stations. observer_ids[i] indexes into observers[]. Optional range_rate fitting and per-observation weights.';

-- ============================================================
-- Angles-only orbit determination (new in v0.6.0)
-- ============================================================

-- Fit TLE from RA/Dec observations — single observer
-- Uses Gauss method for initial orbit determination when no seed is provided.
-- RA in hours [0,24), Dec in degrees [-90,90] (matches star_observe convention).
-- RMS output is in radians for angles-only mode.

CREATE FUNCTION tle_from_angles(
    ra_hours float8[], dec_degrees float8[],
    times timestamptz[],
    obs observer,
    seed tle DEFAULT NULL, fit_bstar boolean DEFAULT false,
    max_iter int4 DEFAULT 15,
    weights float8[] DEFAULT NULL,
    OUT fitted_tle tle, OUT iterations int4,
    OUT rms_final float8, OUT rms_initial float8, OUT status text,
    OUT condition_number float8, OUT covariance float8[], OUT nstate int4
) RETURNS RECORD AS 'MODULE_PATHNAME' LANGUAGE C STABLE PARALLEL SAFE;
COMMENT ON FUNCTION tle_from_angles(float8[], float8[], timestamptz[], observer, tle, boolean, int4, float8[]) IS
    'Fit a TLE from angles-only (RA/Dec) observations via Gauss IOD + differential correction. RA in hours [0,24), Dec in degrees [-90,90]. RMS output in radians. Uses Gauss method for seed-free initial guess.';

-- Fit TLE from RA/Dec observations — multiple observers

CREATE FUNCTION tle_from_angles(
    ra_hours float8[], dec_degrees float8[],
    times timestamptz[],
    observers observer[], observer_ids int4[],
    seed tle DEFAULT NULL, fit_bstar boolean DEFAULT false,
    max_iter int4 DEFAULT 15,
    weights float8[] DEFAULT NULL,
    OUT fitted_tle tle, OUT iterations int4,
    OUT rms_final float8, OUT rms_initial float8, OUT status text,
    OUT condition_number float8, OUT covariance float8[], OUT nstate int4
) RETURNS RECORD
    AS 'MODULE_PATHNAME', 'tle_from_angles_multi'
    LANGUAGE C STABLE PARALLEL SAFE;
COMMENT ON FUNCTION tle_from_angles(float8[], float8[], timestamptz[], observer[], int4[], tle, boolean, int4, float8[]) IS
    'Fit a TLE from angles-only (RA/Dec) observations from multiple ground stations via Gauss IOD + differential correction.';
