-- ================================================================================================
-- Configuration Schema Test Suite (Migration 007)
-- PostgreSQL 16.10 + TimescaleDB 2.22.1
-- Tests hot-reload config, versioning, and parameter validation
-- ================================================================================================

BEGIN;

-- ================================================================================================
-- TEST 1: Configuration Tables Existence
-- Verify all config tables are created
-- ================================================================================================
DO $$
DECLARE
    v_required_tables TEXT[] := ARRAY[
        'config_parameters',
        'config_history',
        'config_categories',
        'config_validation_rules'
    ];
    v_table TEXT;
    v_missing_tables TEXT[] := ARRAY[]::TEXT[];
    v_found_count INTEGER := 0;
BEGIN
    FOREACH v_table IN ARRAY v_required_tables
    LOOP
        IF EXISTS (
            SELECT 1 FROM information_schema.tables
            WHERE table_schema = 'public'
              AND table_name = v_table
        ) THEN
            v_found_count := v_found_count + 1;
        ELSE
            v_missing_tables := array_append(v_missing_tables, v_table);
        END IF;
    END LOOP;

    IF array_length(v_missing_tables, 1) IS NULL THEN
        RAISE NOTICE 'TEST 1 PASS: All % config tables exist', array_length(v_required_tables, 1);
    ELSE
        RAISE WARNING 'TEST 1 WARNING: Missing tables (% of %): %', 
            array_length(v_missing_tables, 1),
            array_length(v_required_tables, 1),
            array_to_string(v_missing_tables, ', ');
    END IF;
END $$;

-- ================================================================================================
-- TEST 2: Configuration Parameter Storage
-- Test storing and retrieving configuration parameters
-- ================================================================================================
DO $$
DECLARE
    v_param_id UUID := uuid_generate_v4();
    v_param_value JSONB;
BEGIN
    -- Insert configuration parameter
    INSERT INTO config_parameters (
        id, key, value, category, description, is_encrypted
    ) VALUES (
        v_param_id,
        'test.risk.var_limit',
        '{"limit": 100000, "confidence": 0.99}'::jsonb,
        'risk_management',
        'VaR limit configuration',
        false
    );

    -- Retrieve and validate
    SELECT value INTO v_param_value
    FROM config_parameters
    WHERE id = v_param_id;

    IF v_param_value->>'limit' = '100000' THEN
        RAISE NOTICE 'TEST 2 PASS: Configuration parameter stored and retrieved correctly';
    ELSE
        RAISE EXCEPTION 'TEST 2 FAIL: Configuration value mismatch';
    END IF;
END $$;

-- ================================================================================================
-- TEST 3: Configuration Versioning
-- Test configuration change history tracking
-- ================================================================================================
DO $$
DECLARE
    v_param_id UUID;
    v_old_value JSONB := '{"limit": 100000}'::jsonb;
    v_new_value JSONB := '{"limit": 150000}'::jsonb;
    v_version_count INTEGER;
BEGIN
    -- Get test parameter
    SELECT id INTO v_param_id
    FROM config_parameters
    WHERE key = 'test.risk.var_limit';

    -- Store original value in history
    INSERT INTO config_history (
        parameter_id, old_value, new_value, changed_by, change_reason
    ) VALUES (
        v_param_id, v_old_value, v_new_value, 'admin_user', 'Risk limit adjustment'
    );

    -- Update current value
    UPDATE config_parameters
    SET value = v_new_value, version = version + 1
    WHERE id = v_param_id;

    -- Verify history
    SELECT COUNT(*) INTO v_version_count
    FROM config_history
    WHERE parameter_id = v_param_id;

    IF v_version_count > 0 THEN
        RAISE NOTICE 'TEST 3 PASS: Configuration versioning operational (% versions)', v_version_count;
    ELSE
        RAISE EXCEPTION 'TEST 3 FAIL: Configuration history not recorded';
    END IF;
END $$;

-- ================================================================================================
-- TEST 4: Hot-Reload Notification
-- Test configuration change notification system
-- ================================================================================================
DO $$
DECLARE
    v_param_id UUID;
    v_notification_count INTEGER;
BEGIN
    SELECT id INTO v_param_id
    FROM config_parameters
    WHERE key = 'test.risk.var_limit';

    -- Simulate hot-reload notification
    NOTIFY config_update, '{"parameter_id": "' || v_param_id || '", "action": "update"}';

    RAISE NOTICE 'TEST 4 PASS: Hot-reload notification sent successfully';
    RAISE NOTICE 'TEST 4 INFO: Applications listening on config_update channel will reload';
END $$;

-- ================================================================================================
-- TEST 5: Configuration Categories
-- Test configuration categorization
-- ================================================================================================
DO $$
DECLARE
    v_categories TEXT[] := ARRAY[
        'risk_management',
        'trading',
        'market_data',
        'authentication',
        'performance'
    ];
    v_category TEXT;
    v_param_count INTEGER;
BEGIN
    -- Create category entries if table exists
    IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'config_categories') THEN
        FOREACH v_category IN ARRAY v_categories
        LOOP
            INSERT INTO config_categories (name, description)
            VALUES (
                v_category,
                'Configuration category: ' || v_category
            )
            ON CONFLICT (name) DO NOTHING;
        END LOOP;

        -- Count parameters by category
        SELECT COUNT(*) INTO v_param_count
        FROM config_parameters
        WHERE category = 'risk_management';

        RAISE NOTICE 'TEST 5 PASS: Configuration categories operational (% risk_management params)', v_param_count;
    ELSE
        RAISE NOTICE 'TEST 5 INFO: config_categories table not found, skipping';
    END IF;
END $$;

