# (c) cavaliba.com - tests / data / exporter view - async task path

from django.test import TestCase, override_settings
from django.urls import reverse

import app_home.cache as cache
from app_data.models import DataFile, DataTask
from tests import helper


@override_settings(CAVALIBA_AUTH_MODE="unittest", CELERY_TASK_ALWAYS_EAGER=True)
class ViewExporterAsyncTest(TestCase):
    def setUp(self):
        helper.isolate_filestore(self)
        cache.clear()
        helper.add_admin_user(login="unittest")
        helper.add_schema(
            classname="vasync",
            field_definition={
                "mystring": {"dataformat": "string", "displayname": "MyString"},
            },
        )
        for i in range(1, 6):
            helper.add_instance(
                classname="vasync",
                keyname=f"vasync-{i:02d}",
                fields={"mystring": f"row {i}"},
            )

    def _post(self, **extra):
        data = {"schema": "vasync", "format": "csv", "columns": "*"}
        data.update(extra)
        return self.client.post(reverse("app_data:data_exporter"), data)

    def test_export_creates_a_task(self):
        response = self._post()

        self.assertEqual(response.status_code, 200)
        self.assertEqual(DataTask.objects.count(), 1)
        task = DataTask.objects.first()
        self.assertEqual(response.context["task_handle"], str(task.handle))

    def test_task_is_owned_by_the_requester(self):
        self._post()

        task = DataTask.objects.first()
        self.assertEqual(task.owner_type, "user")
        self.assertEqual(task.owner_id, "unittest")
        self.assertIn("vasync", task.name)

    def test_task_completes_and_attaches_a_file(self):
        self._post()

        task = DataTask.objects.first()
        self.assertEqual(task.state, "DONE")
        self.assertEqual(task.attachment["type"], "file")
        self.assertTrue(task.attachment["fileid"])
        self.assertTrue(task.attachment["filename"].endswith(".csv"))
        self.assertGreater(task.attachment["size"], 0)

    def test_attached_file_has_an_expiry(self):
        self._post()

        task = DataTask.objects.first()
        datafile = DataFile.objects.get(fileid=task.attachment["fileid"])
        self.assertIsNotNone(datafile.not_after)
        self.assertTrue(datafile.hash)

    def test_task_output_carries_the_stats(self):
        self._post()

        output = DataTask.objects.first().output
        self.assertEqual(output["total"], 5)
        self.assertEqual(output["count_ok"], 5)
        self.assertEqual(output["count_ko"], 0)
        self.assertFalse(output["aborted"])

    def test_result_file_holds_the_whole_export(self):
        self._post()

        task = DataTask.objects.first()
        datafile = DataFile.objects.get(fileid=task.attachment["fileid"])
        with open(datafile.filepath, encoding="utf-8") as f:
            lines = f.read().splitlines()

        self.assertEqual(len(lines), 6)
        self.assertTrue(lines[0].startswith("_schema,keyname"))

    def test_a_single_row_export_is_a_task_too(self):
        # no threshold any more: nothing runs in the request
        response = self._post(query="mystring:row 1")

        self.assertEqual(DataTask.objects.count(), 1)
        self.assertNotIn("Content-Disposition", response)
        self.assertEqual(DataTask.objects.first().output["total"], 1)

    def test_async_export_honours_the_options(self):
        self._post(columns="keyname,mystring", action="noop", format="json")

        task = DataTask.objects.first()
        self.assertEqual(task.params["spec"]["columns"], "keyname,mystring")
        self.assertEqual(task.params["spec"]["action"], "noop")
        self.assertEqual(task.params["spec"]["format"], "json")
        self.assertTrue(task.attachment["filename"].endswith(".json"))
