"""
Comprehensive test cases for OceanBase Native Hybrid Search

This test suite covers all test cases from the test document:
- TC-001: Enable native hybrid search
- TC-005: Hybrid search fusion effect
- TC-006: Table column field filtering
- TC-007: JSON field filtering (auto fallback)
- TC-008: Empty result handling
- TC-009: Large data search
- TC-010: Limit parameter test
- TC-012: Threshold parameter triggers fallback
- TC-013: API compatibility
- TC-014: Old table compatibility (InnoDB to HEAP migration)
- Performance comparison test
"""

from ast import Tuple
import logging
import os
import sys
import time
import pytest
from typing import Dict, Any, List, Optional

# Add project root to Python path
project_root = os.path.join(os.path.dirname(__file__), "..", "..")
project_root = os.path.abspath(project_root)
sys.path.insert(0, project_root)

from powermem import auto_config, Memory

# Configure logging
logging.basicConfig(
    level=logging.DEBUG,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    force=True
)
logger = logging.getLogger(__name__)

# Helper functions for logging
def log_info(msg):
    """Log and print info message"""
    logger.info(msg)
    print(msg)

def log_warning(msg):
    """Log and print warning message"""
    logger.warning(msg)
    print(f"WARNING: {msg}")

def log_error(msg):
    """Log and print error message"""
    logger.error(msg)
    print(f"ERROR: {msg}")


class NativeHybridSearchTester:
    """Native Hybrid Search test class"""
    
    def __init__(self, enable_native_hybrid: bool = True):
        """Initialize tester"""
        self.enable_native_hybrid = enable_native_hybrid
        self.config = auto_config()
        
        # Enable native hybrid search if requested
        if 'vector_store' not in self.config:
            self.config['vector_store'] = {}
        if 'config' not in self.config['vector_store']:
            self.config['vector_store']['config'] = {}
        self.config['vector_store']['config']['enable_native_hybrid'] = enable_native_hybrid
        
        self.memory = Memory(config=self.config)
        log_info(f"Native Hybrid Search tester initialized (enable_native_hybrid={enable_native_hybrid})")
    
    def cleanup_all(self):
        """Cleanup all test data"""
        try:
            # Note: This is a simplified cleanup, actual implementation may vary
            log_info("Cleaning up test data...")
        except Exception as e:
            log_warning(f"Failed to cleanup: {e}")


@pytest.fixture(scope="class")
def native_hybrid_tester(request):
    """Fixture to create NativeHybridSearchTester instance"""
    enable_native = getattr(request.cls, 'enable_native_hybrid', True)
    tester = NativeHybridSearchTester(enable_native_hybrid=enable_native)
    yield tester
    # tester.cleanup_all()


