-- ================================================================================================
-- Migration Test Suite: Trading Events (Migration 001)
-- PostgreSQL 16.10 + TimescaleDB 2.22.1
-- Tests constraint violations, valid insertions, partitioning, and index usage
-- ================================================================================================

-- Setup test transaction (rollback at end to avoid polluting database)
BEGIN;

-- ================================================================================================
-- TEST 1: Valid Trading Event Insertion
-- Should succeed with all required fields
-- ================================================================================================
DO $$
DECLARE
    v_test_id UUID := uuid_generate_v4();
    v_correlation_id UUID := uuid_generate_v4();
    v_current_ns BIGINT := EXTRACT(EPOCH FROM NOW())::BIGINT * 1000000000;
BEGIN
    INSERT INTO trading_events (
        id,
        correlation_id,
        event_timestamp,
        received_timestamp,
        processing_timestamp,
        event_type,
        event_source,
        symbol,
        event_data,
        event_hash,
        node_id,
        process_id
    ) VALUES (
        v_test_id,
        v_correlation_id,
        v_current_ns,
        v_current_ns + 1000,
        v_current_ns + 2000,
        'order_submitted',
        'trading_engine',
        'AAPL',
        '{"order_id": "TEST001", "price": 150.00, "quantity": 100}'::jsonb,
        encode(sha256('test_data'::bytea), 'hex'),
        'node-01',
        12345
    );

    RAISE NOTICE 'TEST 1 PASS: Valid trading event inserted successfully';
EXCEPTION
    WHEN OTHERS THEN
        RAISE EXCEPTION 'TEST 1 FAIL: Valid insertion failed - %', SQLERRM;
END $$;

-- ================================================================================================
-- TEST 2: Constraint Violation - Invalid ns_timestamp (negative value)
-- Should fail with CHECK constraint violation
-- ================================================================================================
DO $$
BEGIN
    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(),
        -1000, -- INVALID: negative timestamp
        1000000000,
        1000000000,
        'order_submitted',
        'trading_engine',
        'AAPL',
        '{}'::jsonb,
        encode(sha256('test'::bytea), 'hex'),
        'node-01',
        12345
    );

    RAISE EXCEPTION 'TEST 2 FAIL: Should have rejected negative timestamp';
EXCEPTION
    WHEN check_violation THEN
        RAISE NOTICE 'TEST 2 PASS: Correctly rejected negative ns_timestamp';
    WHEN OTHERS THEN
        RAISE EXCEPTION 'TEST 2 FAIL: Wrong error type - %', SQLERRM;
END $$;

-- ================================================================================================
-- TEST 3: Constraint Violation - Missing NOT NULL field
-- Should fail with NOT NULL constraint violation
-- ================================================================================================
DO $$
BEGIN
    INSERT INTO trading_events (
        correlation_id,
        event_timestamp,
        received_timestamp,
        processing_timestamp,
        event_type,
        event_source,
        -- symbol is missing (NOT NULL constraint)
        event_data,
        event_hash,
        node_id,
        process_id
    ) VALUES (
        uuid_generate_v4(),
        1000000000,
        1000000000,
        1000000000,
        'order_submitted',
        'trading_engine',
        '{}'::jsonb,
        encode(sha256('test'::bytea), 'hex'),
        'node-01',
        12345
    );

    RAISE EXCEPTION 'TEST 3 FAIL: Should have rejected missing symbol';
EXCEPTION
    WHEN not_null_violation THEN
        RAISE NOTICE 'TEST 3 PASS: Correctly rejected NULL symbol';
    WHEN OTHERS THEN
        RAISE EXCEPTION 'TEST 3 FAIL: Wrong error type - %', SQLERRM;
END $$;

-- ================================================================================================
-- TEST 4: Enum Constraint Violation - Invalid event_type
-- Should fail with invalid input for enum type
-- ================================================================================================
DO $$
BEGIN
    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(),
        1000000000,
        1000000000,
        1000000000,
        'invalid_event_type', -- INVALID: not in enum
        'trading_engine',
        'AAPL',
        '{}'::jsonb,
        encode(sha256('test'::bytea), 'hex'),
        'node-01',
        12345
    );

    RAISE EXCEPTION 'TEST 4 FAIL: Should have rejected invalid event_type';
EXCEPTION
    WHEN invalid_text_representation THEN
        RAISE NOTICE 'TEST 4 PASS: Correctly rejected invalid event_type enum value';
    WHEN OTHERS THEN
        RAISE EXCEPTION 'TEST 4 FAIL: Wrong error type - %', SQLERRM;
