-- ================================================================================================
-- TimescaleDB Features Test Suite
-- PostgreSQL 16.10 + TimescaleDB 2.22.1
-- Tests hypertables, partitioning, compression, and continuous aggregates
-- ================================================================================================

BEGIN;

-- ================================================================================================
-- TEST 1: TimescaleDB Extension Verification
-- Verify TimescaleDB is installed and check version
-- ================================================================================================
DO $$
DECLARE
    v_tsdb_version TEXT;
    v_pg_version TEXT;
BEGIN
    -- Check TimescaleDB version
    SELECT extversion INTO v_tsdb_version
    FROM pg_extension
    WHERE extname = 'timescaledb';

    IF v_tsdb_version IS NULL THEN
        RAISE EXCEPTION 'TEST 1 FAIL: TimescaleDB extension not installed';
    END IF;

    -- Check PostgreSQL version
    SELECT version() INTO v_pg_version;

    RAISE NOTICE 'TEST 1 PASS: TimescaleDB % installed on %', v_tsdb_version, split_part(v_pg_version, ',', 1);
    
    -- Verify minimum versions
    IF v_tsdb_version >= '2.22.0' THEN
        RAISE NOTICE 'TEST 1 INFO: TimescaleDB version meets minimum requirement (2.22.1)';
    ELSE
        RAISE WARNING 'TEST 1 WARNING: TimescaleDB version % may be below recommended 2.22.1', v_tsdb_version;
    END IF;
END $$;

-- ================================================================================================
-- TEST 2: Hypertable Configuration
-- Verify tables are configured as hypertables
-- ================================================================================================
DO $$
DECLARE
    v_expected_hypertables TEXT[] := ARRAY[
        'trading_events',
        'risk_events',
        'audit_events',
        'market_data_raw',
        'market_data_aggregated'
    ];
    v_table TEXT;
    v_hypertables TEXT[] := ARRAY[]::TEXT[];
    v_missing_hypertables TEXT[] := ARRAY[]::TEXT[];
BEGIN
    FOREACH v_table IN ARRAY v_expected_hypertables
    LOOP
        IF EXISTS (
            SELECT 1 FROM timescaledb_information.hypertables
            WHERE hypertable_name = v_table
        ) THEN
            v_hypertables := array_append(v_hypertables, v_table);
        ELSE
            -- Only add to missing if table exists but is not a hypertable
            IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = v_table) THEN
                v_missing_hypertables := array_append(v_missing_hypertables, v_table);
            END IF;
        END IF;
    END LOOP;

    IF array_length(v_hypertables, 1) > 0 THEN
        RAISE NOTICE 'TEST 2 PASS: Found % hypertables: %', 
            array_length(v_hypertables, 1), 
            array_to_string(v_hypertables, ', ');
    ELSE
        RAISE WARNING 'TEST 2 WARNING: No hypertables found';
    END IF;

    IF array_length(v_missing_hypertables, 1) > 0 THEN
        RAISE WARNING 'TEST 2 WARNING: Tables exist but are not hypertables: %', 
            array_to_string(v_missing_hypertables, ', ');
    END IF;
END $$;

-- ================================================================================================
-- TEST 3: Partition Configuration
-- Verify partition intervals are properly configured
-- ================================================================================================
DO $$
DECLARE
    v_hypertable_record RECORD;
    v_partition_info TEXT;
BEGIN
    FOR v_hypertable_record IN
        SELECT 
            hypertable_name,
            chunk_sizing_func,
            chunk_target_size
        FROM timescaledb_information.hypertables
        WHERE hypertable_schema = 'public'
    LOOP
        v_partition_info := v_hypertable_record.hypertable_name || 
            ' (sizing: ' || COALESCE(v_hypertable_record.chunk_sizing_func, 'default') || ')';
        
        RAISE NOTICE 'TEST 3 INFO: Hypertable partition config - %', v_partition_info;
    END LOOP;

    IF FOUND THEN
        RAISE NOTICE 'TEST 3 PASS: Partition configurations verified';
    ELSE
        RAISE WARNING 'TEST 3 WARNING: No hypertable partition configurations found';
    END IF;
END $$;

-- ================================================================================================
-- TEST 4: Chunk Management
-- Verify chunks are being created and managed properly
-- ================================================================================================
DO $$
DECLARE
    v_chunk_count INTEGER;
    v_hypertable_record RECORD;
