-- Test equatorial GiST index: KNN ordering, RA wrapping, cone search
CREATE EXTENSION IF NOT EXISTS pg_orrery;

-- ============================================================
-- Test table: known sky positions
-- ============================================================
CREATE TABLE sky_test (
    id serial,
    name text,
    eq equatorial
);

-- Planets and Sun at a fixed epoch
INSERT INTO sky_test (name, eq) VALUES
    ('Jupiter', planet_equatorial_apparent(5, '2024-06-15 12:00:00+00')),
    ('Saturn',  planet_equatorial_apparent(6, '2024-06-15 12:00:00+00')),
    ('Mars',    planet_equatorial_apparent(4, '2024-06-15 12:00:00+00')),
    ('Venus',   planet_equatorial_apparent(2, '2024-06-15 12:00:00+00')),
    ('Mercury', planet_equatorial_apparent(1, '2024-06-15 12:00:00+00')),
    ('Sun',     sun_equatorial('2024-06-15 12:00:00+00')),
    ('Moon',    moon_equatorial('2024-06-15 12:00:00+00'));

-- Bright stars at well-known positions
INSERT INTO sky_test (name, eq) VALUES
    ('Polaris',  star_equatorial(2.530, 89.264, '2024-06-15 12:00:00+00')),
    ('Sirius',   star_equatorial(6.752, -16.716, '2024-06-15 12:00:00+00')),
    ('Vega',     star_equatorial(18.616, 38.784, '2024-06-15 12:00:00+00')),
    ('Canopus',  star_equatorial(6.399, -52.696, '2024-06-15 12:00:00+00')),
    ('Arcturus', star_equatorial(14.261, 19.182, '2024-06-15 12:00:00+00'));

-- RA-wrapping test: objects near 0h and 23.9h
INSERT INTO sky_test (name, eq) VALUES
    ('NearZeroH',  '(0.10000000,15.00000000,0.000)'::equatorial),
    ('Near24H',    '(23.90000000,15.00000000,0.000)'::equatorial);

-- ============================================================
-- Test 1: Create GiST index
-- ============================================================
CREATE INDEX idx_sky_gist ON sky_test USING gist (eq);

-- ============================================================
-- Test 2: KNN correctness -- seqscan vs index scan
-- Query: 5 nearest to Jupiter
-- ============================================================
-- First get seqscan ordering
SET enable_indexscan = off;
SET enable_bitmapscan = off;
SELECT 'knn_seq' AS test, name,
       round((eq <-> planet_equatorial_apparent(5, '2024-06-15 12:00:00+00'))::numeric, 4) AS dist
FROM sky_test
WHERE name != 'Jupiter'
ORDER BY eq <-> planet_equatorial_apparent(5, '2024-06-15 12:00:00+00')
LIMIT 5;
RESET enable_indexscan;
RESET enable_bitmapscan;

-- Now force index scan
SET enable_seqscan = off;
SELECT 'knn_idx' AS test, name,
       round((eq <-> planet_equatorial_apparent(5, '2024-06-15 12:00:00+00'))::numeric, 4) AS dist
FROM sky_test
WHERE name != 'Jupiter'
ORDER BY eq <-> planet_equatorial_apparent(5, '2024-06-15 12:00:00+00')
LIMIT 5;
RESET enable_seqscan;

-- ============================================================
-- Test 3: KNN near Polaris (high declination)
-- ============================================================
SET enable_seqscan = off;
SELECT 'knn_polaris' AS test, name,
       round((eq <-> star_equatorial(2.530, 89.264, '2024-06-15 12:00:00+00'))::numeric, 2) AS dist
FROM sky_test
ORDER BY eq <-> star_equatorial(2.530, 89.264, '2024-06-15 12:00:00+00')
LIMIT 3;
RESET enable_seqscan;

-- ============================================================
-- Test 4: RA wrapping -- NearZeroH and Near24H should be neighbors
-- (They are only 0.2h * 15 deg/h * cos(15) ~ 2.9 deg apart)
-- ============================================================
SET enable_seqscan = off;
SELECT 'ra_wrap' AS test, name,
       round((eq <-> '(0.10000000,15.00000000,0.000)'::equatorial)::numeric, 2) AS dist
FROM sky_test
ORDER BY eq <-> '(0.10000000,15.00000000,0.000)'::equatorial
LIMIT 3;
RESET enable_seqscan;

-- ============================================================
-- Test 5: Cone search -- everything within 15 degrees of Vega
-- ============================================================
SET enable_seqscan = off;
SELECT 'cone_vega' AS test, name,
       round((eq <-> star_equatorial(18.616, 38.784, '2024-06-15 12:00:00+00'))::numeric, 2) AS dist
FROM sky_test
WHERE eq_within_cone(eq, star_equatorial(18.616, 38.784, '2024-06-15 12:00:00+00'), 15.0)
ORDER BY eq <-> star_equatorial(18.616, 38.784, '2024-06-15 12:00:00+00');
RESET enable_seqscan;

-- ============================================================
-- Test 6: EXPLAIN shows Index Scan
-- ============================================================
SET enable_seqscan = off;
EXPLAIN (COSTS OFF)
SELECT name FROM sky_test
ORDER BY eq <-> '(12.00000000,0.00000000,0.000)'::equatorial
LIMIT 3;
RESET enable_seqscan;

-- ============================================================
-- Test 7: Empty table doesn't crash
-- ============================================================
CREATE TABLE sky_empty (eq equatorial);
CREATE INDEX idx_sky_empty ON sky_empty USING gist (eq);
SELECT 'empty_knn' AS test, count(*) AS n
FROM (
    SELECT eq FROM sky_empty
    ORDER BY eq <-> '(12.00000000,0.00000000,0.000)'::equatorial
) sub;
DROP TABLE sky_empty;

-- ============================================================
-- Test 8: Single row
-- ============================================================
CREATE TABLE sky_single (eq equatorial);
INSERT INTO sky_single VALUES ('(6.00000000,30.00000000,1000.000)'::equatorial);
CREATE INDEX idx_sky_single ON sky_single USING gist (eq);
SET enable_seqscan = off;
SELECT 'single_knn' AS test,
       round((eq <-> '(12.00000000,0.00000000,0.000)'::equatorial)::numeric, 2) AS dist
FROM sky_single
ORDER BY eq <-> '(12.00000000,0.00000000,0.000)'::equatorial
LIMIT 1;
RESET enable_seqscan;
DROP TABLE sky_single;

-- ============================================================
-- Test 9: Larger batch -- verify no crashes on tree rebalancing
-- ============================================================
CREATE TABLE sky_batch (eq equatorial);
INSERT INTO sky_batch
SELECT planet_equatorial_apparent(
    (i % 7) + 1 + (CASE WHEN (i % 7) + 1 >= 3 THEN 1 ELSE 0 END),
    '2024-01-01 00:00:00+00'::timestamptz + (i || ' hours')::interval
)
FROM generate_series(1, 100) AS i;
CREATE INDEX idx_sky_batch ON sky_batch USING gist (eq);
SET enable_seqscan = off;
SELECT 'batch_knn' AS test, count(*) AS n
FROM (
    SELECT eq
    FROM sky_batch
    ORDER BY eq <-> '(12.00000000,0.00000000,0.000)'::equatorial
    LIMIT 10
) sub;
RESET enable_seqscan;
DROP TABLE sky_batch;

-- Cleanup
DROP TABLE sky_test;
