import pytest
import random

from .helpers.collection_setup import (
    drop_collection,
)
from .helpers.helpers import (
    request_with_validation,
)

# Field name constant
FIELD_NAME = "text"


def setup_phrase_collection(
    collection_name="test_phrase_collection",
):
    """Setup a collection with phrase matching enabled for text fields."""
    drop_collection(collection_name)

    # Create collection
    response = request_with_validation(
        api="/collections/{collection_name}",
        method="PUT",
        path_params={"collection_name": collection_name},
        body={
            "vectors": {
                "size": 4,
                "distance": "Dot",
            },
        },
    )
    assert response.ok

    # Create text index with phrase matching enabled
    response = request_with_validation(
        api="/collections/{collection_name}/index",
        method="PUT",
        path_params={"collection_name": collection_name},
        query_params={"wait": "true"},
        body={
            "field_name": FIELD_NAME,
            "field_schema": {
                "type": "text",
                "tokenizer": "word",
                "phrase_matching": True,
            },
        },
    )
    assert response.ok

    # Insert test points with various sentences
    phrases = [
        "the quick brown fox jumps over the lazy dog",
        "a quick brown cat runs through the garden",
        "the brown fox is very quick and agile",
        "lazy dogs sleep all day long",
        "machine learning algorithms are powerful tools",
        "natural language processing with transformers",
        "the artificial intelligence revolution",
        "deep learning neural networks",
        "brown sugar and quick oats",
        "New York City is a bustling metropolis",
        "writing tests is very very very important",
    ]

    test_data = [
        {
            "id": i + 1,
            "vector": [random.random() for _ in range(4)],
            "payload": {FIELD_NAME: phrase},
        }
        for i, phrase in enumerate(phrases)
    ]

    response = request_with_validation(
        api="/collections/{collection_name}/points",
        method="PUT",
        path_params={"collection_name": collection_name},
        query_params={"wait": "true"},
        body={"points": test_data},
    )
    assert response.ok

    return collection_name


@pytest.fixture(scope="module")
def phrase_collection():
    collection_name = setup_phrase_collection()
    yield collection_name
    drop_collection(collection_name)


@pytest.mark.parametrize(
    "phrase,expected_count,expected_ids,description",
    [
        (
            "quick brown fox",
            1,
            {1},
            "exact sequence match",
        ),
        (
            "quick brown bird",
            0,
            set(),
            "exact sequence with unknown token",
        ),
        (
            "brown quick",
            0,
            set(),
            "wrong order no match",
        ),
        (
            "quick brown",
            2,
            {1, 2},
            "correct order",
        ),
        (
            "brown",
            4,
            {1, 2, 3, 9},
            "single word phrase",
        ),
        (
            "machine learning algorithms are powerful tools",
            1,
            {5},
            "longer phrase match",
        ),
        ("", 0, set(), "empty phrase"),
        ("very very very", 1, {11}, "repeated word"),
        ("very very very very", 0, set(), "repeated word too many times"),
    ],
)
def test_phrase_matching(
    phrase_collection,
    phrase,
    expected_count,
    expected_ids,
    description,
):
    """Test phrase matching with various phrases and expected results."""

    # Test scroll endpoint
    scroll_response = request_with_validation(
        api="/collections/{collection_name}/points/scroll",
        method="POST",
        path_params={"collection_name": phrase_collection},
        body={
            "limit": 10,
            "with_payload": True,
            "with_vector": False,
            "filter": {
                "must": [
                    {
                        "key": FIELD_NAME,
                        "match": {"phrase": phrase},
                    }
                ]
            },
        },
    )

    assert scroll_response.ok
    scroll_result = scroll_response.json()["result"]

    # Verify expected count
    assert len(scroll_result["points"]) == expected_count, (
        f"Failed for {description}: expected {expected_count} points"
    )

    # Verify expected IDs if any matches
    if expected_count > 0:
        matched_ids = {point["id"] for point in scroll_result["points"]}
        assert matched_ids == expected_ids, (
            f"Failed for {description}: expected IDs {expected_ids}, got {matched_ids}"
        )

        # Verify that phrase appears in matched documents (except empty phrase)
        if phrase:
            for point in scroll_result["points"]:
                assert phrase in point["payload"][FIELD_NAME], (
                    f"Phrase '{phrase}' not found in matched document"
                )

    # Check count
    count_response = request_with_validation(
        api="/collections/{collection_name}/points/count",
        method="POST",
        path_params={"collection_name": phrase_collection},
        body={
            "filter": {
                "must": [
                    {
                        "key": FIELD_NAME,
                        "match": {"phrase": phrase},
                    }
                ]
            },
        },
    )

    assert count_response.ok
    count_result = count_response.json()["result"]

    # Verify count matches scroll results
    assert count_result["count"] == expected_count, f"Count endpoint mismatch for {description}"
