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', (['"""id"""', 'value', 'operation'], {}), False, 'from datagateway_api.src.datagateway_api.icat.filters import PythonICATWhereFilter\n'), (41, 'datagateway_api.src.datagateway_api.icat.filters.PythonICATWhereFilter', 'PythonICATWhereFilter', (['"""id"""', '(10)', '"""non"""'], {}), False, 'from datagateway_api.src.datagateway_api.icat.filters import PythonICATWhereFilter\n'), (48, 'datagateway_api.src.datagateway_api.icat.filters.PythonICATWhereFilter', 'PythonICATWhereFilter', (['"""startDate"""', '"""o.endDate"""', '"""lt"""'], {}), False, 'from datagateway_api.src.datagateway_api.icat.filters import PythonICATWhereFilter\n'), (54, 'datagateway_api.src.datagateway_api.icat.filters.PythonICATWhereFilter', 'PythonICATWhereFilter', (['"""title"""', '"""Investigation Title"""', '"""eq"""'], {}), False, 'from datagateway_api.src.datagateway_api.icat.filters import PythonICATWhereFilter\n'), (60, 'datagateway_api.src.datagateway_api.icat.filters.PythonICATWhereFilter', 'PythonICATWhereFilter', (['"""random_field"""', '"""my_value"""', '"""eq"""'], {}), False, 'from datagateway_api.src.datagateway_api.icat.filters import PythonICATWhereFilter\n'), (66, 'datagateway_api.src.datagateway_api.icat.filters.PythonICATWhereFilter', 'PythonICATWhereFilter', (['"""id"""', '(10)', '"""lt"""'], {}), False, 'from datagateway_api.src.datagateway_api.icat.filters import PythonICATWhereFilter\n'), (67, 'datagateway_api.src.datagateway_api.icat.filters.PythonICATWhereFilter', 'PythonICATWhereFilter', (['"""id"""', '(5)', '"""gt"""'], {}), 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', (['"""eq"""', '(5)', '["%s = \'5\'"]'], {'id': '"""equal"""'}), False, 'import pytest\n'), (13, 'pytest.param', 'pytest.param', (['"""ne"""', '(5)', "['%s != 5']"], {'id': '"""not equal"""'}), False, 'import pytest\n'), (14, 'pytest.param', 'pytest.param', (['"""like"""', '(5)', '["%s like \'%%5%%\'"]'], {'id': '"""like"""'}), False, 'import pytest\n'), (15, 'pytest.param', 'pytest.param', (['"""ilike"""', '(5)', '["UPPER(%s) like UPPER(\'%%5%%\')"]'], {'id': '"""ilike"""'}), False, 'import pytest\n'), (16, 'pytest.param', 'pytest.param', (['"""nlike"""', '(5)', '["%s not like \'%%5%%\'"]'], {'id': '"""not like"""'}), False, 'import pytest\n'), (17, 'pytest.param', 'pytest.param', (['"""nilike"""', '(5)', '["UPPER(%s) not like UPPER(\'%%5%%\')"]'], {'id': '"""not ilike"""'}), False, 'import pytest\n'), (20, 'pytest.param', 'pytest.param', (['"""lt"""', '(5)', '["%s < \'5\'"]'], {'id': '"""less than"""'}), False, 'import pytest\n'), (21, 'pytest.param', 'pytest.param', (['"""lte"""', '(5)', '["%s <= \'5\'"]'], {'id': '"""less than or equal"""'}), False, 'import pytest\n'), (22, 'pytest.param', 'pytest.param', (['"""gt"""', '(5)', '["%s > \'5\'"]'], {'id': '"""greater than"""'}), False, 'import pytest\n'), (23, 'pytest.param', 'pytest.param', (['"""gte"""', '(5)', '["%s >= \'5\'"]'], {'id': '"""greater than or equal"""'}), False, 'import pytest\n'), (24, 'pytest.param', 'pytest.param', (['"""in"""', '[1, 2, 3, 4]', "['%s in (1, 2, 3, 4)']"], {'id': '"""in a list"""'}), False, 'import pytest\n'), (25, 'pytest.param', 'pytest.param', (['"""in"""', '[]', "['%s in (NULL)']"], {'id': '"""empty list"""'}), False, 'import pytest\n'), (37, 'pytest.raises', 'pytest.raises', (['BadRequestError'], {}), False, 'import pytest\n'), (38, 'datagateway_api.src.datagateway_api.icat.filters.PythonICATWhereFilter', 'PythonICATWhereFilter', (['"""id"""', '"""1, 2, 3, 4, 5"""', '"""in"""'], {}), False, 'from datagateway_api.src.datagateway_api.icat.filters import PythonICATWhereFilter\n'), (43, 'pytest.raises', 'pytest.raises', (['FilterError'], {}), False, 'import pytest\n'), (62, 'pytest.raises', 'pytest.raises', (['FilterError'], {}), False, 'import pytest\n')]