END $$;

-- ================================================================================================
-- TEST 5: Timestamp Ordering Constraint
-- Processing timestamp should be >= received timestamp >= event timestamp
-- ================================================================================================
DO $$
DECLARE
    v_current_ns BIGINT := EXTRACT(EPOCH FROM NOW())::BIGINT * 1000000000;
BEGIN
    -- Should fail: received < event
    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,
        v_current_ns - 1000, -- INVALID: received before event
        v_current_ns,
        'order_submitted',
        'trading_engine',
        'AAPL',
        '{}'::jsonb,
        encode(sha256('test'::bytea), 'hex'),
        'node-01',
        12345
    );

    RAISE EXCEPTION 'TEST 5 FAIL: Should have rejected invalid timestamp ordering';
EXCEPTION
    WHEN check_violation THEN
        RAISE NOTICE 'TEST 5 PASS: Correctly rejected invalid timestamp ordering';
    WHEN OTHERS THEN
        RAISE EXCEPTION 'TEST 5 FAIL: Wrong error type - %', SQLERRM;
END $$;

-- ================================================================================================
-- TEST 6: Partition Routing Test
-- Verify events are routed to correct partitions by date
-- ================================================================================================
DO $$
DECLARE
    v_test_id UUID := uuid_generate_v4();
    v_correlation_id UUID := uuid_generate_v4();
    v_current_ns BIGINT := EXTRACT(EPOCH FROM NOW())::BIGINT * 1000000000;
    v_partition_count INTEGER;
    v_expected_date DATE;
BEGIN
    -- Insert event
    INSERT INTO trading_events (
        id,
        correlation_id,
        event_timestamp,
        received_timestamp,
        processing_timestamp,
        event_type,
        event_source,
        symbol,
        event_data,
        event_hash,
        node_id,
        process_id
    ) VALUES (
        v_test_id,
        v_correlation_id,
        v_current_ns,
        v_current_ns,
        v_current_ns,
        'order_submitted',
        'trading_engine',
        'AAPL',
        '{"test": "partition_routing"}'::jsonb,
        encode(sha256('partition_test'::bytea), 'hex'),
        'node-01',
        12345
    );

    -- Verify event_date was auto-populated
    SELECT event_date INTO v_expected_date
    FROM trading_events
    WHERE id = v_test_id;

    IF v_expected_date = CURRENT_DATE THEN
        RAISE NOTICE 'TEST 6 PASS: Event routed to correct partition (event_date = %)', v_expected_date;
    ELSE
        RAISE EXCEPTION 'TEST 6 FAIL: Event_date mismatch (expected: %, got: %)', CURRENT_DATE, v_expected_date;
    END IF;

    -- Check partition exists
    SELECT COUNT(*) INTO v_partition_count
    FROM pg_tables
    WHERE tablename LIKE 'trading_events_%'
      AND tablename = 'trading_events_' || to_char(CURRENT_DATE, 'YYYY_MM_DD');

    IF v_partition_count > 0 THEN
        RAISE NOTICE 'TEST 6 INFO: Partition exists for today (trading_events_%)', to_char(CURRENT_DATE, 'YYYY_MM_DD');
    ELSE
        RAISE NOTICE 'TEST 6 WARNING: Expected partition not found';
    END IF;
END $$;

-- ================================================================================================
-- TEST 7: Index Usage Verification - Symbol Index
-- Verify index is used for symbol queries (EXPLAIN ANALYZE)
-- ================================================================================================
DO $$
DECLARE
    v_plan_row RECORD;
    v_uses_index BOOLEAN := FALSE;
BEGIN
    -- Check query plan for index usage
    FOR v_plan_row IN
        EXPLAIN (FORMAT TEXT)
        SELECT * FROM trading_events WHERE symbol = 'AAPL' LIMIT 100
    LOOP
        IF v_plan_row."QUERY PLAN" LIKE '%Index%' OR v_plan_row."QUERY PLAN" LIKE '%Bitmap%' THEN
            v_uses_index := TRUE;
            RAISE NOTICE 'TEST 7 PASS: Index detected - %', v_plan_row."QUERY PLAN";
        END IF;
    END LOOP;

    IF NOT v_uses_index THEN
        RAISE NOTICE 'TEST 7 WARNING: No index scan detected (may be seq scan for small tables)';
    END IF;
END $$;