@pytest.mark.usefixtures("native_hybrid_tester")
class TestNativeHybridSearch:
    """Test class for Native Hybrid Search functionality"""
    
    enable_native_hybrid = True
    
    @pytest.fixture(autouse=True)
    def setup_tester(self, native_hybrid_tester):
        """Setup tester instance for each test"""
        self.tester = native_hybrid_tester
    
    def test_tc001_enable_native_hybrid_search(self):
        """
        TC-001: Enable native hybrid search
        
        Test purpose: Verify native hybrid search can be enabled normally
        """
        log_info("=" * 80)
        log_info("TC-001: Enable Native Hybrid Search")
        log_info("=" * 80)
        
        user_id = "tc001_user"
        
        # Step 1: Initialize Memory instance
        log_info("\n[Step 1] Initializing Memory instance...")
        memory = self.tester.memory
        assert memory is not None, "Memory instance should be created"
        log_info("✓ Memory instance created")
        
        # Step 2: Add test data
        log_info("\n[Step 2] Adding test data...")
        result = memory.add(messages="Zhang San lives in Hangzhou", user_id=user_id)
        assert result is not None, "Add operation should succeed"
        log_info("✓ Test data added")
        
        # Step 3: Execute search query
        log_info("\n[Step 3] Executing search query...")
        search_results = memory.search(query="Where does Zhang San live", user_id=user_id, limit=10)
        assert search_results is not None, "Search should return results"
        log_info(f"✓ Search completed, found {len(search_results.get('results', []))} results")
        
        # Step 4: Check log output (we can't directly check logs, but we verify functionality)
        log_info("\n[Step 4] Verifying search results...")
        memories = search_results.get('results', [])
        assert len(memories) > 0, "Should return at least one result"
        
        # Verify result content
        found_relevant = False
        for mem in memories:
            content = mem.get('memory', '')
            if 'Zhang San' in content or 'Hangzhou' in content:
                found_relevant = True
                log_info(f"✓ Found relevant result: {content}...")
                break
        log_info(f"✓ Top Result: {memories[0].get('memory', '') if memories else 'No results'}")
        assert found_relevant, "Should find relevant results"
        log_info("\n✓ TC-001 passed: Native hybrid search enabled successfully")
    
    def test_tc005_hybrid_search_fusion_effect(self):
        """
        TC-005: Hybrid search fusion effect
        
        Test purpose: Verify the fusion effect of vector search, full-text search, and sparse vector search
        """
        log_info("=" * 80)
        log_info("TC-005: Hybrid Search Fusion Effect")
        log_info("=" * 80)
        
        user_id = "tc005_user"
        memory = self.tester.memory
        
        # Step 1: Add diverse test data
        log_info("\n[Step 1] Adding diverse test data...")
        test_messages = [
            "Zhang San lives in Hangzhou and is a software engineer",
            "Li Si is a product manager in Beijing",
            "Wang Wu works in Shenzhen and likes running"
        ]
        
        for msg in test_messages:
            result = memory.add(messages=msg, user_id=user_id)
            assert result is not None, f"Failed to add message: {msg}"
            log_info(f"✓ Added: {msg}")
        
        # Step 2: Execute complex query
        log_info("\n[Step 2] Executing complex query...")
        query = "Zhang San's workplace and occupation"
        results = memory.search(query=query, user_id=user_id, limit=10)
        
        assert results is not None, "Search should return results"
        memories = results.get('results', [])
        log_info(f"✓ Found {len(memories)} results")
        
        # Step 3: Verify fusion results accuracy
        log_info("\n[Step 3] Verifying fusion results...")
        assert len(memories) > 0, "Should return at least one result"
        
        # Check if most relevant result is at the top
        if memories:
            top_result = memories[0]
            content = top_result.get('memory', '')
            score = top_result.get('score', 0)
            log_info(f"✓ Top result: {content}... (score: {score:.4f})")
            
            # Verify relevance
            assert 'Zhang San' in content, "Top result should contain 'Zhang San'"
            assert score > 0, "Score should be positive"
        log_info(f"✓ Top Result: {top_result.get('memory', '') if top_result else 'No results'}")
        log_info("\n✓ TC-005 passed: Hybrid search fusion effect verified")
    
    def test_tc006_table_column_field_filtering(self):
        """
        TC-006: Table column field filtering
        
        Test purpose: Verify native hybrid search supports table column field filtering
        """
        log_info("=" * 80)
        log_info("TC-006: Table Column Field Filtering")
        log_info("=" * 80)
        
        memory = self.tester.memory
        
        # Use specific user_ids for filter testing
        user_id_1 = "tc006_filter_user1"
        user_id_2 = "tc006_filter_user2"
        
        # Step 1: Add memories with different user_id
        log_info("\n[Step 1] Adding memories with different user_id...")
        memory.add(messages="Zhang San lives in Hangzhou", user_id=user_id_1)
        memory.add(messages="Li Si is in Beijing", user_id=user_id_2)
        log_info(f"✓ Added memories for {user_id_1} and {user_id_2}")
        
        # Step 2: Search with table column field filter
        log_info("\n[Step 2] Searching with table column field filter...")
        results = memory.search(
            query="Where does Li Si live",
            filters={"user_id": user_id_2},
            limit=10
        )
        
        assert results is not None, "Search should return results"
        memories = results.get('results', [])
        log_info(f"✓ Found {len(memories)} results")
        
        # Step 3: Verify filtering effect
        log_info("\n[Step 3] Verifying filtering effect...")
        if memories:
            for mem in memories:
                # Check if all results belong to the filtered user
                # Note: This depends on how metadata is stored
                content = mem.get('memory', '')
                log_info(f"  Result: {content}...")
        
        # Verify that results are filtered (all should be user_id_2's data)
        assert len(memories) >= 0, "Should return filtered results"
        log_info("✓ Filtering applied successfully")
        log_info(f"✓ Top Result: {memories[0].get('memory', '') if memories else 'No results'}")
        log_info("\n✓ TC-006 passed: Table column field filtering verified")
    
    def test_tc007_json_field_filtering_auto_fallback(self):
        """
        TC-007: JSON field filtering (auto fallback)
        
        Test purpose: Verify automatic fallback to application-level hybrid search when using JSON field filtering
        """
        log_info("=" * 80)
        log_info("TC-007: JSON Field Filtering (Auto Fallback)")
        log_info("=" * 80)
        
        user_id = "tc007_user"
        memory = self.tester.memory
        
        # Step 1: Add memory with JSON metadata
        log_info("\n[Step 1] Adding memory with JSON metadata...")
        memory.add(
            messages="Zhang San lives in Hangzhou",
            user_id=user_id,
            metadata={"custom_field": "Hangzhou", "city": "Hangzhou", "province": "Zhejiang"}
        )
        log_info("✓ Memory added with metadata: {'custom_field': 'Hangzhou', 'city': 'Hangzhou', 'province': 'Zhejiang'}")
        
        # Step 2: Search with JSON field filter (not supported)
        log_info("\n[Step 2] Searching with JSON field filter (should trigger fallback)...")
        results = memory.search(
            query="Where does Zhang San live",
            user_id=user_id,
            filters={"custom_field": "Hangzhou"},
            limit=10
        )
        
        # Step 3: Check if auto fallback occurred
        log_info("\n[Step 3] Verifying auto fallback...")
        assert results is not None, "Search should still return results (via fallback)"
        memories = results.get('results', [])
        log_info(f"✓ Found {len(memories)} results (via fallback)")
        
        # Verify search results are still correct
        assert len(memories) >= 0, "Should return results even with fallback"
        log_info("✓ Auto fallback mechanism verified")
        log_info(f"✓ Top Result: {memories[0].get('memory', '') if memories else 'No results'}")
        log_info("\n✓ TC-007 passed: JSON field filtering auto fallback verified")
    
    def test_tc008_empty_result_handling(self):
        """
        TC-008: Empty result handling
        
        Test purpose: Verify handling when query returns no results
        """
        log_info("=" * 80)
        log_info("TC-008: Empty Result Handling")
        log_info("=" * 80)
        
        user_id = "tc008_user"
        memory = self.tester.memory
        
        # Step 1: Add small amount of test data
        log_info("\n[Step 1] Adding test data...")
        memory.add(messages="Zhang San lives in Hangzhou", user_id=user_id)
        log_info("✓ Test data added")
        
        # Step 2: Query irrelevant content
        log_info("\n[Step 2] Querying irrelevant content...")
        query = "Completely irrelevant content xyz123"
        results = memory.search(query=query, user_id=user_id, limit=10)
        
        assert results is not None, "Search should return results object"
        memories = results.get('results', [])
        log_info(f"✓ Search completed, found {len(memories)} results")
        
        # Step 3: Verify empty result handling
        log_info("\n[Step 3] Verifying empty result handling...")
        # Empty results or low relevance results are acceptable
        assert isinstance(memories, list), "Results should be a list"
        log_info("✓ Empty result handling verified (no exception thrown)")
        log_info(f"✓ Top Result: {memories[0].get('memory', '') if memories else 'No results'}")
        log_info("\n✓ TC-008 passed: Empty result handling verified")
    
    def test_tc009_large_data_search(self):
        """
        TC-009: Large data search and performance comparison
        
        Test purpose: Verify search performance with large amount of data and compare
                     native hybrid search vs application-level hybrid search
        """
        log_info("=" * 80)
        log_info("TC-009: Large Data Search and Performance Comparison")
        log_info("=" * 80)
        
        user_id = "tc009_user"
        memory = self.tester.memory
        
        # Step 1: Add large amount of test data (100+ records)
        log_info("\n[Step 1] Adding large amount of test data (100 records)...")
        start_time = time.time()
        
        for i in range(10):
            memory.add(messages=f"user{i + 43} is {i + 43} years old", user_id=user_id)
            if (i + 1) % 20 == 0:
                log_info(f"  Added {i + 1} records...")
        
        add_time = time.time() - start_time
        log_info(f"✓ Added 100 records in {add_time:.2f} seconds")
        
        # Step 2: Execute search query
        log_info("\n[Step 2] Executing search query...")
        start_time = time.time()
        results = memory.search(query="user50", user_id=user_id, limit=10)
        search_time = time.time() - start_time
        
        assert results is not None, "Search should return results"
        memories = results.get('results', [])
        log_info(f"✓ Search completed in {search_time:.3f} seconds, found {len(memories)} results")
        
        # Step 3: Verify performance and result accuracy
        log_info("\n[Step 3] Verifying performance and accuracy...")
        assert search_time < 2.0, f"Search should complete within 2 second, took {search_time:.3f}s"
        assert len(memories) > 0, "Should return relevant results"
        
        # Verify recall accuracy. Similar adjacent records such as user49/user51
        # can occasionally outrank user50, but the exact record must be returned.
        contents = [item.get('memory', '') for item in memories]
        log_info(f"✓ Top results: {contents[:3]}")
        assert any('user50' in content or '50' in content for content in contents), (
            f"Search results should include information relevant to 'user50', got: {contents}"
        )
        
        # Step 4: Test native hybrid search performance (enabled)
        log_info("\n[Step 4] Testing native hybrid search performance (enabled)...")
        start = time.time()
        for i in range(30):
            results_native = memory.search(query="user", user_id=user_id, limit=10)
        native_time = time.time() - start
        
        assert results_native is not None, "Native search should return results"
        native_count = len(results_native.get('results', []))
        log_info(f"✓ Native hybrid search: {native_time:.3f}s for 30 queries, {native_count} results")
        
        # Wait for background update operations to complete before next test phase
        log_info("\n[Step 4.5] Waiting for background operations to settle...")
        time.sleep(30)
        log_info("✓ Background operations settled")

        # Step 5: Test application-level hybrid search (disabled)
        log_info("\n[Step 5] Testing application-level hybrid search (disabled)...")
        config_app = auto_config()
        if 'vector_store' not in config_app:
            config_app['vector_store'] = {}
        if 'config' not in config_app['vector_store']:
            config_app['vector_store']['config'] = {}
        config_app['vector_store']['config']['enable_native_hybrid'] = False
        
        memory_app = Memory(config=config_app)
        
        start = time.time()
        for i in range(30):
            results_app = memory_app.search(query="user", limit=10)
        app_time = time.time() - start
        
        assert results_app is not None, "Application-level search should return results"
        app_count = len(results_app.get('results', []))
        log_info(f"✓ Application-level hybrid search: {app_time:.3f}s for 30 queries, {app_count} results")
        
        # Step 6: Compare performance
        log_info("\n[Step 6] Performance comparison:")
        log_info(f"  Native hybrid search:     {native_time:.3f}s")
        log_info(f"  Application-level search: {app_time:.3f}s")
        
        if app_time > 0:
            improvement = ((app_time - native_time) / app_time) * 100
            log_info(f"  Performance improvement:  {improvement:.1f}%")
        
        # Both should return results
        assert native_count >= 0, "Native search should return results"
        assert app_count >= 0, "Application-level search should return results"
        
        log_info(f"\n✓ TC-009 passed: Large data search and performance comparison verified")
    
    def test_tc010_limit_parameter(self):
        """
        TC-010: Limit parameter test
        
        Test purpose: Verify the effect of different limit parameters
        """
        log_info("=" * 80)
        log_info("TC-010: Limit Parameter Test")
        log_info("=" * 80)
        
        user_id = "tc010_user"
        memory = self.tester.memory
        
        # Step 0: Add test data for this test case (30+ records to test limit properly)
        log_info("\n[Step 0] Adding test data for limit testing...")
        for i in range(30):
            memory.add(messages=f"tc010_user{i} is {i} years old", user_id=user_id)
        log_info("✓ Added 30 records for limit testing")
        
        # Step 1: Search with different limit values
        log_info("\n[Step 1] Searching with different limit values...")
        log_info("Note: Testing limit parameter with query 'tc010_user' (should match many records)")
        
        # Test limit=5
        log_info("\n[Test 1] Testing limit=5...")
        results_5 = memory.search(query="tc010_user", user_id=user_id, limit=5)
        memories_5 = results_5.get('results', [])
        log_info(f"✓ limit=5: returned {len(memories_5)} results")
        if len(memories_5) < 5:
            log_warning(f"  ⚠ Expected up to 5 results, but got {len(memories_5)}. This may indicate a limit issue.")
        
        # Test limit=10
        log_info("\n[Test 2] Testing limit=10...")
        results_10 = memory.search(query="tc010_user", user_id=user_id, limit=10)
        memories_10 = results_10.get('results', [])
        log_info(f"✓ limit=10: returned {len(memories_10)} results")
        if len(memories_10) < 10:
            log_warning(f"  ⚠ Expected up to 10 results, but got {len(memories_10)}. This may indicate a limit issue.")
        
        # Test limit=20
        log_info("\n[Test 3] Testing limit=20...")
        results_20 = memory.search(query="tc010_user", user_id=user_id, limit=20)
        memories_20 = results_20.get('results', [])
        log_info(f"✓ limit=20: returned {len(memories_20)} results")
        if len(memories_20) < 20:
            log_warning(f"  ⚠ Expected up to 20 results, but got {len(memories_20)}. This may indicate a limit issue.")
            log_info(f"  Database should have 30 user-related records, but only {len(memories_20)} were returned.")
        
        # Step 2: Verify result counts
        log_info("\n[Step 2] Verifying result counts...")
        # Note: We use <= instead of == because there might not be enough matching records
        assert len(memories_5) <= 5, f"limit=5 should return at most 5 results, got {len(memories_5)}"
        assert len(memories_10) <= 10, f"limit=10 should return at most 10 results, got {len(memories_10)}"
        assert len(memories_20) <= 20, f"limit=20 should return at most 20 results, got {len(memories_20)}"
        
        # Additional check: if limit=20 returns only 10, there might be a bug
        if len(memories_20) == 10 and len(memories_10) == 10:
            log_warning("  ⚠ limit=20 and limit=10 both returned 10 results. This suggests rank_window_size might be capped at 10.")
            log_warning("  This could be a bug in the native hybrid search implementation.")
        
        # Verify ordering (results should be sorted by relevance)
        if len(memories_5) > 1:
            scores = [m.get('score', 0) for m in memories_5]
            assert scores == sorted(scores, reverse=True), "Results should be sorted by score (descending)"
        
        log_info(f"✓ memories_20: {memories_20}")
        log_info("✓ Limit parameter verified")
        log_info("\n✓ TC-010 passed: Limit parameter test verified")
    
    def test_tc012_threshold_parameter_triggers_fallback(self):
        """
        TC-012: Threshold parameter triggers fallback
        
        Test purpose: Verify automatic fallback when threshold parameter is used
        """
        log_info("=" * 80)
        log_info("TC-012: Threshold Parameter Triggers Fallback")
        log_info("=" * 80)
        
        user_id = "tc012_user"
        memory = self.tester.memory
        
        # Step 0: Add test data for this test case
        log_info("\n[Step 0] Adding test data for threshold testing...")
        memory.add(messages="tc012 test user data for threshold testing", user_id=user_id)
        log_info("✓ Test data added")
        
        # Step 1: Enable native hybrid search (already enabled in fixture)
        log_info("\n[Step 1] Native hybrid search is enabled")
        
        # Step 2: Search with threshold parameter (should trigger fallback)
        log_info("\n[Step 2] Searching with threshold parameter (should trigger fallback)...")
        try:
            results = memory.search(
                query="tc012 test",
                user_id=user_id,
                limit=10,
                threshold=0.8  # This should trigger fallback
            )
            
            # Step 3: Check if auto fallback occurred
            log_info("\n[Step 3] Verifying auto fallback...")
            assert results is not None, "Search should still return results (via fallback)"
            memories = results.get('results', [])
            log_info(f"✓ Found {len(memories)} results (via fallback)")

            log_info(f"✓ Top Result: {memories[0].get('memory', '') if memories else 'No results'}")
            # Verify search results are still correct
            assert len(memories) >= 0, "Should return results even with fallback"
            log_info("✓ Auto fallback mechanism verified")
            
        except TypeError as e:
            # If threshold parameter is not supported in the API
            log_warning(f"Threshold parameter may not be supported in API: {e}")
            pytest.skip("Threshold parameter not supported in current API")
        
        log_info("\n✓ TC-012 passed: Threshold parameter triggers fallback verified")
    

    def test_tc014_old_table_compatibility(self):
        """
        TC-014: Old table compatibility test
        
        Test purpose: Verify compatibility when switching from old logic to new logic (native hybrid search)
        
        Test steps:
        1. Drop existing table to ensure clean state
        2. Disable native hybrid search, initialize Memory (auto create table)
        3. Add some data and search with old logic
        4. Enable native hybrid search and search with new logic
        5. Output results (count and content)
        6. Output test results
        
        Note: This test does NOT use the fixture to avoid creating a HEAP table before the test starts.
        """
        import pymysql
        
        log_info("=" * 80)
        log_info("TC-014: Old Table Compatibility Test")
        log_info("=" * 80)
        
        # Database connection info
        db_host = "127.0.0.1"
        db_port = 10001
        db_name = "powermem"
        table_name = "memories_old_table_test"
        
        # Step 0: Drop existing table to ensure clean state
        log_info("\n[Step 0] Dropping existing table to ensure clean state...")
        try:
            conn = pymysql.connect(
                host=db_host,
                port=db_port,
                database=db_name,
                user="root",
                password="",
                charset="utf8mb4"
            )
            cursor = conn.cursor()
            drop_sql = f"DROP TABLE IF EXISTS `{table_name}`"
            cursor.execute(drop_sql)
            conn.commit()
            cursor.close()
            conn.close()
            log_info(f"✓ Table '{table_name}' dropped successfully (or did not exist)")
        except Exception as e:
            log_warning(f"Failed to drop table: {e}")
        
        # Step 1: Disable native hybrid search, initialize Memory (auto create table)
        log_info("\n[Step 1] Disabling native hybrid search and initializing Memory (old mode)...")
        config_old = auto_config()
        if 'vector_store' not in config_old:
            config_old['vector_store'] = {}
        if 'config' not in config_old['vector_store']:
            config_old['vector_store']['config'] = {}
        config_old['vector_store']['config']['enable_native_hybrid'] = False
        config_old['vector_store']['config']['collection_name'] = table_name
        
        memory_old = Memory(config=config_old)
        log_info("✓ Memory initialized with native hybrid search DISABLED (old logic)")
        
        # Step 2: Add some data to the table
        log_info("\n[Step 2] Adding data to table...")
        user_id = "tc014_user"
        test_messages = [
            "user1 is 1 years old",
            "user2 is 2 years old",
            "user3 is 3 years old"
        ]
        
        for msg in test_messages:
            result = memory_old.add(messages=msg, user_id=user_id)
            assert result is not None, f"Failed to add message: {msg}"
            log_info(f"✓ Added: {msg}")
        
        # Step 3: Search with old logic (native hybrid search disabled)
        log_info("\n[Step 3] Searching with OLD logic (native hybrid search DISABLED)...")
        old_results = memory_old.search(query="user", user_id=user_id, limit=10)
        old_memories = old_results.get('results', [])
        
        log_info(f"\n--- OLD Logic Search Results ---")
        log_info(f"Result count: {len(old_memories)}")
        log_info(f"Results content:")
        for i, mem in enumerate(old_memories):
            memory_content = mem.get('memory', 'N/A')
            score = mem.get('score', 'N/A')
            log_info(f"  [{i+1}] score={score}, memory={memory_content}")

        # Step 4: Enable native hybrid search and search with new logic
        log_info("\n[Step 4] Enabling native hybrid search and searching with NEW logic...")
        config_new = auto_config()
        if 'vector_store' not in config_new:
            config_new['vector_store'] = {}
        if 'config' not in config_new['vector_store']:
            config_new['vector_store']['config'] = {}
        config_new['vector_store']['config']['enable_native_hybrid'] = True
        config_new['vector_store']['config']['collection_name'] = table_name
        
        memory_new = Memory(config=config_new)
        log_info("✓ Memory reinitialized with native hybrid search ENABLED (new logic)")
        
        new_results = memory_new.search(query="user", user_id=user_id, limit=10)
        new_memories = new_results.get('results', [])
        
        log_info(f"\n--- NEW Logic Search Results ---")
        log_info(f"Result count: {len(new_memories)}")
        log_info(f"Results content:")
        for i, mem in enumerate(new_memories):
            memory_content = mem.get('memory', 'N/A')
            score = mem.get('score', 'N/A')
            log_info(f"  [{i+1}] score={score}, memory={memory_content}")
        
        # Step 5: Output comparison summary
        log_info("\n" + "=" * 80)
        log_info("Test Results Summary")
        log_info("=" * 80)
        log_info(f"OLD logic (native hybrid DISABLED): {len(old_memories)} results")
        log_info(f"NEW logic (native hybrid ENABLED):  {len(new_memories)} results")
        
        # Verify both searches returned results
        assert len(old_memories) > 0, "Old logic should return results"
        assert len(new_memories) > 0, "New logic should return results"
        
        log_info("\n✓ TC-014 passed: Old table compatibility verified")
        log_info("  - Old logic search works correctly")
        log_info("  - New logic search works correctly after enabling native hybrid search")
    


