import pytest
from strawberry.relay import GlobalID

from phoenix.db.models import SpanAnnotation
from phoenix.server.api.input_types.AnnotationFilter import (
    AnnotationFilter,
    AnnotationFilterCondition,
    satisfies_filter,
)
from phoenix.server.api.types.AnnotationSource import AnnotationSource


@pytest.mark.parametrize(
    "span_annotation, filter, expected_satisfies",
    [
        pytest.param(
            SpanAnnotation(
                span_rowid=1,
                name="test-name",
                label="label",
                score=1.0,
                explanation="explanation",
                metadata_={},
                annotator_kind="HUMAN",
                source="API",
            ),
            AnnotationFilter(include=AnnotationFilterCondition(names=["test-name"])),
            True,
            id="matches-included-name",
        ),
        pytest.param(
            SpanAnnotation(
                span_rowid=1,
                name="span-annotation-name",
                label="label",
                score=1.0,
                explanation="explanation",
                metadata_={},
                annotator_kind="HUMAN",
                source="API",
            ),
            AnnotationFilter(include=AnnotationFilterCondition(names=["missing-name"])),
            False,
            id="does-not-match-included-name",
        ),
        pytest.param(
            SpanAnnotation(
                span_rowid=1,
                name="test-name",
                label="label",
                score=1.0,
                explanation="explanation",
                metadata_={},
                annotator_kind="HUMAN",
                source="API",
            ),
            AnnotationFilter(exclude=AnnotationFilterCondition(names=["test-name"])),
            False,
            id="matches-excluded-name",
        ),
        pytest.param(
            SpanAnnotation(
                span_rowid=1,
                name="test-name",
                label="label",
                score=1.0,
                explanation="explanation",
                metadata_={},
                annotator_kind="HUMAN",
                source="API",
            ),
            AnnotationFilter(exclude=AnnotationFilterCondition(names=["different-name"])),
            True,
            id="does-not-match-excluded-name",
        ),
        pytest.param(
            SpanAnnotation(
                span_rowid=1,
                name="test-name",
                label="label",
                score=1.0,
                explanation="explanation",
                metadata_={},
                annotator_kind="HUMAN",
                source="API",
            ),
            AnnotationFilter(include=AnnotationFilterCondition(sources=[AnnotationSource.API])),
            True,
            id="matches-included-source",
        ),
        pytest.param(
            SpanAnnotation(
                span_rowid=1,
                name="test-name",
                label="label",
                score=1.0,
                explanation="explanation",
                metadata_={},
                annotator_kind="HUMAN",
                source="APP",
            ),
            AnnotationFilter(include=AnnotationFilterCondition(sources=[AnnotationSource.API])),
            False,
            id="does-not-match-included-source",
        ),
        pytest.param(
            SpanAnnotation(
                span_rowid=1,
                name="test-name",
                label="label",
                score=1.0,
                explanation="explanation",
                metadata_={},
                annotator_kind="HUMAN",
                source="APP",
            ),
            AnnotationFilter(exclude=AnnotationFilterCondition(sources=[AnnotationSource.APP])),
            False,
            id="matches-excluded-source",
        ),
        pytest.param(
            SpanAnnotation(
                span_rowid=1,
                name="test-name",
                label="label",
                score=1.0,
                explanation="explanation",
                metadata_={},
                annotator_kind="HUMAN",
                source="API",
            ),
            AnnotationFilter(exclude=AnnotationFilterCondition(sources=[AnnotationSource.APP])),
            True,
            id="does-not-match-excluded-source",
        ),
        pytest.param(
            SpanAnnotation(
                span_rowid=1,
                name="test-name",
                label="label",
                score=1.0,
                explanation="explanation",
                metadata_={},
                annotator_kind="HUMAN",
                source="API",
                user_id=1,
            ),
            AnnotationFilter(include=AnnotationFilterCondition(user_ids=[GlobalID("User", "1")])),
            True,
            id="matches-included-user-id",
        ),
        pytest.param(
            SpanAnnotation(
                span_rowid=1,
                name="test-name",
                label="label",
                score=1.0,
                explanation="explanation",
                metadata_={},
                annotator_kind="HUMAN",
                source="API",
                user_id=1,
            ),
            AnnotationFilter(include=AnnotationFilterCondition(user_ids=[GlobalID("User", "2")])),
            False,
            id="does-not-match-included-user-id",
        ),
        pytest.param(
            SpanAnnotation(
                span_rowid=1,
                name="test-name",
                label="label",
                score=1.0,
                explanation="explanation",
                metadata_={},
                annotator_kind="HUMAN",
                source="API",
                user_id=None,
            ),
            AnnotationFilter(include=AnnotationFilterCondition(user_ids=[GlobalID("User", "1")])),
            False,
            id="does-not-match-included-user-id-with-null-user-id",
        ),
        pytest.param(
            SpanAnnotation(
                span_rowid=1,
                name="test-name",
                label="label",
                score=1.0,
                explanation="explanation",
                metadata_={},
                annotator_kind="HUMAN",
                source="API",
                user_id=1,
            ),
            AnnotationFilter(exclude=AnnotationFilterCondition(user_ids=[GlobalID("User", "1")])),
            False,
            id="matches-excluded-user-id",
        ),
        pytest.param(
            SpanAnnotation(
                span_rowid=1,
                name="test-name",
                label="label",
                score=1.0,
                explanation="explanation",
                metadata_={},
                annotator_kind="HUMAN",
                source="API",
                user_id=2,
            ),
            AnnotationFilter(exclude=AnnotationFilterCondition(user_ids=[GlobalID("User", "1")])),
            True,
            id="does-not-match-excluded-user-id",
        ),
        pytest.param(
            SpanAnnotation(
                span_rowid=1,
                name="test-name",
                label="label",
                score=1.0,
                explanation="explanation",
                metadata_={},
                annotator_kind="HUMAN",
                source="API",
                user_id=None,
            ),
            AnnotationFilter(exclude=AnnotationFilterCondition(user_ids=[GlobalID("User", "1")])),
            True,
            id="does-not-match-excluded-user-id-with-null-user-id",
        ),
        pytest.param(
            SpanAnnotation(
                span_rowid=1,
                name="test-name",
                label="label",
                score=1.0,
                explanation="explanation",
                metadata_={},
                annotator_kind="HUMAN",
                source="API",
                user_id=1,
            ),
            AnnotationFilter(
                include=AnnotationFilterCondition(
                    names=["test-name"],
                    sources=[AnnotationSource.API],
                    user_ids=[GlobalID("User", "1")],
                ),
                exclude=AnnotationFilterCondition(
                    names=["other-name"],
                    sources=[AnnotationSource.APP],
                    user_ids=[GlobalID("User", "2")],
                ),
            ),
            True,
            id="matches-all-include-fields-and-no-exclude-fields",
        ),
        pytest.param(
            SpanAnnotation(
                span_rowid=1,
                name="test-name",
                label="label",
                score=1.0,
                explanation="explanation",
                metadata_={},
                annotator_kind="HUMAN",
                source="API",
                user_id=1,
            ),
            AnnotationFilter(
                include=AnnotationFilterCondition(
                    names=["test-name"],
                    sources=[AnnotationSource.API],
                    user_ids=[GlobalID("User", "1")],
                ),
                exclude=AnnotationFilterCondition(names=["test-name"]),
            ),
            False,
            id="matches-all-include-fields-but-fails-on-exclude-name",
        ),
        pytest.param(
            SpanAnnotation(
                span_rowid=1,
                name="test-name",
                label="label",
                score=1.0,
                explanation="explanation",
                metadata_={},
                annotator_kind="HUMAN",
                source="API",
            ),
            AnnotationFilter(
                include=AnnotationFilterCondition(
                    names=["test-name", "other-name"],
                    sources=[AnnotationSource.API, AnnotationSource.APP],
                ),
            ),
            True,
            id="matches-multiple-included-names-and-sources",
        ),
        pytest.param(
            SpanAnnotation(
                span_rowid=1,
                name="test-name",
                label="label",
                score=1.0,
                explanation="explanation",
                metadata_={},
                annotator_kind="HUMAN",
                source="API",
            ),
            AnnotationFilter(
                exclude=AnnotationFilterCondition(
                    names=["test-name", "other-name"],
                    sources=[AnnotationSource.API, AnnotationSource.APP],
                ),
            ),
            False,
            id="matches-multiple-excluded-names-and-sources",
        ),
    ],
)
def test_satisfies_filter(
    span_annotation: SpanAnnotation,
    filter: AnnotationFilter,
    expected_satisfies: bool,
) -> None:
    assert satisfies_filter(span_annotation, filter) == expected_satisfies
