# (c) cavaliba.com - tests / tasks UI - download link for a finished export's result

import shutil
import tempfile

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

import app_home.cache as cache
from app_data.exporter import ExportSpec
from app_data.loader import load_broker
from app_data.models import DataTask
from app_data.task_manager import create_datatask
from app_data.tasks import task_export
from app_user.models import SirenePermission
from tests import helper

AAA = {"username": "unittest", "perms": ["p_data_admin"]}
BASE_PERMS = ["p_data_export", "p_data_access", "p_data_read", "p_task_view"]


@override_settings(CAVALIBA_AUTH_MODE="unittest")
class ViewsTaskAttachmentLinkTest(TestCase):
    def _isolate_filestore(self):
        """Point the filestore at a throwaway directory for this test."""

        rootdir = tempfile.mkdtemp(prefix="cavaliba_test_filestore_")
        override = override_settings(CAVALIBA_FILESTORE=rootdir)
        override.enable()
        self.addCleanup(override.disable)
        self.addCleanup(shutil.rmtree, rootdir, ignore_errors=True)
        return rootdir

    def setUp(self):
        self._isolate_filestore()
        cache.clear()
        helper.add_user_with_perm(login="unittest", perms=BASE_PERMS)
        helper.add_schema(
            classname="vlink",
            field_definition={
                "mystring": {"dataformat": "string", "displayname": "MyString"},
            },
        )
        helper.add_instance(classname="vlink", keyname="vlink-01", fields={"mystring": "one"})

        self.params = {"spec": ExportSpec(schema="vlink", format="csv").to_dict(), "aaa": AAA}
        self.task = create_datatask(
            name="Export csv - vlink", params=self.params, owner_type="user", owner_id="unittest"
        )
        task_export(str(self.task.handle), self.params)
        self.task.refresh_from_db()

    def _set_perms(self, perms):
        for perm_name in perms:
            SirenePermission.objects.get_or_create(keyname=perm_name)
        load_broker(
            datalist=[
                {
                    "classname": "role",
                    "_action": "update",
                    "keyname": "role_unittest",
                    "permissions": perms,
                }
            ],
            aaa={"perms": ["p_role_update"]},
        )
        cache.clear()

    def _detail(self):
        return self.client.get(reverse("app_data:task_detail", args=[self.task.handle]))

    # ---------------------------------------------------------------
    # detail page
    # ---------------------------------------------------------------

    def test_detail_offers_a_download_link(self):
        # this is the path once the progress modal has been hidden:
        # navbar Tasks -> the task -> this link
        response = self._detail()

        expected = reverse("app_data:data_exporter_result", args=[self.task.handle])
        self.assertEqual(response.context["attachment_url"], expected)
        self.assertContains(response, expected)
        self.assertContains(response, self.task.attachment["filename"])

    def test_detail_link_actually_downloads(self):
        response = self.client.get(response_url := self._detail().context["attachment_url"])

        self.assertEqual(response.status_code, 200)
        self.assertIn("attachment;", response["Content-Disposition"])
        self.assertIn("vlink-01", b"".join(response.streaming_content).decode())
        self.assertTrue(response_url)

    def test_detail_falls_back_to_raw_json_without_p_data_export(self):
        self._set_perms(["p_data_access", "p_data_read", "p_task_view"])

        response = self._detail()

        self.assertIsNone(response.context["attachment_url"])
        self.assertContains(response, "Attachment")
        self.assertNotContains(
            response, reverse("app_data:data_exporter_result", args=[self.task.handle])
        )

    def test_no_link_while_the_task_is_not_done(self):
        DataTask.objects.filter(handle=self.task.handle).update(state="RUNNING")

        response = self._detail()

        self.assertIsNone(response.context["attachment_url"])

    def test_no_link_for_a_task_without_a_file_attachment(self):
        DataTask.objects.filter(handle=self.task.handle).update(attachment={"note": "no file"})

        response = self._detail()

        self.assertIsNone(response.context["attachment_url"])

    def test_no_link_for_a_non_dict_attachment(self):
        DataTask.objects.filter(handle=self.task.handle).update(attachment=["not", "a", "dict"])

        response = self._detail()

        self.assertIsNone(response.context["attachment_url"])

    # ---------------------------------------------------------------
    # list page
    # ---------------------------------------------------------------

    def test_list_offers_a_download_link_per_row(self):
        response = self.client.get(reverse("app_data:task_list"))

        expected = reverse("app_data:data_exporter_result", args=[self.task.handle])
        self.assertEqual(response.context["tasks"][0].attachment_url, expected)
        self.assertContains(response, expected)

    def test_list_has_no_link_for_a_running_task(self):
        DataTask.objects.filter(handle=self.task.handle).update(state="RUNNING")

        response = self.client.get(reverse("app_data:task_list"))

        self.assertIsNone(response.context["tasks"][0].attachment_url)
