-- de_ephemeris regression tests
--
-- Tests the _de() function variants and VSOP87 fallback behavior.
-- Since DE ephemeris files are not available in CI, these tests
-- verify that fallback behavior is correct and produces identical
-- results to the VSOP87 variants.

\set boulder '''40.015N 105.270W 1655m'''::observer

-- ============================================================
-- Test 1: pg_orrery_ephemeris_info() returns VSOP87 when no DE file
-- The provider should be 'VSOP87' since no ephemeris_path is set.
-- ============================================================
SELECT 'eph_info_vsop87' AS test,
       (pg_orrery_ephemeris_info()).provider AS provider;

-- ============================================================
-- Test 2: planet_heliocentric_de falls back to VSOP87
-- Should produce identical results to planet_heliocentric()
-- when DE is unavailable.
-- ============================================================
SELECT 'helio_fallback' AS test,
       round(helio_x(planet_heliocentric(3, '2024-06-21 12:00:00+00'))::numeric, 8) =
       round(helio_x(planet_heliocentric_de(3, '2024-06-21 12:00:00+00'))::numeric, 8) AS x_match,
       round(helio_y(planet_heliocentric(3, '2024-06-21 12:00:00+00'))::numeric, 8) =
       round(helio_y(planet_heliocentric_de(3, '2024-06-21 12:00:00+00'))::numeric, 8) AS y_match,
       round(helio_z(planet_heliocentric(3, '2024-06-21 12:00:00+00'))::numeric, 8) =
       round(helio_z(planet_heliocentric_de(3, '2024-06-21 12:00:00+00'))::numeric, 8) AS z_match;

-- ============================================================
-- Test 3: planet_heliocentric_de Sun at origin
-- ============================================================
SELECT 'sun_origin_de' AS test,
       round(helio_x(planet_heliocentric_de(0, '2024-06-21 12:00:00+00'))::numeric, 10) AS x,
       round(helio_y(planet_heliocentric_de(0, '2024-06-21 12:00:00+00'))::numeric, 10) AS y,
       round(helio_z(planet_heliocentric_de(0, '2024-06-21 12:00:00+00'))::numeric, 10) AS z;

-- ============================================================
-- Test 4: planet_observe_de falls back to VSOP87
-- Elevation and azimuth should be within 0.01 deg of planet_observe().
-- (Tolerance accounts for LTO inline function divergence.)
-- ============================================================
SELECT 'observe_fallback' AS test,
       abs(topo_azimuth(planet_observe(5, :boulder, '2024-03-15 03:00:00+00'))
         - topo_azimuth(planet_observe_de(5, :boulder, '2024-03-15 03:00:00+00'))) < 0.01 AS az_match,
       abs(topo_elevation(planet_observe(5, :boulder, '2024-03-15 03:00:00+00'))
         - topo_elevation(planet_observe_de(5, :boulder, '2024-03-15 03:00:00+00'))) < 0.01 AS el_match;

-- ============================================================
-- Test 5: sun_observe_de falls back to VSOP87
-- ============================================================
SELECT 'sun_fallback' AS test,
       abs(topo_azimuth(sun_observe(:boulder, '2024-06-21 18:00:00+00'))
         - topo_azimuth(sun_observe_de(:boulder, '2024-06-21 18:00:00+00'))) < 0.01 AS az_match,
       abs(topo_elevation(sun_observe(:boulder, '2024-06-21 18:00:00+00'))
         - topo_elevation(sun_observe_de(:boulder, '2024-06-21 18:00:00+00'))) < 0.01 AS el_match;

-- ============================================================
-- Test 6: moon_observe_de falls back to ELP2000-82B
-- ============================================================
SELECT 'moon_fallback' AS test,
       abs(topo_azimuth(moon_observe(:boulder, '2024-06-21 18:00:00+00'))
         - topo_azimuth(moon_observe_de(:boulder, '2024-06-21 18:00:00+00'))) < 0.01 AS az_match,
       round(topo_range(moon_observe(:boulder, '2024-06-21 18:00:00+00'))::numeric, 0) =
       round(topo_range(moon_observe_de(:boulder, '2024-06-21 18:00:00+00'))::numeric, 0) AS range_match;

-- ============================================================
-- Test 7: lambert_c3_de falls back to VSOP87
-- Earth-Mars 2024 window should match lambert_c3().
-- ============================================================
SELECT 'lambert_fallback' AS test,
       round(lambert_c3(3, 4, '2024-05-01 00:00:00+00', '2025-02-01 00:00:00+00')::numeric, 2) =
       round(lambert_c3_de(3, 4, '2024-05-01 00:00:00+00', '2025-02-01 00:00:00+00')::numeric, 2) AS c3_match;

-- ============================================================
-- Test 8: lambert_transfer_de falls back to VSOP87
-- Should produce identical departure C3.
-- ============================================================
SELECT 'transfer_fallback' AS test,
       round((lambert_transfer(3, 4, '2024-05-01 00:00:00+00', '2025-02-01 00:00:00+00')).c3_departure::numeric, 2) =
       round((lambert_transfer_de(3, 4, '2024-05-01 00:00:00+00', '2025-02-01 00:00:00+00')).c3_departure::numeric, 2) AS c3_match;

-- ============================================================
-- Test 9: galilean_observe_de falls back to VSOP87
-- ============================================================
SELECT 'galilean_fallback' AS test,
       abs(topo_elevation(galilean_observe(0, :boulder, '2024-03-15 03:00:00+00'))
         - topo_elevation(galilean_observe_de(0, :boulder, '2024-03-15 03:00:00+00'))) < 0.01 AS el_match;

-- ============================================================
-- Test 10: saturn_moon_observe_de falls back to VSOP87
-- ============================================================
SELECT 'saturn_moon_fallback' AS test,
       abs(topo_elevation(saturn_moon_observe(5, :boulder, '2024-06-15 04:00:00+00'))
         - topo_elevation(saturn_moon_observe_de(5, :boulder, '2024-06-15 04:00:00+00'))) < 0.01 AS el_match;

-- ============================================================
-- Test 11: uranus_moon_observe_de falls back to VSOP87
-- ============================================================
SELECT 'uranus_moon_fallback' AS test,
       abs(topo_elevation(uranus_moon_observe(3, :boulder, '2024-06-15 04:00:00+00'))
         - topo_elevation(uranus_moon_observe_de(3, :boulder, '2024-06-15 04:00:00+00'))) < 0.01 AS el_match;

-- ============================================================
-- Test 12: mars_moon_observe_de falls back to VSOP87
-- ============================================================
SELECT 'mars_moon_fallback' AS test,
       abs(topo_elevation(mars_moon_observe(0, :boulder, '2024-06-15 04:00:00+00'))
         - topo_elevation(mars_moon_observe_de(0, :boulder, '2024-06-15 04:00:00+00'))) < 0.01 AS el_match;

-- ============================================================
-- Test 13: All DE planet functions work (fallback mode)
-- Mercury through Neptune, all should return valid positions
-- matching their VSOP87 counterparts.
-- ============================================================
SELECT 'all_planets_de' AS test,
       body_id,
       round(helio_distance(planet_heliocentric_de(body_id, '2024-06-21 12:00:00+00'))::numeric, 2) AS dist_au
FROM generate_series(1, 8) AS body_id;

-- ============================================================
-- Test 14: Error handling - invalid body_id
-- ============================================================
SELECT 'invalid_body_de' AS test, planet_heliocentric_de(9, now());

-- ============================================================
-- Test 15: Error handling - cannot observe Earth from Earth
-- ============================================================
SELECT 'earth_error_de' AS test, planet_observe_de(3, :boulder, now());