-- ================================================================================================
-- TEST 6: Configuration Validation Rules
-- Test parameter validation constraints
-- ================================================================================================
DO $$
DECLARE
    v_param_id UUID;
    v_test_value JSONB := '{"limit": 50000}'::jsonb;
    v_min_limit INTEGER := 10000;
    v_max_limit INTEGER := 200000;
BEGIN
    SELECT id INTO v_param_id
    FROM config_parameters
    WHERE key = 'test.risk.var_limit';

    -- Create validation rule if table exists
    IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'config_validation_rules') THEN
        INSERT INTO config_validation_rules (
            parameter_id, rule_type, rule_config
        ) VALUES (
            v_param_id,
            'range',
            format('{"min": %s, "max": %s}', v_min_limit, v_max_limit)::jsonb
        );

        -- Validate test value
        IF (v_test_value->>'limit')::INTEGER BETWEEN v_min_limit AND v_max_limit THEN
            RAISE NOTICE 'TEST 6 PASS: Configuration validation rules enforced';
        ELSE
            RAISE EXCEPTION 'TEST 6 FAIL: Value validation failed';
        END IF;
    ELSE
        RAISE NOTICE 'TEST 6 INFO: config_validation_rules table not found, skipping';
    END IF;
END $$;

-- ================================================================================================
-- TEST 7: Encrypted Configuration Values
-- Test encrypted parameter storage
-- ================================================================================================
DO $$
DECLARE
    v_secret_id UUID := uuid_generate_v4();
    v_encrypted_value TEXT;
    v_plain_value TEXT := 'api_key_12345';
BEGIN
    -- Encrypt value using pgcrypto
    v_encrypted_value := encode(encrypt(v_plain_value::bytea, 'encryption_key'::bytea, 'aes'), 'hex');

    -- Store encrypted parameter
    INSERT INTO config_parameters (
        id, key, value, category, is_encrypted
    ) VALUES (
        v_secret_id,
        'test.api.secret_key',
        to_jsonb(v_encrypted_value),
        'authentication',
        true
    );

    -- Verify encryption flag
    IF EXISTS (
        SELECT 1 FROM config_parameters
        WHERE id = v_secret_id AND is_encrypted = true
    ) THEN
        RAISE NOTICE 'TEST 7 PASS: Encrypted configuration storage validated';
    ELSE
        RAISE EXCEPTION 'TEST 7 FAIL: Encryption flag not set';
    END IF;
END $$;

-- ================================================================================================
-- TEST 8: Configuration Rollback
-- Test rolling back to previous configuration version
-- ================================================================================================
DO $$
DECLARE
    v_param_id UUID;
    v_history_id UUID;
    v_old_value JSONB;
    v_rollback_value JSONB;
BEGIN
    SELECT id INTO v_param_id
    FROM config_parameters
    WHERE key = 'test.risk.var_limit';

    -- Get previous version from history
    SELECT id, old_value INTO v_history_id, v_old_value
    FROM config_history
    WHERE parameter_id = v_param_id
    ORDER BY changed_at DESC
    LIMIT 1;

    -- Rollback to previous version
    UPDATE config_parameters
    SET value = v_old_value,
        version = version + 1
    WHERE id = v_param_id
    RETURNING value INTO v_rollback_value;

    -- Record rollback in history
    INSERT INTO config_history (
        parameter_id, old_value, new_value, changed_by, change_reason
    ) VALUES (
        v_param_id,
        v_rollback_value,
        v_old_value,
        'admin_user',
        'Rollback to previous version'
    );

    RAISE NOTICE 'TEST 8 PASS: Configuration rollback successful';
    RAISE NOTICE 'TEST 8 INFO: Rolled back to: %', v_old_value;
END $$;

-- ================================================================================================
-- TEST 9: Configuration Query Performance
-- Test indexed query performance
-- ================================================================================================
DO $$
DECLARE
    v_start_time TIMESTAMP;
    v_end_time TIMESTAMP;
    v_duration INTERVAL;
BEGIN
    v_start_time := clock_timestamp();

    -- Query by key (should use index)
    PERFORM * FROM config_parameters WHERE key = 'test.risk.var_limit';

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

    IF v_duration < INTERVAL '10 milliseconds' THEN
        RAISE NOTICE 'TEST 9 PASS: Configuration query performance acceptable (%)', v_duration;
    ELSE
        RAISE WARNING 'TEST 9 WARNING: Query took % (> 10ms)', v_duration;
    END IF;
END $$;

-- ================================================================================================
-- TEST 10: Multi-Environment Configuration
-- Test environment-specific configuration support
-- ================================================================================================
DO $$
DECLARE
    v_environments TEXT[] := ARRAY['development', 'staging', 'production'];
    v_env TEXT;
    v_env_param_id UUID;
BEGIN
    FOREACH v_env IN ARRAY v_environments
    LOOP
        v_env_param_id := uuid_generate_v4();
        
        INSERT INTO config_parameters (
            id,
            key,
            value,
            category,
            environment
        ) VALUES (
            v_env_param_id,
            'test.database.pool_size',
            to_jsonb(CASE v_env
                WHEN 'development' THEN 5
                WHEN 'staging' THEN 10
                WHEN 'production' THEN 50
            END),
            'database',
            v_env
        );
    END LOOP;

    -- Verify environment-specific configs
    IF EXISTS (
        SELECT 1 FROM config_parameters
        WHERE key = 'test.database.pool_size'
        GROUP BY key
        HAVING COUNT(DISTINCT environment) = 3
    ) THEN
        RAISE NOTICE 'TEST 10 PASS: Multi-environment configuration validated';
    ELSE
        RAISE NOTICE 'TEST 10 INFO: Environment column may not exist in config_parameters';
    END IF;
END $$;

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

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