-- v017_features.sql -- Tests for v0.17.0: solar elongation, planet phase,
-- satellite eclipse, observing night quality, lunar libration
--
-- Verifies all 12 new functions added in v0.17.0.
CREATE EXTENSION IF NOT EXISTS pg_orrery;

-- ============================================================
-- Solar elongation: Mercury always < 28 deg
-- ============================================================

SELECT solar_elongation(1, '2024-01-15 00:00:00+00'::timestamptz) < 28.0
    AS mercury_max_elongation;

-- ============================================================
-- Solar elongation: Venus always < 47 deg
-- ============================================================

SELECT solar_elongation(2, '2024-01-15 00:00:00+00'::timestamptz) < 47.5
    AS venus_max_elongation;

-- ============================================================
-- Solar elongation: Mars can exceed 90 deg (superior planet)
-- Use a date near opposition (2024-01-12 Mars at elongation ~180)
-- At least verify it can be large for outer planets
-- ============================================================

SELECT solar_elongation(4, '2024-12-08 00:00:00+00'::timestamptz) > 50.0
    AS mars_large_elongation;

-- ============================================================
-- Solar elongation: always [0, 180]
-- ============================================================

SELECT bool_and(
    solar_elongation(body_id, '2024-06-15 00:00:00+00'::timestamptz) >= 0.0
    AND solar_elongation(body_id, '2024-06-15 00:00:00+00'::timestamptz) <= 180.0
) AS elongation_in_range
FROM (VALUES (1),(2),(4),(5),(6),(7),(8)) AS t(body_id);

-- ============================================================
-- Solar elongation: error on body_id 0, 3, 9
-- ============================================================

DO $$ BEGIN PERFORM solar_elongation(0, '2024-01-15 00:00:00+00'::timestamptz); EXCEPTION WHEN OTHERS THEN RAISE NOTICE 'elong body_id=0: %', SQLERRM; END $$;
DO $$ BEGIN PERFORM solar_elongation(3, '2024-01-15 00:00:00+00'::timestamptz); EXCEPTION WHEN OTHERS THEN RAISE NOTICE 'elong body_id=3: %', SQLERRM; END $$;
DO $$ BEGIN PERFORM solar_elongation(9, '2024-01-15 00:00:00+00'::timestamptz); EXCEPTION WHEN OTHERS THEN RAISE NOTICE 'elong body_id=9: %', SQLERRM; END $$;

-- ============================================================
-- Planet phase: Jupiter always near 1.0 (outer planet)
-- ============================================================

SELECT planet_phase(5, '2024-01-15 00:00:00+00'::timestamptz) > 0.95
    AS jupiter_nearly_full;

-- ============================================================
-- Planet phase: Neptune always near 1.0
-- ============================================================

SELECT planet_phase(8, '2024-06-15 00:00:00+00'::timestamptz) > 0.99
    AS neptune_nearly_full;

-- ============================================================
-- Planet phase: Venus varies significantly (inner planet)
-- Check it's in valid range
-- ============================================================

SELECT planet_phase(2, '2024-06-01 12:00:00+00'::timestamptz) BETWEEN 0.0 AND 1.0
    AS venus_phase_valid;

-- ============================================================
-- Planet phase: always [0, 1] for all planets
-- ============================================================

SELECT bool_and(
    planet_phase(body_id, '2024-01-15 00:00:00+00'::timestamptz) >= 0.0
    AND planet_phase(body_id, '2024-01-15 00:00:00+00'::timestamptz) <= 1.0
) AS phase_in_range
FROM (VALUES (1),(2),(4),(5),(6),(7),(8)) AS t(body_id);

-- ============================================================
-- Planet phase: error cases match elongation
-- ============================================================

DO $$ BEGIN PERFORM planet_phase(3, '2024-01-15 00:00:00+00'::timestamptz); EXCEPTION WHEN OTHERS THEN RAISE NOTICE 'phase body_id=3: %', SQLERRM; END $$;

-- ============================================================
-- Satellite eclipse: ISS point-in-time test
-- (At night the ISS can be eclipsed; just verify function returns bool)
-- ============================================================

SELECT satellite_is_eclipsed(
    E'1 25544U 98067A   24001.50000000  .00016717  00000-0  10270-3 0  9025\n2 25544  51.6400 208.9163 0006703  30.1694  61.7520 15.50100486 00001'::tle,
    '2024-01-01 12:00:00+00'::timestamptz
) IS NOT NULL
    AS eclipse_returns_bool;

-- ============================================================
-- Satellite eclipse: next entry/exit return timestamps or NULL
-- ============================================================

