-- v016_features.sql -- Tests for v0.16.0: twilight, lunar phase, planet magnitude
--
-- Verifies twilight dawn/dusk, lunar phase calculations,
-- and planet apparent magnitude.
CREATE EXTENSION IF NOT EXISTS pg_orrery;

-- ============================================================
-- Twilight: ordering (astronomical < nautical < civil < sunrise)
-- Eagle, Idaho on the 2024 summer solstice
-- ============================================================

-- Dawn ordering: astronomical dawn < nautical dawn < civil dawn < sunrise
-- Use midnight MDT (07:00 UTC) so all "next" events land on the same morning
SELECT sun_astronomical_dawn('(43.7,-116.4,800)'::observer, '2024-06-21 07:00:00+00'::timestamptz)
     < sun_nautical_dawn('(43.7,-116.4,800)'::observer, '2024-06-21 07:00:00+00'::timestamptz)
    AS astro_before_nautical;

SELECT sun_nautical_dawn('(43.7,-116.4,800)'::observer, '2024-06-21 07:00:00+00'::timestamptz)
     < sun_civil_dawn('(43.7,-116.4,800)'::observer, '2024-06-21 07:00:00+00'::timestamptz)
    AS nautical_before_civil;

SELECT sun_civil_dawn('(43.7,-116.4,800)'::observer, '2024-06-21 07:00:00+00'::timestamptz)
     < sun_next_rise('(43.7,-116.4,800)'::observer, '2024-06-21 07:00:00+00'::timestamptz)
    AS civil_before_sunrise;

-- Dusk ordering: sunset < civil dusk < nautical dusk < astronomical dusk
-- Noon MDT (18:00 UTC) ensures all dusk events are still ahead
SELECT sun_next_set('(43.7,-116.4,800)'::observer, '2024-06-21 18:00:00+00'::timestamptz)
     < sun_civil_dusk('(43.7,-116.4,800)'::observer, '2024-06-21 18:00:00+00'::timestamptz)
    AS sunset_before_civil;

SELECT sun_civil_dusk('(43.7,-116.4,800)'::observer, '2024-06-21 18:00:00+00'::timestamptz)
     < sun_nautical_dusk('(43.7,-116.4,800)'::observer, '2024-06-21 18:00:00+00'::timestamptz)
    AS civil_before_nautical;

SELECT sun_nautical_dusk('(43.7,-116.4,800)'::observer, '2024-06-21 18:00:00+00'::timestamptz)
     < sun_astronomical_dusk('(43.7,-116.4,800)'::observer, '2024-06-21 18:00:00+00'::timestamptz)
    AS nautical_before_astro;

-- ============================================================
-- Twilight: civil dawn ~30 min before sunrise at mid-latitude
-- ============================================================

SELECT extract(epoch FROM
    sun_next_rise('(43.7,-116.4,800)'::observer, '2024-06-21 07:00:00+00'::timestamptz)
    - sun_civil_dawn('(43.7,-116.4,800)'::observer, '2024-06-21 07:00:00+00'::timestamptz)
) BETWEEN 1200 AND 3600
    AS civil_dawn_reasonable_offset;

-- ============================================================
-- Twilight: high latitude summer -- no astronomical darkness
-- At 60N in June, astronomical dusk should be NULL (never gets dark enough)
-- ============================================================

SELECT sun_astronomical_dusk('(60.0,25.0,0)'::observer, '2024-06-21 00:00:00+00'::timestamptz) IS NULL
    AS no_astro_dark_60n_summer;

-- ============================================================
-- Lunar phase: known full moon (2024-01-25 ~17:54 UTC)
-- Phase angle should be near 180 deg, illumination near 1.0
-- ============================================================

SELECT round(moon_phase_angle('2024-01-25 18:00:00+00'::timestamptz)::numeric, 0)
    BETWEEN 170 AND 190
    AS full_moon_angle_near_180;

SELECT round(moon_illumination('2024-01-25 18:00:00+00'::timestamptz)::numeric, 2)
    >= 0.95
    AS full_moon_high_illumination;

SELECT moon_phase_name('2024-01-25 18:00:00+00'::timestamptz) = 'full_moon'
    AS full_moon_named;

-- ============================================================
-- Lunar phase: known new moon (2024-01-11 ~11:57 UTC)
-- Phase angle should be near 0 or 360, illumination near 0
-- ============================================================

SELECT moon_illumination('2024-01-11 12:00:00+00'::timestamptz)
    < 0.05
    AS new_moon_low_illumination;

SELECT moon_phase_name('2024-01-11 12:00:00+00'::timestamptz) = 'new_moon'
    AS new_moon_named;

-- ============================================================
-- Lunar phase: first quarter (2024-01-18 ~03:53 UTC)
-- Phase angle near 90, illumination near 0.5
-- ============================================================

SELECT round(moon_phase_angle('2024-01-18 04:00:00+00'::timestamptz)::numeric, 0)
    BETWEEN 80 AND 100
    AS first_quarter_angle_near_90;

SELECT moon_illumination('2024-01-18 04:00:00+00'::timestamptz)
    BETWEEN 0.4 AND 0.6
    AS first_quarter_half_illuminated;

SELECT moon_phase_name('2024-01-18 04:00:00+00'::timestamptz) = 'first_quarter'
    AS first_quarter_named;

-- ============================================================
-- Moon age: new moon has age near 0, full moon near 14.7
-- ============================================================

SELECT moon_age('2024-01-11 12:00:00+00'::timestamptz) < 2.0
    AS new_moon_young;

SELECT moon_age('2024-01-25 18:00:00+00'::timestamptz)
    BETWEEN 12.0 AND 17.0
    AS full_moon_age_midcycle;

-- ============================================================
-- Illumination range: always [0, 1]
-- ============================================================

SELECT moon_illumination('2024-06-01 00:00:00+00'::timestamptz) BETWEEN 0.0 AND 1.0
   AND moon_illumination('2024-09-01 00:00:00+00'::timestamptz) BETWEEN 0.0 AND 1.0
   AND moon_illumination('2024-12-01 00:00:00+00'::timestamptz) BETWEEN 0.0 AND 1.0
    AS illumination_always_valid;

-- ============================================================
-- Planet magnitude: Jupiter should be bright (negative mag)
-- ============================================================

SELECT planet_magnitude(5, '2024-01-15 00:00:00+00'::timestamptz) < 0.0
    AS jupiter_is_bright;

-- ============================================================
-- Planet magnitude: Venus is the brightest planet
-- ============================================================

SELECT planet_magnitude(2, '2024-06-01 12:00:00+00'::timestamptz)
     < planet_magnitude(4, '2024-06-01 12:00:00+00'::timestamptz)
    AS venus_brighter_than_mars;

-- ============================================================
-- Planet magnitude: Neptune is faint (~+7-8)
-- ============================================================

SELECT planet_magnitude(8, '2024-01-15 00:00:00+00'::timestamptz) > 7.0
    AS neptune_is_faint;

-- ============================================================
-- Planet magnitude: all planets return finite values
-- ============================================================

SELECT bool_and(
    planet_magnitude(body_id, '2024-01-15 00:00:00+00'::timestamptz) IS NOT NULL
    AND planet_magnitude(body_id, '2024-01-15 00:00:00+00'::timestamptz) > -30
    AND planet_magnitude(body_id, '2024-01-15 00:00:00+00'::timestamptz) < 30
) AS all_magnitudes_finite
FROM (VALUES (1),(2),(4),(5),(6),(7),(8)) AS t(body_id);

-- ============================================================
-- Planet magnitude: error cases
-- ============================================================

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