-- v018_features.sql -- Tests for v0.18.0: Saturn ring tilt, penumbral eclipse,
-- rise/set event windows, angular separation rate
--
-- Verifies all 10 new functions added in v0.18.0.

CREATE EXTENSION IF NOT EXISTS pg_orrery;

-- ============================================================
-- Saturn ring tilt: in [-27, +27] range
-- ============================================================

SELECT saturn_ring_tilt('2024-01-15 00:00:00+00'::timestamptz) BETWEEN -27.0 AND 27.0
    AS ring_tilt_in_range;

-- ============================================================
-- Saturn ring tilt: near zero around 2025 ring crossing
-- (rings edge-on to Earth around March 2025)
-- ============================================================

SELECT abs(saturn_ring_tilt('2025-03-23 00:00:00+00'::timestamptz)) < 5.0
    AS ring_tilt_near_edge_on;

-- ============================================================
-- Saturn ring tilt: varies over time (not constant)
-- ============================================================

SELECT saturn_ring_tilt('2024-01-01 00:00:00+00'::timestamptz)
    != saturn_ring_tilt('2024-07-01 00:00:00+00'::timestamptz)
    AS ring_tilt_varies;

-- ============================================================
-- Saturn ring tilt: sign changes across ring plane crossing
-- (2017 was fully open, 2025 is edge-on, tilt changes sign)
-- ============================================================

SELECT abs(saturn_ring_tilt('2017-06-15 00:00:00+00'::timestamptz)) > 10.0
    AS ring_tilt_open_2017;

-- ============================================================
-- Planet magnitude: Saturn now includes ring correction
-- (ring-corrected magnitude should differ from globe-only)
-- Saturn magnitude should be roughly between -0.5 and +1.5
-- ============================================================

SELECT planet_magnitude(6, '2024-01-15 00:00:00+00'::timestamptz) BETWEEN -1.0 AND 2.0
    AS saturn_mag_valid_range;

-- ============================================================
-- Satellite shadow state: returns valid text values
-- ============================================================

SELECT satellite_shadow_state(
    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
) IN ('sunlit', 'penumbra', 'umbra')
    AS shadow_state_valid;

-- ============================================================
-- Satellite in penumbra: returns bool
-- ============================================================

SELECT satellite_in_penumbra(
    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 penumbra_returns_bool;

-- ============================================================
-- Backward compatibility: satellite_is_eclipsed still works
-- (cone model upgrade is internal-only)
-- ============================================================

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_backward_compat;

-- ============================================================
-- Penumbra entry precedes umbra entry (penumbra is outer zone)
-- ============================================================

SELECT satellite_next_penumbra_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
) <= 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
) AS penumbra_precedes_umbra;

-- ============================================================
-- Penumbra exit is after penumbra entry
-- ============================================================

SELECT satellite_next_penumbra_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 penumbra_exit_in_future;

-- ============================================================
-- Eclipse fraction still valid after cone upgrade
-- ============================================================

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_still_valid;

-- ============================================================
-- Sun rise/set events: mid-latitude 24h window returns events
-- ============================================================

SELECT count(*) >= 1 AS sun_events_exist
FROM sun_rise_set_events(
    '(43.7,-116.4,800)'::observer,
    '2024-06-21 00:00:00+00'::timestamptz,
    '2024-06-22 00:00:00+00'::timestamptz
);

-- ============================================================
-- Sun rise/set events: events alternate rise/set
-- ============================================================

SELECT bool_and(event_type IN ('rise', 'set')) AS sun_event_types_valid
FROM sun_rise_set_events(
    '(43.7,-116.4,800)'::observer,
    '2024-06-21 00:00:00+00'::timestamptz,
    '2024-06-22 00:00:00+00'::timestamptz
);

-- ============================================================
-- Sun rise/set events: refracted vs geometric
-- (refracted rise is earlier than geometric rise)
-- ============================================================