-- ================================================================================================
-- TEST 8: JSONB Operations - Event Data Query
-- Verify JSONB indexing and query performance
-- ================================================================================================
DO $$
DECLARE
    v_test_id UUID := uuid_generate_v4();
    v_correlation_id UUID := uuid_generate_v4();
    v_current_ns BIGINT := EXTRACT(EPOCH FROM NOW())::BIGINT * 1000000000;
    v_result JSONB;
BEGIN
    -- Insert event with complex JSONB
    INSERT INTO trading_events (
        id,
        correlation_id,
        event_timestamp,
        received_timestamp,
        processing_timestamp,
        event_type,
        event_source,
        symbol,
        event_data,
        event_hash,
        node_id,
        process_id
    ) VALUES (
        v_test_id,
        v_correlation_id,
        v_current_ns,
        v_current_ns,
        v_current_ns,
        'order_submitted',
        'trading_engine',
        'AAPL',
        '{"order_id": "TEST008", "price": 150.50, "quantity": 1000, "metadata": {"source": "algo"}}'::jsonb,
        encode(sha256('jsonb_test'::bytea), 'hex'),
        'node-01',
        12345
    );

    -- Query using JSONB operators
    SELECT event_data INTO v_result
    FROM trading_events
    WHERE id = v_test_id
      AND event_data->>'order_id' = 'TEST008';

    IF v_result IS NOT NULL THEN
        RAISE NOTICE 'TEST 8 PASS: JSONB query successful, retrieved: %', v_result;
    ELSE
        RAISE EXCEPTION 'TEST 8 FAIL: JSONB query failed';
    END IF;
END $$;

-- ================================================================================================
-- TEST 9: Order Lifecycle Validation
-- Test complete order workflow: submit -> accept -> fill
-- ================================================================================================
DO $$
DECLARE
    v_order_id UUID := uuid_generate_v4();
    v_current_ns BIGINT := EXTRACT(EPOCH FROM NOW())::BIGINT * 1000000000;
BEGIN
    -- Create order
    INSERT INTO orders (
        id, symbol, side, order_type, time_in_force,
        quantity, limit_price, account_id, venue
    ) VALUES (
        v_order_id, 'AAPL', 'buy', 'limit', 'day',
        100, 15000, 'ACC001', 'NASDAQ'
    );

    -- Verify order was created
    IF EXISTS (SELECT 1 FROM orders WHERE id = v_order_id AND status = 'pending') THEN
        RAISE NOTICE 'TEST 9 PASS: Order created with pending status';
    ELSE
        RAISE EXCEPTION 'TEST 9 FAIL: Order creation failed';
    END IF;

    -- Verify trading event was auto-generated by trigger
    IF EXISTS (SELECT 1 FROM trading_events WHERE correlation_id = v_order_id AND event_type = 'order_submitted') THEN
        RAISE NOTICE 'TEST 9 PASS: Order submission event auto-generated';
    ELSE
        RAISE EXCEPTION 'TEST 9 FAIL: Order event not generated';
    END IF;
END $$;

-- ================================================================================================
-- TEST 10: Performance - Bulk Insert
-- Verify performance of bulk insertions
-- ================================================================================================
DO $$
DECLARE
    v_start_time TIMESTAMP;
    v_end_time TIMESTAMP;
    v_duration INTERVAL;
    v_correlation_id UUID := uuid_generate_v4();
    v_current_ns BIGINT := EXTRACT(EPOCH FROM NOW())::BIGINT * 1000000000;
    i INTEGER;
BEGIN
    v_start_time := clock_timestamp();

    -- Insert 100 events
    FOR i IN 1..100 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 (
            v_correlation_id,
            v_current_ns + i,
            v_current_ns + i,
            v_current_ns + i,
            'order_submitted',
            'trading_engine',
            'BULK' || (i % 10),
            format('{"order_id": "BULK%s"}', i)::jsonb,
            encode(sha256(('bulk' || i)::bytea), 'hex'),
            'node-01',
            12345
        );
    END LOOP;

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

    RAISE NOTICE 'TEST 10 PASS: Bulk insert of 100 events completed in %', v_duration;

    IF v_duration > INTERVAL '1 second' THEN
        RAISE WARNING 'TEST 10 WARNING: Bulk insert took > 1 second, may indicate performance issue';
    END IF;
END $$;

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

-- Test Summary
SELECT 'Trading Events Test Suite Completed - Review NOTICE messages above for results' AS test_summary;
