"""Integration tests for fuzzy search functionality."""

import os
from collections.abc import Generator

import pytest

from lib.config import Settings
from lib.database import Neo4jClient
from lib.models import Command

# Check if Neo4j is available for integration tests
SKIP_INTEGRATION = os.getenv("SKIP_INTEGRATION_TESTS", "false").lower() == "true"
skip_if_no_neo4j = pytest.mark.skipif(
    SKIP_INTEGRATION,
    reason="Integration tests disabled (set SKIP_INTEGRATION_TESTS=false to enable)",
)


@pytest.fixture(scope="module")
def neo4j_settings() -> Settings:
    """Create settings for Neo4j test database."""
    return Settings(
        neo4j_uri=os.getenv("NEO4J_TEST_URI", "bolt://localhost:7687"),
        neo4j_user=os.getenv("NEO4J_TEST_USER", "neo4j"),
        neo4j_password=os.getenv("NEO4J_PASSWORD", "devpassword"),
        neo4j_database=os.getenv("NEO4J_TEST_DATABASE", "neo4j"),
    )


@pytest.fixture
def db_client(neo4j_settings: Settings) -> Generator[Neo4jClient, None, None]:
    """Create a database client and clean up after tests."""
    client = Neo4jClient(neo4j_settings)
    yield client

    # Cleanup: Delete all test data
    with client.driver.session(database=client.database) as session:
        session.run("MATCH (n:Command) DETACH DELETE n")
        session.run("MATCH (n:Tag) DELETE n")

    client.close()