BEGIN
    FOR v_hypertable_record IN
        SELECT 
            h.hypertable_name,
            COUNT(c.chunk_name) as chunk_count,
            pg_size_pretty(SUM(c.total_bytes)::bigint) as total_size
        FROM timescaledb_information.hypertables h
        LEFT JOIN timescaledb_information.chunks c 
            ON h.hypertable_name = c.hypertable_name
        WHERE h.hypertable_schema = 'public'
        GROUP BY h.hypertable_name
    LOOP
        RAISE NOTICE 'TEST 4 INFO: % has % chunks (total size: %)',
            v_hypertable_record.hypertable_name,
            v_hypertable_record.chunk_count,
            COALESCE(v_hypertable_record.total_size, '0 bytes');
    END LOOP;

    SELECT COUNT(*) INTO v_chunk_count
    FROM timescaledb_information.chunks
    WHERE hypertable_schema = 'public';

    IF v_chunk_count > 0 THEN
        RAISE NOTICE 'TEST 4 PASS: Chunk management operational (% total chunks)', v_chunk_count;
    ELSE
        RAISE NOTICE 'TEST 4 INFO: No chunks created yet (expected for empty hypertables)';
    END IF;
END $$;

-- ================================================================================================
-- TEST 5: Compression Policies
-- Verify compression is configured for time-series data
-- ================================================================================================
DO $$
DECLARE
    v_compression_record RECORD;
    v_compression_count INTEGER := 0;
BEGIN
    FOR v_compression_record IN
        SELECT 
            hypertable_name,
            attname as compressed_column,
            compression_algorithm
        FROM timescaledb_information.compression_settings
        WHERE hypertable_schema = 'public'
        ORDER BY hypertable_name, orderby_column_index
    LOOP
        v_compression_count := v_compression_count + 1;
        RAISE NOTICE 'TEST 5 INFO: Compression on %.% (algorithm: %)',
            v_compression_record.hypertable_name,
            v_compression_record.compressed_column,
            v_compression_record.compression_algorithm;
    END LOOP;

    IF v_compression_count > 0 THEN
        RAISE NOTICE 'TEST 5 PASS: Compression configured on % columns', v_compression_count;
    ELSE
        RAISE NOTICE 'TEST 5 INFO: No compression policies configured (may be intentional for hot data)';
    END IF;
END $$;

-- ================================================================================================
-- TEST 6: Retention Policies
-- Verify data retention policies are configured
-- ================================================================================================
DO $$
DECLARE
    v_retention_record RECORD;
    v_retention_count INTEGER := 0;
BEGIN
    FOR v_retention_record IN
        SELECT 
            hypertable_name,
            drop_after,
            schedule_interval
        FROM timescaledb_information.jobs j
        JOIN timescaledb_information.job_stats js ON j.job_id = js.job_id
        WHERE j.proc_name = 'policy_retention'
          AND hypertable_schema = 'public'
    LOOP
        v_retention_count := v_retention_count + 1;
        RAISE NOTICE 'TEST 6 INFO: Retention policy on % (drop after: %, interval: %)',
            v_retention_record.hypertable_name,
            v_retention_record.drop_after,
            v_retention_record.schedule_interval;
    END LOOP;

    IF v_retention_count > 0 THEN
        RAISE NOTICE 'TEST 6 PASS: Data retention policies configured (% policies)', v_retention_count;
    ELSE
        RAISE NOTICE 'TEST 6 INFO: No retention policies configured (manual management may be in use)';
    END IF;
END $$;

-- ================================================================================================
-- TEST 7: Continuous Aggregates
-- Verify continuous aggregates for real-time analytics
-- ================================================================================================
DO $$
DECLARE
    v_cagg_record RECORD;
    v_cagg_count INTEGER := 0;
BEGIN
    FOR v_cagg_record IN
        SELECT 
            view_name,
            materialization_hypertable_name,
            refresh_lag,
            refresh_interval
        FROM timescaledb_information.continuous_aggregates
        WHERE view_schema = 'public'
    LOOP
        v_cagg_count := v_cagg_count + 1;
        RAISE NOTICE 'TEST 7 INFO: Continuous aggregate % (lag: %, interval: %)',
            v_cagg_record.view_name,
            v_cagg_record.refresh_lag,
            v_cagg_record.refresh_interval;
    END LOOP;

    IF v_cagg_count > 0 THEN
        RAISE NOTICE 'TEST 7 PASS: Continuous aggregates configured (% aggregates)', v_cagg_count;
    ELSE
        RAISE NOTICE 'TEST 7 INFO: No continuous aggregates configured (may use real-time queries)';
    END IF;
END $$;

-- ================================================================================================
-- TEST 8: Hypertable Insert Performance
-- Test insertion into hypertable with automatic partitioning
-- ================================================================================================
DO $$
DECLARE
    v_start_time TIMESTAMP;
    v_end_time TIMESTAMP;
    v_duration INTERVAL;
    v_test_table TEXT := 'trading_events';
    v_current_ns BIGINT := EXTRACT(EPOCH FROM NOW())::BIGINT * 1000000000;
    i INTEGER;
