-- PostgreSQL UUID v8 regression test

-- Load extension
CREATE EXTENSION pg_uuid_v8;

-- Basic extension loading test
SELECT extname FROM pg_extension WHERE extname = 'pg_uuid_v8';

-- Test steganographic UUID generation
SELECT uuid_stego_generate() IS NOT NULL;

-- Test that generated UUIDs look like version 4
WITH test_uuid AS (
  SELECT uuid_stego_generate() as u
)
SELECT
  -- Check version character (should be 4)
  substring(u::text from 15 for 1) = '4' as is_version_4,
  -- Check variant character (should be 8, 9, A, or B)
  substring(u::text from 20 for 1) IN ('8', '9', 'a', 'b') as is_correct_variant
FROM test_uuid;

-- Test seed functionality
SELECT uuid_stego_set_seed('test_seed_123');
SELECT uuid_stego_get_seed();

-- Test timestamp extraction
WITH test_data AS (
  SELECT uuid_stego_generate() as uuid1, uuid_stego_generate() as uuid2
)
SELECT
  uuid_stego_extract_timestamp(uuid1) > 0 as has_timestamp1,
  uuid_stego_extract_timestamp(uuid2) > 0 as has_timestamp2,
  uuid_stego_extract_timestamp(uuid2) >= uuid_stego_extract_timestamp(uuid1) as timestamp_order
FROM test_data;

-- Regression test for the 48-bit-microsecond truncation bug (fixed in 1.1):
-- the recovered timestamp must be close to real wall-clock time, not just
-- monotonically ordered. Before the fix this was off by ~1e15 us; 5 second
-- tolerance is generous for test-runner clock/scheduling noise while still
-- failing hard on the old bug.
WITH t AS (
  SELECT uuid_stego_generate() AS id,
         (extract(epoch FROM clock_timestamp()) * 1000000)::bigint AS now_us
)
SELECT abs(uuid_stego_extract_timestamp(id) - now_us) < 5000000 AS absolute_timestamp_recovered
FROM t;

-- uuid_stego_in_range against real wall-clock bounds (was unconditionally
-- false before the fix, since the truncated field could never reach a
-- current epoch-microsecond value)
SELECT uuid_stego_in_range(
  uuid_stego_generate(),
  clock_timestamp() - interval '5 seconds',
  clock_timestamp() + interval '5 seconds'
) AS in_range_works;

-- Test comparison functions
-- (the pg_sleep forces u1/u2 into different millisecond buckets -- as of 1.1
-- the stego timestamp has millisecond resolution, so two generate() calls
-- issued back-to-back can legitimately tie without it)
WITH test_uuids AS (
  SELECT uuid_stego_generate() as u1, pg_sleep(0.005), uuid_stego_generate() as u2
)
SELECT
  uuid_stego_compare(u1, u1) = 0 as self_equal,
  uuid_stego_compare(u1, u2) != 0 OR uuid_stego_compare(u2, u1) != 0 as different_comparison
FROM test_uuids;

-- Test operators
WITH test_uuids AS (
  SELECT uuid_stego_generate() as u1, pg_sleep(0.005), uuid_stego_generate() as u2
)
SELECT
  CASE WHEN u1 = u2 THEN true
       WHEN uuid_stego_lt(u1, u2) THEN uuid_stego_gt(u2, u1)
       WHEN uuid_stego_gt(u1, u2) THEN uuid_stego_lt(u2, u1)
       ELSE false
  END as operators_consistent
FROM test_uuids;

-- Test with different seeds
SELECT uuid_stego_set_seed('seed1');
SELECT uuid_stego_get_seed() = 'seed1' as seed_set_correctly;

SELECT uuid_stego_set_seed('seed2');
SELECT uuid_stego_get_seed() = 'seed2' as seed_changed_correctly;

-- Reset to default seed
SELECT uuid_stego_set_seed('pg_iuuid_default_seed_2024');
SELECT uuid_stego_get_seed() = 'pg_iuuid_default_seed_2024' as seed_reset;

-- Test encryption mode functionality
SELECT '=== Testing encryption modes ===' as test_encryption;

-- Test default mode
SELECT uuid_stego_get_encryption_mode() = 'XOR' as default_mode_xor;

-- Test mode setting
SELECT uuid_stego_set_encryption_mode('AES128');
SELECT uuid_stego_get_encryption_mode() = 'AES128' as mode_set_aes128;

-- Test UUID generation with AES128
SELECT uuid_stego_generate() IS NOT NULL as aes128_generation;

-- Test timestamp extraction with AES128 (not a correctness check: known
-- issue, tracked separately -- AES128/256 modes truncate the ciphertext
-- block before storage, so decrypted values are not reliable. This only
-- asserts extraction doesn't error/crash under AES mode.)
WITH aes_test AS (
    SELECT uuid_stego_generate() as aes_uuid
)
SELECT uuid_stego_extract_timestamp(aes_uuid) IS NOT NULL as aes128_extraction
FROM aes_test;

-- Test AES256 mode
SELECT uuid_stego_set_encryption_mode('AES256');
SELECT uuid_stego_get_encryption_mode() = 'AES256' as mode_set_aes256;

-- Test UUID generation with AES256
SELECT uuid_stego_generate() IS NOT NULL as aes256_generation;

-- Reset to XOR mode for compatibility
SELECT uuid_stego_set_encryption_mode('XOR');
SELECT uuid_stego_get_encryption_mode() = 'XOR' as mode_reset_xor;

-- Test UUID v8 convenience aliases
SELECT '=== Testing UUID v8 aliases ===' as test_aliases;

-- Test uuid_v8_generate
SELECT uuid_v8_generate() IS NOT NULL as v8_generation;

-- Test uuid_v8_extract_timestamp
WITH v8_test AS (
    SELECT uuid_v8_generate() as v8_uuid
)
SELECT uuid_v8_extract_timestamp(v8_uuid) > 0 as v8_extraction
FROM v8_test;

-- Test uuid_v8_compare
WITH v8_compare AS (
    SELECT uuid_v8_generate() as u1, pg_sleep(0.005), uuid_v8_generate() as u2
)
SELECT
    uuid_v8_compare(u1, u1) = 0 as v8_self_equal,
    uuid_v8_compare(u1, u2) != 0 OR uuid_v8_compare(u2, u1) != 0 as v8_different
FROM v8_compare;

-- Test uuid_v8 configuration functions
SELECT uuid_v8_set_seed('v8_test_seed');
SELECT uuid_v8_get_seed() = 'v8_test_seed' as v8_seed_test;

SELECT uuid_v8_set_encryption_mode('AES128');
SELECT uuid_v8_get_encryption_mode() = 'AES128' as v8_encryption_test;

-- Reset to defaults
SELECT uuid_v8_set_seed('uuid_v8_default_seed_2024');
SELECT uuid_v8_set_encryption_mode('XOR');