"""This file and its contents are licensed under the Apache License 2.0. Please see the included NOTICE for copyright information and LICENSE for a copy of the license.
"""
import pytest
import json

from ..utils import make_task, make_annotation, make_prediction, project_id, make_annotator
from projects.models import Project
from data_import.models import FileUpload
from django.conf import settings
from django.core.files.base import ContentFile
from django.utils.timezone import now


@pytest.mark.parametrize(
    "ordering, element_index, undefined",
    [
        [["tasks:id"], 0, False],  # ordered by id ascending, first element api == first created
        [["tasks:-id"], -1, False],  # ordered by id descending, first element api == last created
        [["tasks:completed_at"], 0, False],
        [["tasks:-completed_at"], 0, False],  # only one task is labeled
        [["tasks:total_annotations"], -1, False],
        [["tasks:-total_annotations"], 0, False],
        [["tasks:total_predictions"], 0, False],
        [["tasks:-total_predictions"], -1, False],
        [["tasks:cancelled_annotations"], 0, False],
        [["tasks:-cancelled_annotations"], -1, False],
        [["tasks:annotations_results"], 0, False],
        [["tasks:-annotations_results"], -1, False],
        [["tasks:predictions_results"], 0, False],
        [["tasks:-predictions_results"], -1, False],
        [["tasks:predictions_score"], 0, False],
        [["tasks:-predictions_score"], -1, False],
        [["tasks:data.text"], 0, False],
        [["tasks:-data.text"], -1, False],
        [["tasks:data.data"], 0, True],
        [["-tasks:data.data"], 1, True],
        [["tasks:file_upload"], 0, False],
        [["-tasks:file_upload"], 1, False],
    ],
)
@pytest.mark.django_db
def test_views_ordering(ordering, element_index, undefined, business_client, project_id):

    payload = dict(
        project=project_id,
        data={"test": 1, "ordering": ordering},
    )
    response = business_client.post(
        "/api/dm/views/",
        data=json.dumps(payload),
        content_type="application/json",
    )

    assert response.status_code == 201, response.content
    view_id = response.json()["id"]

    project = Project.objects.get(pk=project_id)

    if undefined:
        task_field_name = settings.DATA_UNDEFINED_NAME
    else:
        task_field_name = 'text'

    file_upload1 = FileUpload.objects.create(user=project.created_by, project=project, file=ContentFile('', name='file_upload1'))

    task_id_1 = make_task({"data": {task_field_name: 1}, 'file_upload': file_upload1}, project).id
    make_annotation({"result": [{"1": True}]}, task_id_1)
    make_prediction({"result": [{"1": True}], "score": 1}, task_id_1)

    file_upload2 = FileUpload.objects.create(user=project.created_by, project=project, file=ContentFile('', name='file_upload2'))
    task_id_2 = make_task({"data": {task_field_name: 2}, 'file_upload': file_upload2}, project).id
    for _ in range(0, 2):
        make_annotation({"result": [{"2": True}], "was_cancelled": True}, task_id_2)
    for _ in range(0, 2):
        make_prediction({"result": [{"2": True}], "score": 2}, task_id_2)

    task_ids = [task_id_1, task_id_2]

    response = business_client.get(f"/api/tasks?view={view_id}")
    response_data = response.json()

    assert response_data["tasks"][0]["id"] == task_ids[element_index]