def run_all_tests():
    """Run tests with case selection in code"""
    # Define available test cases
    test_cases = {
        "1": ("test_tc001_enable_native_hybrid_search", "TC-001: Enable native hybrid search"),
        "2": ("test_tc005_hybrid_search_fusion_effect", "TC-005: Hybrid search fusion effect"),
        "3": ("test_tc006_table_column_field_filtering", "TC-006: Table column field filtering"),
        "4": ("test_tc007_json_field_filtering_auto_fallback", "TC-007: JSON field filtering (auto fallback)"),
        "5": ("test_tc008_empty_result_handling", "TC-008: Empty result handling"),
        "6": ("test_tc009_large_data_search", "TC-009: Large data search and performance comparison"),
        "7": ("test_tc010_limit_parameter", "TC-010: Limit parameter test"),
        "8": ("test_tc012_threshold_parameter_triggers_fallback", "TC-012: Threshold parameter triggers fallback"),
        "9": ("test_tc014_old_table_compatibility", "TC-014: Old table compatibility test"),
    }
    
    log_info("=" * 80)
    log_info("Starting Native Hybrid Search Comprehensive Tests")
    log_info("=" * 80)
    
    # Build pytest arguments - run all test cases defined in test_cases
    pytest_args = ["-v", "-s"]
    
    log_info(f"Running {len(test_cases)} test cases from test_cases list:")
    for test_key, (test_method, desc) in sorted(test_cases.items(), key=lambda x: int(x[0])):
        # Each test case needs to be a complete path: file::Class::method
        test_path = f"{__file__}::TestNativeHybridSearch::{test_method}"
        pytest_args.append(test_path)
        log_info(f"  - {desc}")
    
    log_info("=" * 80)
    pytest.main(pytest_args)


if __name__ == "__main__":
    run_all_tests()
