<?php

declare(strict_types=1);

echo "Testing PostgreSQL JSONB with GIN Index Support\n";
echo "===============================================\n\n";

try {
    // Create PDO connection
    $pdo = new PDO(
        'pgsql:host=db;dbname=michaelschiemer',
        'postgres',
        'StartSimple2024!'
    );
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    echo "✅ Database connection established\n\n";

    // Drop test table if exists
    echo "Dropping test table if exists...\n";
    $pdo->exec("DROP TABLE IF EXISTS test_jsonb_table");
    echo "✅ Cleanup complete\n\n";

    // Create test table with JSONB column
    echo "Creating test table with JSONB column...\n";
    $pdo->exec("
        CREATE TABLE test_jsonb_table (
            id SERIAL PRIMARY KEY,
            name VARCHAR(100) NOT NULL,
            metadata JSONB NOT NULL,
            created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
        )
    ");
    echo "✅ Table created successfully\n\n";

    // Create GIN index on JSONB column
    echo "Creating GIN index on JSONB column...\n";
    $pdo->exec("CREATE INDEX idx_metadata_gin ON test_jsonb_table USING GIN (metadata)");
    echo "✅ GIN index created successfully\n\n";

    // Verify index was created with correct method
    echo "Verifying index method...\n";
    $stmt = $pdo->query("
        SELECT
            indexname,
            indexdef
        FROM pg_indexes
        WHERE tablename = 'test_jsonb_table'
        AND indexname = 'idx_metadata_gin'
    ");
    $indexInfo = $stmt->fetch(PDO::FETCH_ASSOC);

    if ($indexInfo && str_contains($indexInfo['indexdef'], 'USING gin')) {
        echo "✅ Index confirmed to use GIN method\n";
        echo "   Definition: {$indexInfo['indexdef']}\n\n";
    } else {
        echo "❌ Index not found or not using GIN method\n\n";
        exit(1);
    }

    // Insert test data with JSONB
    echo "Inserting test data...\n";
    $testData = [
        [
            'name' => 'Product A',
            'metadata' => json_encode([
                'category' => 'electronics',
                'price' => 299.99,
                'tags' => ['new', 'sale', 'featured'],
                'specs' => [
                    'cpu' => 'Intel i7',
                    'ram' => '16GB',
                    'storage' => '512GB SSD'
                ]
            ])
        ],
        [
            'name' => 'Product B',
            'metadata' => json_encode([
                'category' => 'electronics',
                'price' => 499.99,
                'tags' => ['premium', 'featured'],
                'specs' => [
                    'cpu' => 'AMD Ryzen 9',
                    'ram' => '32GB',
                    'storage' => '1TB SSD'
                ]
            ])
        ],
        [
            'name' => 'Product C',
            'metadata' => json_encode([
                'category' => 'books',
                'price' => 19.99,
                'tags' => ['bestseller'],
                'author' => 'John Doe',
                'isbn' => '978-3-16-148410-0'
            ])
        ]
    ];

    $insertStmt = $pdo->prepare("
        INSERT INTO test_jsonb_table (name, metadata)
        VALUES (:name, :metadata)
    ");

    foreach ($testData as $data) {
        $insertStmt->execute([
            'name' => $data['name'],
            'metadata' => $data['metadata']
        ]);
    }
    echo "✅ Test data inserted (3 products)\n\n";

    // Test JSONB queries with different operators
    echo "Testing JSONB queries:\n";
    echo "=====================\n\n";

    // Test 1: Contains operator (@>)
    echo "1. Query: Find all electronics\n";
    $stmt = $pdo->query("
        SELECT name, metadata->>'category' as category, metadata->>'price' as price
        FROM test_jsonb_table
        WHERE metadata @> '{\"category\": \"electronics\"}'
    ");
    $results = $stmt->fetchAll(PDO::FETCH_ASSOC);
    echo "   Found " . count($results) . " products:\n";
    foreach ($results as $row) {
        echo "   - {$row['name']}: {$row['category']} (\${$row['price']})\n";
    }
    echo "\n";

    // Test 2: JSON path query (using jsonb_exists to avoid PDO parameter conflict with ?)
    echo "2. Query: Find products with 'featured' tag\n";
    $stmt = $pdo->query("
        SELECT name, metadata->'tags' as tags
        FROM test_jsonb_table
        WHERE jsonb_exists(metadata->'tags', 'featured')
    ");
    $results = $stmt->fetchAll(PDO::FETCH_ASSOC);
    echo "   Found " . count($results) . " products:\n";
    foreach ($results as $row) {
        echo "   - {$row['name']}: " . $row['tags'] . "\n";
    }
    echo "\n";

    // Test 3: Nested JSON query
    echo "3. Query: Find products with specific CPU\n";
    $stmt = $pdo->query("
        SELECT name, metadata->'specs'->>'cpu' as cpu, metadata->'specs'->>'ram' as ram
        FROM test_jsonb_table
        WHERE metadata->'specs'->>'cpu' LIKE '%Intel%'
    ");
    $results = $stmt->fetchAll(PDO::FETCH_ASSOC);
    echo "   Found " . count($results) . " products:\n";
    foreach ($results as $row) {
        echo "   - {$row['name']}: {$row['cpu']}, {$row['ram']} RAM\n";
    }
    echo "\n";

    // Test 4: Query by price range
    echo "4. Query: Find products under $100\n";
    $stmt = $pdo->query("
        SELECT name, (metadata->>'price')::numeric as price
        FROM test_jsonb_table
        WHERE (metadata->>'price')::numeric < 100
    ");
    $results = $stmt->fetchAll(PDO::FETCH_ASSOC);
    echo "   Found " . count($results) . " products:\n";
    foreach ($results as $row) {
        echo "   - {$row['name']}: \${$row['price']}\n";
    }
    echo "\n";

    // Test 5: Existence check (using jsonb_exists to avoid PDO parameter conflict)
    echo "5. Query: Find products with author field\n";
    $stmt = $pdo->query("
        SELECT name, metadata->>'author' as author
        FROM test_jsonb_table
        WHERE jsonb_exists(metadata, 'author')
    ");
    $results = $stmt->fetchAll(PDO::FETCH_ASSOC);
    echo "   Found " . count($results) . " products:\n";
    foreach ($results as $row) {
        echo "   - {$row['name']}: by {$row['author']}\n";
    }
    echo "\n";

    // Verify GIN index is being used via EXPLAIN
    echo "Verifying GIN index usage with EXPLAIN:\n";
    $stmt = $pdo->query("
        EXPLAIN (FORMAT JSON)
        SELECT name FROM test_jsonb_table
        WHERE metadata @> '{\"category\": \"electronics\"}'
    ");
    $explainResult = $stmt->fetch(PDO::FETCH_ASSOC);
    $explainJson = json_decode($explainResult['QUERY PLAN'], true);

    $usesGinIndex = false;
    $planStr = json_encode($explainJson, JSON_PRETTY_PRINT);

    if (str_contains($planStr, 'idx_metadata_gin') || str_contains($planStr, 'Bitmap Index Scan')) {
        echo "✅ Query optimizer is using GIN index\n";
        $usesGinIndex = true;
    } else {
        echo "⚠️  GIN index may not be used (table might be too small for index to be beneficial)\n";
    }
    echo "\n";

    // Cleanup
    echo "Cleaning up...\n";
    $pdo->exec("DROP TABLE IF EXISTS test_jsonb_table");
    echo "✅ Test table dropped\n";

    echo "\n✅ All JSONB with GIN Index tests passed!\n";
    echo "\nSummary:\n";
    echo "========\n";
    echo "✅ JSONB column type supported\n";
    echo "✅ GIN index created successfully\n";
    echo "✅ Contains operator (@>) works\n";
    echo "✅ Existence check (jsonb_exists) works\n";
    echo "✅ JSON path queries work\n";
    echo "✅ Nested JSON queries work\n";
    echo "✅ Type casting works\n";
    if ($usesGinIndex) {
        echo "✅ Query optimizer uses GIN index\n";
    }
    echo "\nNote: Using jsonb_exists() instead of ? operator due to PDO parameter placeholder conflict\n";

} catch (\Exception $e) {
    echo "❌ Error: " . $e->getMessage() . "\n";
    echo "Stack trace:\n" . $e->getTraceAsString() . "\n";
    exit(1);
}
