from django.test import SimpleTestCase
from django.db.models.query import Q

from console_base.utils import (
    jquery_builder,
    QTestMixin,
)


# -----------------------------------------------------------------------
class TestjQueryBuilder(SimpleTestCase, QTestMixin):
    def test_equal_q(self):
        q = {
            "condition": "OR",
            "rules": [
                {
                    "id": "date",
                    "field": "domain_name",
                    "type": "string",
                    "input": "text",
                    "operator": "exact",
                    "value": "google.com",
                }
            ],
        }
        self.assertQEqual(jquery_builder(q), Q(domain_name__exact='google.com'))

    def test_equals_negate_string(self):
        q = {
            "condition": "OR",
            "rules": [
                {
                    "id": "date",
                    "field": "domain_name",
                    "type": "string",
                    "input": "text",
                    "operator": "not_exact",
                    "value": "google.com",
                }
            ],
        }
        self.assertQEqual(jquery_builder(q), ~Q(domain_name__exact='google.com'))

    def test_equals_negate_list(self):
        q = {
            "condition": "OR",
            "rules": [
                {
                    "id": "date",
                    "field": "domain_name",
                    "type": "string",
                    "input": "text",
                    "operator": "not_in",
                    "value": "google.com,hp.com,lenovo.com",
                }
            ],
        }
        self.assertQEqual(
            jquery_builder(q), ~Q(domain_name__in=['google.com', 'hp.com', 'lenovo.com'])
        )

    def test_equals_contains_list(self):
        q = {
            "condition": "AND",
            "rules": [
                {
                    "id": "date",
                    "field": "domain_name",
                    "type": "string",
                    "input": "text",
                    "operator": "not_in",
                    "value": "google.com,hp.com,lenovo.com",
                }
            ],
        }
        self.assertQEqual(
            jquery_builder(q), ~Q(domain_name__in=['google.com', 'hp.com', 'lenovo.com'])
        )

    def test_list_with_single_value(self):
        q = {
            "condition": "OR",
            "rules": [
                {
                    "id": "device_type",
                    "field": "device_type",
                    "type": "string",
                    "input": "select",
                    "operator": "equal",
                    "value": ["smartphone"],
                }
            ],
            "not": False,
            "valid": True,
        }
        self.assertQEqual(jquery_builder(q), Q(device_type__exact="smartphone"))

        q = {
            "condition": "OR",
            "rules": [
                {
                    "id": "device_type",
                    "field": "device_type",
                    "type": "string",
                    "input": "select",
                    "operator": "ends_with",
                    "value": ["aws.com"],
                }
            ],
            "not": False,
            "valid": True,
        }
        self.assertQEqual(jquery_builder(q), Q(device_type__endswith="aws.com"))

    def test_multiple_or_filters(self):
        q = {
            "condition": "OR",
            "rules": [
                {
                    "id": "date",
                    "field": "domain_name",
                    "type": "string",
                    "input": "text",
                    "operator": "equal",
                    "value": "google.com",
                },
                {
                    "id": "date",
                    "field": "mimetype",
                    "type": "string",
                    "input": "text",
                    "operator": "equal",
                    "value": "text/html",
                },
            ],
        }
        self.assertQEqual(
            jquery_builder(q), Q(domain_name__exact='google.com') | Q(mimetype__exact='text/html')
        )

    def test_multiple_groups(self):
        q = {
            "condition": "AND",
            "rules": [
                {
                    "condition": "OR",
                    "rules": [
                        {
                            "id": "rating",
                            "field": "rating",
                            "type": "string",
                            "input": "select",
                            "operator": "in",
                            "value": ["bld", "rck"],
                        },
                        {
                            "id": "top_rating",
                            "field": "top_rating",
                            "type": "string",
                            "input": "select",
                            "operator": "in",
                            "value": ["bld", "rck"],
                        },
                    ],
                },
                {
                    "condition": "AND",
                    "rules": [
                        {
                            "id": "rating_confidence",
                            "field": "rating_confidence",
                            "type": "integer",
                            "input": "text",
                            "operator": "greater_or_equal",
                            "value": "50",
                        }
                    ],
                },
            ],
        }
        self.assertQEqual(
            jquery_builder(q),
            Q(Q(rating__in=['bld', 'rck']) | Q(top_rating__in=['bld', 'rck']))
            & Q(rating_confidence__gte=50.0),
        )

    def test_multiple_groups_with_multiple_filters(self):
        q = {
            "condition": "OR",
            "rules": [
                {
                    "condition": "AND",
                    "rules": [
                        {
                            "id": "rating",
                            "field": "rating",
                            "type": "string",
                            "input": "select",
                            "operator": "in",
                            "value": ["bld", "rck"],
                        },
                        {
                            "id": "rating_confidence",
                            "field": "rating_confidence",
                            "type": "integer",
                            "input": "text",
                            "operator": "greater_or_equal",
                            "value": "50",
                        },
                    ],
                },
                {
                    "condition": "AND",
                    "rules": [
                        {
                            "id": "top_rating",
                            "field": "top_rating",
                            "type": "string",
                            "input": "select",
                            "operator": "in",
                            "value": ["bld", "rck"],
                        },
                        {
                            "id": "rating_confidence",
                            "field": "rating_confidence",
                            "type": "integer",
                            "input": "text",
                            "operator": "less_or_equal",
                            "value": "50",
                        },
                    ],
                },
            ],
        }
        self.assertQEqual(
            jquery_builder(q),
            Q(Q(rating__in=['bld', 'rck']) & Q(rating_confidence__gte=50.0))
            | Q(Q(top_rating__in=['bld', 'rck']) & Q(rating_confidence__lte=50.0)),
        )

    def test_less_than(self):
        q = {
            "condition": "AND",
            "rules": [
                {
                    "id": "category_confidence",
                    "field": "category_confidence",
                    "type": "integer",
                    "input": "text",
                    "operator": "less",
                    "value": "50",
                }
            ],
        }
        self.assertQEqual(jquery_builder(q), Q(category_confidence__lt=50.0))

    def test_less_than_or_equal(self):
        q = {
            "condition": "AND",
            "rules": [
                {
                    "id": "category_confidence",
                    "field": "category_confidence",
                    "type": "integer",
                    "input": "text",
                    "operator": "less_or_equal",
                    "value": "70.2",
                }
            ],
        }
        self.assertQEqual(jquery_builder(q), Q(category_confidence__lte=70.2))

    def test_greater(self):
        q = {
            "condition": "AND",
            "rules": [
                {
                    "id": "category_confidence",
                    "field": "category_confidence",
                    "type": "integer",
                    "input": "text",
                    "operator": "greater",
                    "value": "50",
                }
            ],
        }
        self.assertQEqual(jquery_builder(q), Q(category_confidence__gt=50.0))

    def test_greater_than_or_equal(self):
        q = {
            "condition": "AND",
            "rules": [
                {
                    "id": "category_confidence",
                    "field": "category_confidence",
                    "type": "integer",
                    "input": "text",
                    "operator": "greater_or_equal",
                    "value": "50.6",
                }
            ],
        }
        self.assertQEqual(jquery_builder(q), Q(category_confidence__gte=50.6))

    def test_range(self):
        q = {
            "condition": "AND",
            "rules": [
                {
                    "id": "category_confidence",
                    "field": "category_confidence",
                    "type": "integer",
                    "input": "text",
                    "operator": "between",
                    "value": ["25.8", "50.9"],
                }
            ],
        }
        self.assertQEqual(jquery_builder(q), Q(category_confidence__range=[25.8, 50.9]))

    def test_not_range(self):
        q = {
            "condition": "AND",
            "rules": [
                {
                    "id": "category_confidence",
                    "field": "category_confidence",
                    "type": "integer",
                    "input": "text",
                    "operator": "not_between",
                    "value": ["25.8", "50.9"],
                }
            ],
        }
        self.assertQEqual(jquery_builder(q), ~Q(category_confidence__range=[25.8, 50.9]))

    def test_startswith(self):
        q = {
            "condition": "AND",
            "rules": [
                {
                    "id": "domain_name",
                    "field": "domain_name",
                    "type": "string",
                    "input": "text",
                    "operator": "begins_with",
                    "value": "google",
                }
            ],
        }
        self.assertQEqual(jquery_builder(q), Q(domain_name__startswith='google'))

    def test_not_startswith(self):
        q = {
            "condition": "AND",
            "rules": [
                {
                    "id": "domain_name",
                    "field": "domain_name",
                    "type": "string",
                    "input": "text",
                    "operator": "not_begins_with",
                    "value": "google",
                }
            ],
        }
        self.assertQEqual(jquery_builder(q), ~Q(domain_name__startswith='google'))

    def test_endswith(self):
        q = {
            "condition": "AND",
            "rules": [
                {
                    "id": "domain_name",
                    "field": "domain_name",
                    "type": "string",
                    "input": "text",
                    "operator": "ends_with",
                    "value": "google",
                }
            ],
        }
        self.assertQEqual(jquery_builder(q), Q(domain_name__endswith='google'))

    def test_not_endswith(self):
        q = {
            "condition": "AND",
            "rules": [
                {
                    "id": "domain_name",
                    "field": "domain_name",
                    "type": "string",
                    "input": "text",
                    "operator": "not_ends_with",
                    "value": "google",
                }
            ],
        }
        self.assertQEqual(jquery_builder(q), ~Q(domain_name__endswith='google'))

    def test_isnull(self):
        q = {
            "condition": "AND",
            "rules": [
                {
                    "id": "rating",
                    "field": "rating",
                    "type": "string",
                    "input": "select",
                    "operator": "is_null",
                    "value": None,
                }
            ],
        }
        self.assertQEqual(jquery_builder(q), Q(rating__isnull=True))

    def test_isnot_null(self):
        q = {
            "condition": "AND",
            "rules": [
                {
                    "id": "rating",
                    "field": "rating",
                    "type": "string",
                    "input": "select",
                    "operator": "is_not_null",
                    "value": None,
                }
            ],
        }
        self.assertQEqual(jquery_builder(q), ~Q(rating__isnull=True))