@pytest.mark.parametrize(
    "filters, ids",
    [
        [
            {
                "conjunction": "or",
                "items": [{"filter": "filter:tasks:id", "operator": "equal", "value": 1, "type": "Number"}],
            },
            [1],
        ],
        [
            {
                "conjunction": "or",
                "items": [
                    {"filter": "filter:tasks:id", "operator": "equal", "value": 1, "type": "Number"},
                    {"filter": "filter:tasks:id", "operator": "equal", "value": 2, "type": "Number"},
                ],
            },
            [1, 2],
        ],
        [
            {
                "conjunction": "or",
                "items": [
                    {"filter": "filter:tasks:id", "operator": "not_equal", "value": 1, "type": "Number"},
                    {"filter": "filter:tasks:id", "operator": "greater", "value": 3, "type": "Number"},
                ],
            },
            [2, 3, 4],
        ],
        [
            {
                "conjunction": "or",
                "items": [{"filter": "filter:tasks:id", "operator": "not_equal", "value": 1, "type": "Number"}],
            },
            [2, 3, 4],
        ],
        [
            {
                "conjunction": "or",
                "items": [{"filter": "filter:tasks:id", "operator": "less", "value": 3, "type": "Number"}],
            },
            [1, 2],
        ],
        [
            {
                "conjunction": "or",
                "items": [{"filter": "filter:tasks:id", "operator": "greater", "value": 2, "type": "Number"}],
            },
            [3, 4],
        ],
        [
            {
                "conjunction": "or",
                "items": [{"filter": "filter:tasks:id", "operator": "less_or_equal", "value": 3, "type": "Number"}],
            },
            [1, 2, 3],
        ],
        [
            {
                "conjunction": "or",
                "items": [{"filter": "filter:tasks:id", "operator": "greater_or_equal", "value": 2, "type": "Number"}],
            },
            [2, 3, 4],
        ],
        [
            {
                "conjunction": "or",
                "items": [
                    {"filter": "filter:tasks:id", "operator": "in", "value": {"min": 2, "max": 3}, "type": "Number"}
                ],
            },
            [2, 3],
        ],
        [
            {
                "conjunction": "or",
                "items": [
                    {
                        "filter": "filter:tasks:id",
                        "operator": "not_in",
                        "value": {"min": 2, "max": 3},
                        "type": "Number",
                    }
                ],
            },
            [1, 4],
        ],
        [
            {
                "conjunction": "or",
                "items": [
                    {
                        "filter": "filter:tasks:completed_at",
                        "operator": "less",
                        "type": "Datetime",
                        "value": now().strftime('%Y-%m-%dT%H:%M:%S.%fZ'),
                    }
                ],
            },
            [],
        ],
        [
            {
                "conjunction": "or",
                "items": [
                    {
                        "filter": "filter:tasks:completed_at",
                        "operator": "greater",
                        "type": "Datetime",
                        "value": now().strftime('%Y-%m-%dT%H:%M:%S.%fZ'),
                    }
                ],
            },
            [1],  # only first task is labeled, second one is skipped
        ],
        [
            {
                "conjunction": "or",
                "items": [
                    {
                        "filter": "filter:tasks:completed_at",
                        "operator": "empty",
                        "type": "Datetime",
                        "value": "True",
                    }
                ],
            },
            [2, 3, 4],
        ],
        [
            {
                "conjunction": "or",
                "items": [
                    {
                        "filter": "filter:tasks:completed_at",
                        "operator": "empty",
                        "type": "Datetime",
                        "value": "False",
                    }
                ],
            },
            [1],
        ],
        [
            {
                "conjunction": "or",
                "items": [
                    {
                        "filter": "filter:tasks:annotations_results",
                        "operator": "contains",
                        "type": "String",
                        "value": "first",
                    }
                ],
            },
            [1, ],
        ],
        [
            {
                "conjunction": "or",
                "items": [
                    {
                        "filter": "filter:tasks:data.data",
                        "operator": "contains",
                        "type": "String",
                        "value": "text1",
                    }
                ],
            },
            [1, ],
        ],
        [
            {
                "conjunction": "and",
                "items": [
                    {
                        "filter": "filter:tasks:data.data",  # undefined column test
                        "operator": "contains",
                        "type": "String",
                        "value": "text",
                    },
                    {"filter": "filter:tasks:id", "operator": "equal", "value": 1, "type": "Number"},
                ],
            },
            [1, ],
        ],
        [
            {
                "conjunction": "or",
                "items": [
                    {
                        "filter": "filter:tasks:annotations_results",
                        "operator": "not_contains",
                        "type": "String",
                        "value": "first",
                    }
                ],
            },
            [2, 3, 4],
        ],
        [
            {
                "conjunction": "and",
                "items": [
                    {"filter": "filter:tasks:annotators", "operator": "contains", "value": "$ANN1_ID", "type": "List"},
                    {"filter": "filter:tasks:annotators", "operator": "contains", "value": "$ANN2_ID", "type": "List"},
                ],
            },
            [2],
        ],
    ],
)
@pytest.mark.django_db
def test_views_filters(filters, ids, business_client, project_id):
    project = Project.objects.get(pk=project_id)
    ann1 = make_annotator({'email': 'ann1@testheartex.com'}, project)
    ann2 = make_annotator({'email': 'ann2@testheartex.com'}, project)

    ann_ids = {
        '$ANN1_ID': ann1.id,
        '$ANN2_ID': ann2.id,
    }
    for item in filters['items']:
        for ann_id_key, ann_id_value in ann_ids.items():
            if isinstance(item['value'], str) and ann_id_key in item['value']:
                item['value'] = ann_id_value

    payload = dict(
        project=project_id,
        data={"test": 1, "filters": filters},
    )
    response = business_client.post(
        "/api/dm/views/",
        data=json.dumps(payload),
        content_type="application/json",
    )

    assert response.status_code == 201, response.content
    view_id = response.json()["id"]

    task_data_field_name = settings.DATA_UNDEFINED_NAME

    task_id_1 = make_task({"data": {task_data_field_name: "some text1"}}, project).id
    make_annotation({"result": [{"from_name": "1_first", "to_name": "", "value": {}}], "completed_by": ann1}, task_id_1)
    make_prediction({"result": [{"from_name": "1_first", "to_name": "", "value": {}}], "score": 1}, task_id_1)

    task_id_2 = make_task({"data": {task_data_field_name: "some text2"}}, project).id
    for ann in (ann1, ann2):
        make_annotation({"result": [{"from_name": "2_second", "to_name": "", "value": {}}], "was_cancelled": True, "completed_by": ann}, task_id_2)
    for _ in range(0, 2):
        make_prediction({"result": [{"from_name": "2_second", "to_name": "", "value": {}}], "score": 2}, task_id_2)

    task_ids = [0, task_id_1, task_id_2]

    for _ in range(0, 2):
        task_id = make_task({"data": {task_data_field_name: "some text_"}}, project).id
        task_ids.append(task_id)

    for item in filters['items']:
        if item['type'] == 'Number':
            if isinstance(item['value'], dict):
                item['value']['min'] = task_ids[int(item['value']['min'])]
                item['value']['max'] = task_ids[int(item['value']['max'])]
            else:
                item['value'] = task_ids[int(item['value'])]

    updated_payload = dict(
        data={"filters": filters},
    )
    response = business_client.patch(
        f"/api/dm/views/{view_id}",
        data=json.dumps(payload),
        content_type="application/json",
    )

    response = business_client.get(f"/api/tasks/?view={view_id}")
    response_data = response.json()

    assert 'tasks' in response_data, response_data

    response_ids = [task["id"] for task in response_data["tasks"]]
    correct_ids = [task_ids[i] for i in ids]
    assert response_ids == correct_ids, (response_ids, correct_ids, filters)