SELECT (SELECT min(event_time) FROM sun_rise_set_events(
    '(43.7,-116.4,800)'::observer,
    '2024-06-21 00:00:00+00'::timestamptz,
    '2024-06-22 00:00:00+00'::timestamptz,
    true
) WHERE event_type = 'rise')
<=
(SELECT min(event_time) FROM sun_rise_set_events(
    '(43.7,-116.4,800)'::observer,
    '2024-06-21 00:00:00+00'::timestamptz,
    '2024-06-22 00:00:00+00'::timestamptz,
    false
) WHERE event_type = 'rise')
    AS refracted_rise_earlier;

-- ============================================================
-- Moon rise/set events: returns valid event types
-- ============================================================

SELECT bool_and(event_type IN ('rise', 'set')) AS moon_event_types_valid
FROM moon_rise_set_events(
    '(43.7,-116.4,800)'::observer,
    '2024-01-15 00:00:00+00'::timestamptz,
    '2024-01-16 00:00:00+00'::timestamptz
);

-- ============================================================
-- Planet rise/set events: Jupiter over 24h
-- ============================================================

SELECT count(*) >= 1 AS jupiter_events_exist
FROM planet_rise_set_events(
    5,
    '(43.7,-116.4,800)'::observer,
    '2024-01-15 00:00:00+00'::timestamptz,
    '2024-01-16 00:00:00+00'::timestamptz
);

-- ============================================================
-- Rise/set events: window > 366 days rejected
-- ============================================================

DO $$ BEGIN
    PERFORM * FROM sun_rise_set_events(
        '(43.7,-116.4,800)'::observer,
        '2024-01-01 00:00:00+00'::timestamptz,
        '2025-03-01 00:00:00+00'::timestamptz
    );
EXCEPTION WHEN OTHERS THEN
    RAISE NOTICE 'window overflow: %', SQLERRM;
END $$;

-- ============================================================
-- Rise/set events: stop before start rejected
-- ============================================================

DO $$ BEGIN
    PERFORM * FROM sun_rise_set_events(
        '(43.7,-116.4,800)'::observer,
        '2024-06-22 00:00:00+00'::timestamptz,
        '2024-06-21 00:00:00+00'::timestamptz
    );
EXCEPTION WHEN OTHERS THEN
    RAISE NOTICE 'stop before start: %', SQLERRM;
END $$;

-- ============================================================
-- eq_angular_rate: generic rate computation
-- Two positions that are 10 deg apart, then 9 deg apart after 1 hour
-- should give rate = -1.0 deg/hr (approaching)
-- ============================================================

SELECT abs(eq_angular_rate(
    '(6.0, 45.0, 1.0)'::equatorial,
    '(6.667, 45.0, 1.0)'::equatorial,
    '(6.0, 45.0, 1.0)'::equatorial,
    '(6.6, 45.0, 1.0)'::equatorial,
    3600.0
)) > 0.0
    AS angular_rate_nonzero;

-- ============================================================
-- eq_angular_rate: dt_seconds <= 0 rejected
-- ============================================================

DO $$ BEGIN
    PERFORM eq_angular_rate(
        '(6.0, 45.0, 1.0)'::equatorial,
        '(7.0, 45.0, 1.0)'::equatorial,
        '(6.0, 45.0, 1.0)'::equatorial,
        '(7.0, 45.0, 1.0)'::equatorial,
        0.0
    );
EXCEPTION WHEN OTHERS THEN
    RAISE NOTICE 'dt_seconds=0: %', SQLERRM;
END $$;

-- ============================================================
-- planet_angular_rate: Moon rate ~0.5 deg/hr relative to Sun
-- ============================================================

SELECT abs(planet_angular_rate(0, 10, '2024-01-15 00:00:00+00'::timestamptz)) > 0.1
    AS moon_sun_rate_nonzero;

-- ============================================================
-- planet_angular_rate: same body rejected
-- ============================================================

DO $$ BEGIN
    PERFORM planet_angular_rate(5, 5, '2024-01-15 00:00:00+00'::timestamptz);
EXCEPTION WHEN OTHERS THEN
    RAISE NOTICE 'same body: %', SQLERRM;
END $$;

-- ============================================================
-- planet_angular_rate: Jupiter-Saturn rate is small
-- (outer planets move slowly)
-- ============================================================

SELECT abs(planet_angular_rate(5, 6, '2024-01-15 00:00:00+00'::timestamptz)) < 1.0
    AS outer_planet_rate_slow;
