import pytest

from datagateway_api.src.common.exceptions import BadRequestError, FilterError
from datagateway_api.src.datagateway_api.filter_order_handler import FilterOrderHandler
from datagateway_api.src.datagateway_api.icat.filters import PythonICATWhereFilter


class TestICATWhereFilter:
    @pytest.mark.parametrize(
        "operation, value, expected_condition_value",
        [
            pytest.param("eq", 5, ["%s = '5'"], id="equal"),
            pytest.param("ne", 5, ["%s != 5"], id="not equal"),
            pytest.param("like", 5, ["%s like '%%5%%'"], id="like"),
            pytest.param("ilike", 5, ["UPPER(%s) like UPPER('%%5%%')"], id="ilike"),
            pytest.param("nlike", 5, ["%s not like '%%5%%'"], id="not like"),
            pytest.param(
                "nilike", 5, ["UPPER(%s) not like UPPER('%%5%%')"], id="not ilike",
            ),
            pytest.param("lt", 5, ["%s < '5'"], id="less than"),
            pytest.param("lte", 5, ["%s <= '5'"], id="less than or equal"),
            pytest.param("gt", 5, ["%s > '5'"], id="greater than"),
            pytest.param("gte", 5, ["%s >= '5'"], id="greater than or equal"),
            pytest.param("in", [1, 2, 3, 4], ["%s in (1, 2, 3, 4)"], id="in a list"),
            pytest.param("in", [], ["%s in (NULL)"], id="empty list"),
        ],
    )
    def test_valid_operations(
        self, icat_query, operation, value, expected_condition_value,
    ):
        test_filter = PythonICATWhereFilter("id", value, operation)
        test_filter.apply_filter(icat_query)

        assert icat_query.conditions == {"id": expected_condition_value}

    def test_invalid_in_operation(self, icat_query):
        with pytest.raises(BadRequestError):
            PythonICATWhereFilter("id", "1, 2, 3, 4, 5", "in")

    def test_invalid_operation(self, icat_query):
        test_filter = PythonICATWhereFilter("id", 10, "non")

        with pytest.raises(FilterError):
            test_filter.apply_filter(icat_query)

    def test_valid_internal_icat_value(self, icat_query):
        """Check that values that point to other values in the schema are applied"""
        test_filter = PythonICATWhereFilter("startDate", "o.endDate", "lt")
        test_filter.apply_filter(icat_query)

        assert icat_query.conditions == {"startDate": ["%s < o.endDate"]}

    def test_valid_field(self, icat_query):
        test_filter = PythonICATWhereFilter("title", "Investigation Title", "eq")
        test_filter.apply_filter(icat_query)

        assert icat_query.conditions == {"title": ["%s = 'Investigation Title'"]}

    def test_invalid_field(self, icat_query):
        test_filter = PythonICATWhereFilter("random_field", "my_value", "eq")

        with pytest.raises(FilterError):
            test_filter.apply_filter(icat_query)

    def test_multiple_conditions_per_field(self, icat_query):
        lt_filter = PythonICATWhereFilter("id", 10, "lt")
        gt_filter = PythonICATWhereFilter("id", 5, "gt")

        filter_handler = FilterOrderHandler()
        filter_handler.add_filters([lt_filter, gt_filter])
        filter_handler.apply_filters(icat_query)

        assert icat_query.conditions == {"id": ["%s < '10'", "%s > '5'"]}

[(31, 'datagateway_api.src.datagateway_api.icat.filters.PythonICATWhereFilter', 'PythonICATWhereFilter', False, 'from datagateway_api.src.datagateway_api.icat.filters import PythonICATWhereFilter\n'), (41, 'datagateway_api.src.datagateway_api.icat.filters.PythonICATWhereFilter', 'PythonICATWhereFilter', False, 'from datagateway_api.src.datagateway_api.icat.filters import PythonICATWhereFilter\n'), (48, 'datagateway_api.src.datagateway_api.icat.filters.PythonICATWhereFilter', 'PythonICATWhereFilter', False, 'from datagateway_api.src.datagateway_api.icat.filters import PythonICATWhereFilter\n'), (54, 'datagateway_api.src.datagateway_api.icat.filters.PythonICATWhereFilter', 'PythonICATWhereFilter', False, 'from datagateway_api.src.datagateway_api.icat.filters import PythonICATWhereFilter\n'), (60, 'datagateway_api.src.datagateway_api.icat.filters.PythonICATWhereFilter', 'PythonICATWhereFilter', False, 'from datagateway_api.src.datagateway_api.icat.filters import PythonICATWhereFilter\n'), (66, 'datagateway_api.src.datagateway_api.icat.filters.PythonICATWhereFilter', 'PythonICATWhereFilter', False, 'from datagateway_api.src.datagateway_api.icat.filters import PythonICATWhereFilter\n'), (67, 'datagateway_api.src.datagateway_api.icat.filters.PythonICATWhereFilter', 'PythonICATWhereFilter', False, 'from datagateway_api.src.datagateway_api.icat.filters import PythonICATWhereFilter\n'), (69, 'datagateway_api.src.datagateway_api.filter_order_handler.FilterOrderHandler', 'FilterOrderHandler', False, 'from datagateway_api.src.datagateway_api.filter_order_handler import FilterOrderHandler\n'), (12, 'pytest.param', 'pytest.param', False, 'import pytest\n'), (13, 'pytest.param', 'pytest.param', False, 'import pytest\n'), (14, 'pytest.param', 'pytest.param', False, 'import pytest\n'), (15, 'pytest.param', 'pytest.param', False, 'import pytest\n'), (16, 'pytest.param', 'pytest.param', False, 'import pytest\n'), (17, 'pytest.param', 'pytest.param', False, 'import pytest\n'), (20, 'pytest.param', 'pytest.param', False, 'import pytest\n'), (21, 'pytest.param', 'pytest.param', False, 'import pytest\n'), (22, 'pytest.param', 'pytest.param', False, 'import pytest\n'), (23, 'pytest.param', 'pytest.param', False, 'import pytest\n'), (24, 'pytest.param', 'pytest.param', False, 'import pytest\n'), (25, 'pytest.param', 'pytest.param', False, 'import pytest\n'), (37, 'pytest.raises', 'pytest.raises', False, 'import pytest\n'), (38, 'datagateway_api.src.datagateway_api.icat.filters.PythonICATWhereFilter', 'PythonICATWhereFilter', False, 'from datagateway_api.src.datagateway_api.icat.filters import PythonICATWhereFilter\n'), (43, 'pytest.raises', 'pytest.raises', False, 'import pytest\n'), (62, 'pytest.raises', 'pytest.raises', False, 'import pytest\n')]