BEGIN
    -- Check if table is a hypertable
    IF NOT EXISTS (
        SELECT 1 FROM timescaledb_information.hypertables
        WHERE hypertable_name = v_test_table
    ) THEN
        RAISE NOTICE 'TEST 8 INFO: Skipping - % is not a hypertable', v_test_table;
        RETURN;
    END IF;

    v_start_time := clock_timestamp();

    -- Insert 50 test events
    FOR i IN 1..50 LOOP
        INSERT INTO trading_events (
            correlation_id,
            event_timestamp,
            received_timestamp,
            processing_timestamp,
            event_type,
            event_source,
            symbol,
            event_data,
            event_hash,
            node_id,
            process_id
        ) VALUES (
            uuid_generate_v4(),
            v_current_ns + (i * 1000000), -- 1ms intervals
            v_current_ns + (i * 1000000),
            v_current_ns + (i * 1000000),
            'order_submitted',
            'test_suite',
            'PERF' || (i % 5),
            format('{"test_id": %s}', i)::jsonb,
            encode(sha256(('perf' || i)::bytea), 'hex'),
            'test-node',
            99999
        );
    END LOOP;

    v_end_time := clock_timestamp();
    v_duration := v_end_time - v_start_time;

    RAISE NOTICE 'TEST 8 PASS: Hypertable insert performance - 50 events in %', v_duration;

    IF v_duration > INTERVAL '100 milliseconds' THEN
        RAISE WARNING 'TEST 8 WARNING: Insert duration > 100ms, may indicate performance issue';
    END IF;
END $$;

-- ================================================================================================
-- TEST 9: Time-based Query Performance
-- Verify time-based queries use chunk exclusion
-- ================================================================================================
DO $$
DECLARE
    v_plan_row RECORD;
    v_uses_chunk_exclusion BOOLEAN := FALSE;
    v_test_table TEXT := 'trading_events';
BEGIN
    -- Check if table exists and is hypertable
    IF NOT EXISTS (
        SELECT 1 FROM timescaledb_information.hypertables
        WHERE hypertable_name = v_test_table
    ) THEN
        RAISE NOTICE 'TEST 9 INFO: Skipping - % is not a hypertable', v_test_table;
        RETURN;
    END IF;

    -- Check query plan for chunk exclusion
    FOR v_plan_row IN
        EXPLAIN (FORMAT TEXT)
        SELECT * FROM trading_events
        WHERE event_timestamp >= EXTRACT(EPOCH FROM NOW() - INTERVAL '1 hour')::BIGINT * 1000000000
        LIMIT 100
    LOOP
        IF v_plan_row."QUERY PLAN" LIKE '%Chunk%' OR 
           v_plan_row."QUERY PLAN" LIKE '%constraint%' OR
           v_plan_row."QUERY PLAN" LIKE '%exclusion%' THEN
            v_uses_chunk_exclusion := TRUE;
            RAISE NOTICE 'TEST 9 INFO: Query plan - %', v_plan_row."QUERY PLAN";
        END IF;
    END LOOP;

    IF v_uses_chunk_exclusion THEN
        RAISE NOTICE 'TEST 9 PASS: Time-based queries use chunk exclusion optimization';
    ELSE
        RAISE NOTICE 'TEST 9 INFO: Chunk exclusion not detected (may indicate empty hypertable)';
    END IF;
END $$;

-- ================================================================================================
-- TEST 10: Background Jobs Health
-- Verify TimescaleDB background jobs are running
-- ================================================================================================
DO $$
DECLARE
    v_job_record RECORD;
    v_active_jobs INTEGER := 0;
    v_failed_jobs INTEGER := 0;
BEGIN
    FOR v_job_record IN
        SELECT 
            j.job_id,
            j.proc_name,
            js.last_run_status,
            js.last_run_started_at,
            js.total_runs,
            js.total_failures
        FROM timescaledb_information.jobs j
        JOIN timescaledb_information.job_stats js ON j.job_id = js.job_id
        WHERE j.hypertable_schema = 'public'
        ORDER BY j.job_id
    LOOP
        IF v_job_record.last_run_status = 'Success' OR v_job_record.total_runs = 0 THEN
            v_active_jobs := v_active_jobs + 1;
            RAISE NOTICE 'TEST 10 INFO: Job % (%) - runs: %, failures: %',
                v_job_record.job_id,
                v_job_record.proc_name,
                v_job_record.total_runs,
                v_job_record.total_failures;
        ELSE
            v_failed_jobs := v_failed_jobs + 1;
            RAISE WARNING 'TEST 10 WARNING: Job % failed - last status: %',
                v_job_record.job_id,
                v_job_record.last_run_status;
        END IF;
    END LOOP;

    IF v_active_jobs > 0 THEN
        RAISE NOTICE 'TEST 10 PASS: Background jobs operational (% active, % failed)',
            v_active_jobs, v_failed_jobs;
    ELSE
        RAISE NOTICE 'TEST 10 INFO: No background jobs configured';
    END IF;
END $$;

-- ================================================================================================
-- Cleanup: Rollback all test data
-- ================================================================================================
ROLLBACK;

-- Test Summary
SELECT 'TimescaleDB Features Test Suite Completed - Review NOTICE/WARNING messages above' AS test_summary;