@skip_if_no_neo4j
class TestFuzzySearchIntegration:
    """Integration tests for fuzzy search with real Neo4j database."""

    def test_fuzzy_search_scores_results(self, db_client: Neo4jClient) -> None:
        """Test that fuzzy search scores and filters results from initial matches."""
        # Add commands
        cmd1 = Command(
            command="docker ps -a",
            description="List all docker containers",
            tags=["docker", "containers"],
        )
        cmd2 = Command(
            command="docker run ubuntu",
            description="Run docker Ubuntu container",
            tags=["docker", "ubuntu"],
        )

        db_client.add_command(cmd1)
        db_client.add_command(cmd2)

        # Search with "docker" - fuzzy will score results
        results = db_client.search_commands(query="docker", fuzzy=True, fuzzy_threshold=80)

        # Should find docker commands with high scores
        assert len(results) >= 2
        # Verify actual commands are returned
        commands = [r.command for r in results]
        assert "docker ps -a" in commands
        assert "docker run ubuntu" in commands

    def test_fuzzy_search_with_similar_term(self, db_client: Neo4jClient) -> None:
        """Test fuzzy search refines results based on similarity."""
        cmd = Command(
            command="kubectl get pods",
            description="Get Kubernetes pods from cluster",
            tags=["kubernetes", "k8s"],
        )

        db_client.add_command(cmd)

        # Search with "kube" - should match as substring
        results = db_client.search_commands(query="kube", fuzzy=True, fuzzy_threshold=70)

        # Should find the kubernetes command
        assert len(results) >= 1
        # Verify kubectl command is returned
        assert results[0].command == "kubectl get pods"
        assert "kubernetes" in results[0].description.lower()

    def test_fuzzy_threshold_filters_results(self, db_client: Neo4jClient) -> None:
        """Test that fuzzy threshold filters results by similarity score."""
        cmd = Command(
            command="git commit -m 'message'",
            description="Commit changes to git repository",
            tags=["git"],
        )

        db_client.add_command(cmd)

        # Search for "git" with very high threshold
        results_high = db_client.search_commands(query="git", fuzzy=True, fuzzy_threshold=95)

        # Should find exact matches
        assert len(results_high) >= 1
        assert results_high[0].command == "git commit -m 'message'"

        # Search with lower threshold
        results_low = db_client.search_commands(query="git", fuzzy=True, fuzzy_threshold=50)

        # Should find same or more results
        assert len(results_low) >= len(results_high)

    def test_fuzzy_disabled_requires_exact_match(self, db_client: Neo4jClient) -> None:
        """Test that with fuzzy disabled, requires exact substring match."""
        cmd = Command(
            command="npm install package", description="Install npm package", tags=["npm", "node"]
        )

        db_client.add_command(cmd)

        # Search with typo and fuzzy disabled
        results = db_client.search_commands(query="npn", fuzzy=False)

        # Should not find anything (no exact match)
        assert len(results) == 0

        # Search with correct term and fuzzy disabled
        results = db_client.search_commands(query="npm", fuzzy=False)

        # Should find the command
        assert len(results) >= 1
        assert results[0].command == "npm install package"

    def test_fuzzy_search_scoring_order(self, db_client: Neo4jClient) -> None:
        """Test that fuzzy search returns results ordered by relevance score."""
        # Add commands with varying relevance
        cmd1 = Command(command="docker ps", description="List Docker containers", tags=["docker"])
        cmd2 = Command(
            command="docker-compose up",
            description="Start Docker Compose services",
            tags=["docker", "compose"],
        )
        cmd3 = Command(command="podman ps", description="List podman containers", tags=["podman"])

        db_client.add_command(cmd1)
        db_client.add_command(cmd2)
        db_client.add_command(cmd3)

        # Search for "docker"
        results = db_client.search_commands(query="docker", fuzzy=True, fuzzy_threshold=50)

        # Should have results with "docker" scoring higher
        assert len(results) > 0
        # First result should be a docker command
        assert "docker" in results[0].command.lower()

    def test_fuzzy_search_with_low_threshold(self, db_client: Neo4jClient) -> None:
        """Test fuzzy search with low threshold accepts more matches."""
        cmd = Command(command="python script.py", description="Run Python script", tags=["python"])

        db_client.add_command(cmd)

        # Search with very different term and low threshold
        results = db_client.search_commands(query="pyt", fuzzy=True, fuzzy_threshold=30)

        # Should find python command with low threshold
        assert len(results) >= 1
        assert results[0].command == "python script.py"

    def test_fuzzy_search_empty_query(self, db_client: Neo4jClient) -> None:
        """Test fuzzy search with empty query returns all results."""
        cmd = Command(command="ls -la", description="List files", tags=["filesystem"])

        db_client.add_command(cmd)

        # Search with no query
        results = db_client.search_commands(fuzzy=True)

        # Should return results
        assert len(results) >= 1
        assert results[0].command == "ls -la"

    def test_fuzzy_search_with_typo(self, db_client: Neo4jClient) -> None:
        """Test that fuzzy search finds commands despite typos."""
        cmd = Command(
            command="docker ps -a", description="List all docker containers", tags=["docker"]
        )

        db_client.add_command(cmd)

        # Search with typo "doker" instead of "docker"
        results = db_client.search_commands(query="doker", fuzzy=True, fuzzy_threshold=60)

        # Should find docker command despite typo
        assert len(results) >= 1
        assert results[0].command == "docker ps -a"

    def test_fuzzy_search_with_misspelling(self, db_client: Neo4jClient) -> None:
        """Test fuzzy search finds misspelled terms."""
        cmd = Command(
            command="kubectl get pods", description="Get Kubernetes pods", tags=["kubernetes"]
        )

        db_client.add_command(cmd)

        # Search with misspelling "kuberntes" instead of "kubernetes"
        results = db_client.search_commands(query="kuberntes", fuzzy=True, fuzzy_threshold=70)

        # Should find kubernetes command
        assert len(results) >= 1
        assert results[0].command == "kubectl get pods"

    def test_fuzzy_search_transposed_characters(self, db_client: Neo4jClient) -> None:
        """Test fuzzy search handles transposed characters."""
        cmd = Command(
            command="grep -r 'pattern' .",
            description="Search for pattern recursively",
            tags=["search"],
        )

        db_client.add_command(cmd)

        # Search with transposed chars "gerp" instead of "grep"
        results = db_client.search_commands(query="gerp", fuzzy=True, fuzzy_threshold=60)

        assert len(results) >= 1
        assert results[0].command == "grep -r 'pattern' ."

    def test_fuzzy_search_multiple_typos(self, db_client: Neo4jClient) -> None:
        """Test fuzzy search with multiple typos in query."""
        cmd = Command(
            command="systemctl restart nginx",
            description="Restart nginx service",
            tags=["systemd", "nginx"],
        )

        db_client.add_command(cmd)

        # Multiple typos: "systenctl restat" instead of "systemctl restart"
        results = db_client.search_commands(
            query="systenctl restat", fuzzy=True, fuzzy_threshold=70
        )

        assert len(results) >= 1
        assert results[0].command == "systemctl restart nginx"

    def test_fuzzy_search_extra_characters(self, db_client: Neo4jClient) -> None:
        """Test fuzzy search handles extra characters."""
        cmd = Command(
            command="curl https://api.example.com", description="Make HTTP request", tags=["http"]
        )

        db_client.add_command(cmd)

        # Extra characters: "currrl" instead of "curl"
        results = db_client.search_commands(query="currrl", fuzzy=True, fuzzy_threshold=60)

        assert len(results) >= 1
        assert results[0].command == "curl https://api.example.com"

    def test_fuzzy_search_missing_characters(self, db_client: Neo4jClient) -> None:
        """Test fuzzy search handles missing characters."""
        cmd = Command(
            command="terraform apply",
            description="Apply Terraform changes",
            tags=["terraform", "iac"],
        )

        db_client.add_command(cmd)

        # Missing characters: "teraform" instead of "terraform"
        results = db_client.search_commands(query="teraform", fuzzy=True, fuzzy_threshold=70)

        assert len(results) >= 1
        assert results[0].command == "terraform apply"

    def test_fuzzy_search_case_insensitive(self, db_client: Neo4jClient) -> None:
        """Test fuzzy search is case insensitive."""
        cmd = Command(
            command="PostgreSQL backup script",
            description="Backup PostgreSQL database",
            tags=["database", "backup"],
        )

        db_client.add_command(cmd)

        # Different case variations
        for query in ["POSTGRESQL", "postgresql", "PoStGrEsQl", "postgres"]:
            results = db_client.search_commands(query=query, fuzzy=True, fuzzy_threshold=70)
            assert len(results) >= 1
            assert "PostgreSQL" in results[0].command

    def test_fuzzy_search_partial_word(self, db_client: Neo4jClient) -> None:
        """Test fuzzy search matches partial words."""
        cmd = Command(
            command="git rebase -i HEAD~3",
            description="Interactive rebase last 3 commits",
            tags=["git", "rebase"],
        )

        db_client.add_command(cmd)

        # Partial word "rebas" instead of "rebase"
        results = db_client.search_commands(query="rebas", fuzzy=True, fuzzy_threshold=70)

        assert len(results) >= 1
        assert results[0].command == "git rebase -i HEAD~3"

    def test_fuzzy_search_abbreviation(self, db_client: Neo4jClient) -> None:
        """Test fuzzy search handles common abbreviations."""
        cmd = Command(
            command="kubernetes cluster info",
            description="Get Kubernetes cluster information",
            tags=["kubernetes"],
        )

        db_client.add_command(cmd)

        # Abbreviation "k8s" for "kubernetes"
        results = db_client.search_commands(query="k8s", fuzzy=True, fuzzy_threshold=40)

        assert len(results) >= 1
        assert (
            "kubernetes" in results[0].command.lower()
            or "kubernetes" in results[0].description.lower()
        )

    def test_fuzzy_search_with_numbers(self, db_client: Neo4jClient) -> None:
        """Test fuzzy search handles numbers correctly."""
        cmd = Command(
            command="ffmpeg -i input.mp4 output.mp3",
            description="Convert mp4 to mp3",
            tags=["ffmpeg", "media"],
        )

        db_client.add_command(cmd)

        # Query with slight variation "mp3 to mp4"
        results = db_client.search_commands(query="mp4 mp3", fuzzy=True, fuzzy_threshold=50)

        assert len(results) >= 1
        assert results[0].command == "ffmpeg -i input.mp4 output.mp3"

    def test_fuzzy_search_special_characters(self, db_client: Neo4jClient) -> None:
        """Test fuzzy search handles special characters."""
        cmd = Command(
            command="find . -name '*.py' -type f",
            description="Find all Python files",
            tags=["find", "python"],
        )

        db_client.add_command(cmd)

        # Search without special chars
        results = db_client.search_commands(query="find py type", fuzzy=True, fuzzy_threshold=50)

        assert len(results) >= 1
        assert results[0].command == "find . -name '*.py' -type f"

    def test_fuzzy_search_word_order_variation(self, db_client: Neo4jClient) -> None:
        """Test fuzzy search handles different word orders."""
        cmd = Command(
            command="docker build -t myapp:latest .",
            description="Build Docker image with tag",
            tags=["docker", "build"],
        )

        db_client.add_command(cmd)

        # Different word order: "build docker" instead of "docker build"
        results = db_client.search_commands(
            query="build docker latest", fuzzy=True, fuzzy_threshold=50
        )

        assert len(results) >= 1
        assert results[0].command == "docker build -t myapp:latest ."

    def test_fuzzy_search_with_filters_and_typo(self, db_client: Neo4jClient) -> None:
        """Test fuzzy search combined with other filters."""
        cmd1 = Command(
            command="docker ps -a",
            description="List all docker containers",
            tags=["docker"],
            os="linux",
        )
        cmd2 = Command(
            command="docker ps -a",
            description="List all docker containers",
            tags=["docker"],
            os="windows",
        )

        db_client.add_command(cmd1)
        db_client.add_command(cmd2)

        # Fuzzy search with OS filter and typo
        results = db_client.search_commands(
            query="doker", fuzzy=True, fuzzy_threshold=60, os="linux"
        )

        assert len(results) >= 1
        assert results[0].command == "docker ps -a"
        assert results[0].os == "linux"

    def test_fuzzy_search_no_results_below_threshold(self, db_client: Neo4jClient) -> None:
        """Test fuzzy search returns no results when score below threshold."""
        cmd = Command(
            command="ansible-playbook deploy.yml",
            description="Deploy with Ansible",
            tags=["ansible"],
        )

        db_client.add_command(cmd)

        # Completely unrelated query with high threshold
        results = db_client.search_commands(query="xyz123", fuzzy=True, fuzzy_threshold=80)

        assert len(results) == 0

    def test_fuzzy_search_single_character_typo(self, db_client: Neo4jClient) -> None:
        """Test fuzzy search handles single character differences."""
        cmd = Command(
            command="yarn install",
            description="Install dependencies with yarn",
            tags=["yarn", "node"],
        )

        db_client.add_command(cmd)

        # Single char diff: "yarm" instead of "yarn"
        results = db_client.search_commands(query="yarm", fuzzy=True, fuzzy_threshold=70)

        assert len(results) >= 1
        assert results[0].command == "yarn install"

    def test_fuzzy_search_phonetic_similarity(self, db_client: Neo4jClient) -> None:
        """Test fuzzy search with phonetically similar words."""
        cmd = Command(
            command="nmap -sV -p- 192.168.1.1",
            description="Network port scan",
            tags=["security", "network"],
        )

        db_client.add_command(cmd)

        # Phonetically similar: "enmap" instead of "nmap"
        results = db_client.search_commands(query="enmap", fuzzy=True, fuzzy_threshold=60)

        assert len(results) >= 1
        assert results[0].command == "nmap -sV -p- 192.168.1.1"

    def test_fuzzy_search_matches_context_field(self, db_client: Neo4jClient) -> None:
        """Test fuzzy search also matches against context field."""
        cmd = Command(
            command="make build",
            description="Build project",
            tags=["build"],
            context="Used in Django projects for deployment",
        )

        db_client.add_command(cmd)

        # Search for "djnago" (typo of "django") which is in context
        results = db_client.search_commands(query="djnago", fuzzy=True, fuzzy_threshold=70)

        assert len(results) >= 1
        assert results[0].command == "make build"

    def test_fuzzy_search_limit_respected(self, db_client: Neo4jClient) -> None:
        """Test that fuzzy search respects the limit parameter."""
        # Add multiple similar commands
        for i in range(10):
            cmd = Command(
                command=f"docker container ls {i}",
                description=f"List docker containers {i}",
                tags=["docker"],
            )
            db_client.add_command(cmd)

        # Search with limit
        results = db_client.search_commands(query="doker", fuzzy=True, fuzzy_threshold=60, limit=3)

        assert len(results) <= 3

    def test_fuzzy_search_prefers_higher_use_count(self, db_client: Neo4jClient) -> None:
        """Test that fuzzy search considers use_count in ranking."""
        cmd1 = Command(command="docker ps", description="List containers", tags=["docker"])
        cmd2 = Command(command="docker ps -a", description="List all containers", tags=["docker"])

        db_client.add_command(cmd1)
        db_client.add_command(cmd2)

        # Increment use_count for cmd2
        cmd2_stored = db_client.search_commands(query="ps -a", fuzzy=False)[0]
        for _ in range(5):
            db_client.get_command(cmd2_stored.id)

        # Search with typo
        results = db_client.search_commands(query="doker ps", fuzzy=True, fuzzy_threshold=60)

        # Should return results, potentially ordered by use_count
        assert len(results) >= 2

    def test_fuzzy_search_empty_database(self, db_client: Neo4jClient) -> None:
        """Test fuzzy search on empty database returns no results."""
        results = db_client.search_commands(query="anything", fuzzy=True, fuzzy_threshold=60)

        assert len(results) == 0

    def test_fuzzy_search_very_long_query(self, db_client: Neo4jClient) -> None:
        """Test fuzzy search handles very long queries."""
        cmd = Command(
            command="aws s3 sync . s3://bucket", description="Sync to S3", tags=["aws", "s3"]
        )

        db_client.add_command(cmd)

        # Very long query with typos
        long_query = "aws s3 sinc synchronize upload files to amazn bucket storage"
        results = db_client.search_commands(query=long_query, fuzzy=True, fuzzy_threshold=40)

        assert len(results) >= 1

    def test_fuzzy_search_unicode_characters(self, db_client: Neo4jClient) -> None:
        """Test fuzzy search handles unicode characters."""
        cmd = Command(
            command="echo 'Hello 世界'", description="Print hello world in Chinese", tags=["test"]
        )

        db_client.add_command(cmd)

        # Search with unicode
        results = db_client.search_commands(query="世界", fuzzy=True, fuzzy_threshold=60)

        assert len(results) >= 1
        assert results[0].command == "echo 'Hello 世界'"

    def test_fuzzy_search_combined_with_tags(self, db_client: Neo4jClient) -> None:
        """Test fuzzy search works with tag filtering."""
        cmd1 = Command(
            command="docker ps", description="List containers", tags=["docker", "container"]
        )
        cmd2 = Command(command="docker images", description="List images", tags=["docker", "image"])

        db_client.add_command(cmd1)
        db_client.add_command(cmd2)

        # Fuzzy search with typo AND tag filter
        results = db_client.search_commands(
            query="doker", fuzzy=True, fuzzy_threshold=60, tags=["docker", "container"]
        )

        assert len(results) >= 1
        assert results[0].command == "docker ps"

    def test_fuzzy_search_whitespace_variations(self, db_client: Neo4jClient) -> None:
        """Test fuzzy search handles whitespace variations."""
        cmd = Command(command="git commit -m 'message'", description="Commit changes", tags=["git"])

        db_client.add_command(cmd)

        # Query with different whitespace
        results = db_client.search_commands(query="git  commit", fuzzy=True, fuzzy_threshold=70)

        assert len(results) >= 1
        assert results[0].command == "git commit -m 'message'"

    def test_fuzzy_search_completely_unrelated_query(self, db_client: Neo4jClient) -> None:
        """Test fuzzy search returns nothing for completely unrelated queries."""
        cmd = Command(
            command="docker ps -a", description="List all docker containers", tags=["docker"]
        )

        db_client.add_command(cmd)

        # Completely unrelated queries
        unrelated_queries = [
            "zzzxxx999",
            "qwerty12345",
            "asdfghjkl",
            "foo bar baz qux",
            "completely different thing",
        ]

        for query in unrelated_queries:
            results = db_client.search_commands(query=query, fuzzy=True, fuzzy_threshold=60)
            assert len(results) == 0, f"Expected no results for '{query}'"

    def test_fuzzy_search_similar_but_not_matching(self, db_client: Neo4jClient) -> None:
        """Test fuzzy search doesn't return results for similar but unrelated terms."""
        cmd = Command(
            command="kubectl apply -f deployment.yaml",
            description="Apply Kubernetes deployment",
            tags=["kubernetes"],
        )

        db_client.add_command(cmd)

        # Similar looking but unrelated terms
        similar_but_different = [
            "mysql",  # Similar length, different tool
            "apache",  # Server software, not k8s
            "python",  # Programming language
            "windows",  # OS, not k8s
        ]

        for query in similar_but_different:
            results = db_client.search_commands(query=query, fuzzy=True, fuzzy_threshold=70)
            assert len(results) == 0, f"Expected no results for '{query}'"

    def test_fuzzy_search_partial_match_below_threshold(self, db_client: Neo4jClient) -> None:
        """Test that partial matches below threshold don't return results."""
        cmd = Command(
            command="terraform plan",
            description="Show Terraform execution plan",
            tags=["terraform", "iac"],
        )

        db_client.add_command(cmd)

        # Very different query with high threshold
        # Note: "form" appears in "terraform" so partial_ratio will be high
        # Use a truly different query instead
        results = db_client.search_commands(query="xyz", fuzzy=True, fuzzy_threshold=90)

        # "xyz" has no relation to terraform
        assert len(results) == 0

    def test_fuzzy_search_wrong_tool_names(self, db_client: Neo4jClient) -> None:
        """Test fuzzy search doesn't confuse different tool names."""
        # Add multiple commands with different tools
        commands = [
            Command(command="docker build", description="Build docker image", tags=["docker"]),
            Command(command="podman build", description="Build podman image", tags=["podman"]),
            Command(command="kubectl create", description="Create k8s resource", tags=["k8s"]),
        ]

        for cmd in commands:
            db_client.add_command(cmd)

        # Search for "npm" - shouldn't match any of these
        results = db_client.search_commands(query="npm install", fuzzy=True, fuzzy_threshold=60)

        assert len(results) == 0

    def test_fuzzy_search_numeric_mismatch(self, db_client: Neo4jClient) -> None:
        """Test fuzzy search doesn't match when numbers are completely different."""
        cmd = Command(command="port 8080", description="Check port 8080", tags=["network"])

        db_client.add_command(cmd)

        results = db_client.search_commands(
            query="database connection", fuzzy=True, fuzzy_threshold=70
        )

        # Should not match - completely different concepts
        assert len(results) == 0

    def test_fuzzy_search_language_specific_mismatch(self, db_client: Neo4jClient) -> None:
        """Test fuzzy search doesn't mix up programming languages."""
        commands = [
            Command(command="python script.py", description="Run Python", tags=["python"]),
            Command(command="node app.js", description="Run Node", tags=["node"]),
            Command(command="ruby script.rb", description="Run Ruby", tags=["ruby"]),
        ]

        for cmd in commands:
            db_client.add_command(cmd)

        # Search for Java - shouldn't match these
        results = db_client.search_commands(query="java", fuzzy=True, fuzzy_threshold=65)

        assert len(results) == 0

    def test_fuzzy_search_opposite_actions(self, db_client: Neo4jClient) -> None:
        """Test fuzzy search doesn't confuse opposite actions."""
        cmd = Command(
            command="docker stop container", description="Stop Docker container", tags=["docker"]
        )

        db_client.add_command(cmd)

        # Search for "start" - opposite of "stop"
        results = db_client.search_commands(query="docker start", fuzzy=True, fuzzy_threshold=70)

        # Should match "docker" but score might be too low due to start/stop difference
        # Verify it doesn't incorrectly return stop when asking for start
        if len(results) > 0:
            # If it does return something, verify it's actually relevant
            # This is a tricky case - "docker start" vs "docker stop" are very similar
            # We accept this might match, but document the behavior
            assert "docker" in results[0].command.lower()

    def test_fuzzy_search_with_filters_excludes_non_matching(self, db_client: Neo4jClient) -> None:
        """Test that fuzzy search with filters excludes non-matching records."""
        cmd1 = Command(
            command="docker ps", description="List containers", tags=["docker"], os="linux"
        )
        cmd2 = Command(command="dir /s", description="List files", tags=["windows"], os="windows")

        db_client.add_command(cmd1)
        db_client.add_command(cmd2)

        # Fuzzy search for "list" on linux only
        results = db_client.search_commands(
            query="list", fuzzy=True, fuzzy_threshold=50, os="linux"
        )

        # Should only get linux command
        assert all(r.os == "linux" for r in results)
        # Should not include windows command
        assert not any("dir" in r.command for r in results)

    def test_fuzzy_search_empty_string_query(self, db_client: Neo4jClient) -> None:
        """Test fuzzy search with empty string query."""
        cmd = Command(command="echo test", description="Print test", tags=["shell"])

        db_client.add_command(cmd)

        # Empty string query
        results = db_client.search_commands(query="", fuzzy=True, fuzzy_threshold=60)

        # Should return all commands (no filtering)
        assert len(results) >= 1

    def test_fuzzy_search_special_regex_chars_no_match(self, db_client: Neo4jClient) -> None:
        """Test fuzzy search handles special regex chars without false matches."""
        cmd = Command(
            command="grep pattern file.txt", description="Search for pattern", tags=["search"]
        )

        db_client.add_command(cmd)

        # Query with regex special chars that shouldn't match
        results = db_client.search_commands(query="***###$$$", fuzzy=True, fuzzy_threshold=60)

        # Should not match
        assert len(results) == 0

    def test_fuzzy_search_highest_use_count_first(self, db_client: Neo4jClient) -> None:
        """Test that commands with highest use_count are returned first."""
        # Add multiple similar commands
        cmd1 = Command(command="docker ps", description="List docker containers", tags=["docker"])
        cmd2 = Command(
            command="docker ps -a", description="List all docker containers", tags=["docker"]
        )
        cmd3 = Command(
            command="docker ps -q", description="List docker container IDs", tags=["docker"]
        )

        db_client.add_command(cmd1)
        db_client.add_command(cmd2)
        db_client.add_command(cmd3)

        # Increment use_count for cmd2 (5 times)
        cmd2_stored = db_client.search_commands(query="ps -a", fuzzy=False)[0]
        for _ in range(5):
            db_client.get_command(cmd2_stored.id)

        # Increment use_count for cmd3 (10 times - highest)
        cmd3_stored = db_client.search_commands(query="ps -q", fuzzy=False)[0]
        for _ in range(10):
            db_client.get_command(cmd3_stored.id)

        # Search with fuzzy - all should have same score
        results = db_client.search_commands(query="docker ps", fuzzy=True, fuzzy_threshold=60)

        # Should have all three
        assert len(results) >= 3

        # Highest use_count should be first (cmd3 with 10)
        assert results[0].command == "docker ps -q"
        assert results[0].use_count == 10

        # Second highest should be cmd2 (5)
        assert results[1].command == "docker ps -a"
        assert results[1].use_count == 5

        # Lowest should be cmd1 (0)
        assert results[2].command == "docker ps"
        assert results[2].use_count == 0

    def test_fuzzy_search_tie_score_sorted_by_use_count(self, db_client: Neo4jClient) -> None:
        """Test that when fuzzy scores tie, use_count determines order."""
        # Add commands that will score identically
        cmd1 = Command(command="kubectl get pods", description="Get all pods", tags=["k8s"])
        cmd2 = Command(command="kubectl get pods", description="List Kubernetes pods", tags=["k8s"])

        db_client.add_command(cmd1)
        db_client.add_command(cmd2)

        # Make cmd2 more popular
        cmd2_stored = db_client.search_commands(query="List Kubernetes pods", fuzzy=False)[0]
        for _ in range(8):
            db_client.get_command(cmd2_stored.id)

        # Search - both will have identical fuzzy scores
        results = db_client.search_commands(
            query="kubectl get pods", fuzzy=True, fuzzy_threshold=50
        )

        assert len(results) >= 2

        # Higher use_count should be first
        assert results[0].use_count == 8
        assert results[0].description == "List Kubernetes pods"

        assert results[1].use_count == 0
        assert results[1].description == "Get all pods"

    def test_exact_search_respects_use_count_order(self, db_client: Neo4jClient) -> None:
        """Test that exact search also orders by use_count."""
        # Add multiple commands with "git" in them
        cmd1 = Command(command="git status", description="Show git status", tags=["git"])
        cmd2 = Command(command="git log", description="Show git log", tags=["git"])
        cmd3 = Command(command="git commit", description="Commit changes", tags=["git"])

        db_client.add_command(cmd1)
        db_client.add_command(cmd2)
        db_client.add_command(cmd3)

        # Make cmd2 most popular
        cmd2_stored = db_client.search_commands(query="git log", fuzzy=False)[0]
        for _ in range(15):
            db_client.get_command(cmd2_stored.id)

        # Make cmd3 second most popular
        cmd3_stored = db_client.search_commands(query="git commit", fuzzy=False)[0]
        for _ in range(7):
            db_client.get_command(cmd3_stored.id)

        # Exact search for "git"
        results = db_client.search_commands(query="git", fuzzy=False)

        assert len(results) >= 3

        # Should be ordered by use_count
        assert results[0].command == "git log"
        assert results[0].use_count == 15

        assert results[1].command == "git commit"
        assert results[1].use_count == 7

        assert results[2].command == "git status"
        assert results[2].use_count == 0

    def test_fuzzy_search_use_count_overrides_slight_score_diff(
        self, db_client: Neo4jClient
    ) -> None:
        """Test use_count is considered when fuzzy scores are close."""
        # Add commands with slightly different fuzzy scores
        cmd1 = Command(
            command="systemctl restart nginx", description="Restart nginx service", tags=["systemd"]
        )
        cmd2 = Command(command="systemctl start nginx", description="Start nginx", tags=["systemd"])

        db_client.add_command(cmd1)
        db_client.add_command(cmd2)

        # Make cmd2 very popular
        cmd2_stored = db_client.search_commands(query="start nginx", fuzzy=False)[0]
        for _ in range(20):
            db_client.get_command(cmd2_stored.id)

        # Search with typo that matches both
        results = db_client.search_commands(query="systmctl nginx", fuzzy=True, fuzzy_threshold=60)

        assert len(results) >= 2

        # Even if scores are close, higher use_count should rank higher
        # (This tests the sort key: -score, then -use_count)
        use_counts = [r.use_count for r in results]
        assert use_counts[0] >= use_counts[1]