SELECT satellite_next_eclipse_entry(
    E'1 25544U 98067A   24001.50000000  .00016717  00000-0  10270-3 0  9025\n2 25544  51.6400 208.9163 0006703  30.1694  61.7520 15.50100486 00001'::tle,
    '2024-01-01 12:00:00+00'::timestamptz
) > '2024-01-01 12:00:00+00'::timestamptz
    AS entry_in_future;

SELECT satellite_next_eclipse_exit(
    E'1 25544U 98067A   24001.50000000  .00016717  00000-0  10270-3 0  9025\n2 25544  51.6400 208.9163 0006703  30.1694  61.7520 15.50100486 00001'::tle,
    '2024-01-01 12:00:00+00'::timestamptz
) > '2024-01-01 12:00:00+00'::timestamptz
    AS exit_in_future;

-- ============================================================
-- Satellite eclipse: fraction in [0, 1] for a 2-hour window
-- ============================================================

SELECT satellite_eclipse_fraction(
    E'1 25544U 98067A   24001.50000000  .00016717  00000-0  10270-3 0  9025\n2 25544  51.6400 208.9163 0006703  30.1694  61.7520 15.50100486 00001'::tle,
    '2024-01-01 12:00:00+00'::timestamptz,
    '2024-01-01 14:00:00+00'::timestamptz
) BETWEEN 0.0 AND 1.0
    AS eclipse_fraction_valid;

-- ============================================================
-- Observing night quality: polar summer at 65N = 'poor'
-- (no astronomical darkness in June)
-- ============================================================

SELECT observing_night_quality('(65.0,25.0,0)'::observer, '2024-06-21 12:00:00+00'::timestamptz) = 'poor'
    AS polar_summer_poor;

-- ============================================================
-- Observing night quality: winter mid-latitude returns valid rating
-- ============================================================

SELECT observing_night_quality('(43.7,-116.4,800)'::observer, '2024-12-21 12:00:00+00'::timestamptz)
    IN ('excellent', 'good', 'fair', 'poor')
    AS winter_valid_rating;

-- ============================================================
-- Lunar libration: longitude in [-8, 8] range
-- ============================================================

SELECT moon_libration_longitude('2024-01-15 00:00:00+00'::timestamptz) BETWEEN -8.5 AND 8.5
    AS libration_lon_in_range;

SELECT moon_libration_longitude('2024-06-15 00:00:00+00'::timestamptz) BETWEEN -8.5 AND 8.5
    AS libration_lon_in_range_2;

-- ============================================================
-- Lunar libration: latitude in [-7, 7] range
-- ============================================================

SELECT moon_libration_latitude('2024-01-15 00:00:00+00'::timestamptz) BETWEEN -7.5 AND 7.5
    AS libration_lat_in_range;

SELECT moon_libration_latitude('2024-06-15 00:00:00+00'::timestamptz) BETWEEN -7.5 AND 7.5
    AS libration_lat_in_range_2;

-- ============================================================
-- Lunar libration: position angle in [0, 360)
-- ============================================================

SELECT moon_libration_position_angle('2024-01-15 00:00:00+00'::timestamptz) BETWEEN -1.0 AND 361.0
    AS libration_pa_in_range;

-- ============================================================
-- Lunar libration: composite returns same as individual functions
-- ============================================================

SELECT abs((moon_libration('2024-01-15 00:00:00+00'::timestamptz)).l
         - moon_libration_longitude('2024-01-15 00:00:00+00'::timestamptz)) < 0.001
    AS composite_matches_lon;

SELECT abs((moon_libration('2024-01-15 00:00:00+00'::timestamptz)).b
         - moon_libration_latitude('2024-01-15 00:00:00+00'::timestamptz)) < 0.001
    AS composite_matches_lat;

-- ============================================================
-- Lunar libration: changes over time (not constant)
-- ============================================================

SELECT moon_libration_longitude('2024-01-01 00:00:00+00'::timestamptz)
    != moon_libration_longitude('2024-01-15 00:00:00+00'::timestamptz)
    AS libration_varies;

-- ============================================================
-- Subsolar longitude: in [0, 360) range
-- ============================================================

SELECT moon_subsolar_longitude('2024-01-15 00:00:00+00'::timestamptz) BETWEEN 0.0 AND 360.0
    AS subsolar_in_range;

SELECT moon_subsolar_longitude('2024-06-15 00:00:00+00'::timestamptz) BETWEEN 0.0 AND 360.0
    AS subsolar_in_range_2;

-- ============================================================
-- Subsolar longitude: changes significantly over synodic month
-- (full 360 degrees over ~29.5 days)
-- ============================================================

SELECT abs(moon_subsolar_longitude('2024-01-01 00:00:00+00'::timestamptz)
         - moon_subsolar_longitude('2024-01-15 00:00:00+00'::timestamptz)) > 10.0
    AS subsolar_moves;
