# (c) cavaliba.com - tests / data / export folder download page

import hashlib
import os

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

import app_home.cache as cache
from tests import helper

FILENAME = "unittest-download.txt"
CONTENT = "This is a test export file\n"


@override_settings(CAVALIBA_AUTH_MODE="unittest")
class ViewDownloadFolderTest(TestCase):
    def setUp(self):
        cache.clear()
        helper.add_admin_user(login="unittest")

        self.folder = str(settings.CAVALIBA_EXPORT_FOLDER)
        os.makedirs(self.folder, exist_ok=True)
        self.filepath = os.path.join(self.folder, FILENAME)
        with open(self.filepath, "w") as f:
            f.write(CONTENT)
        self.md5 = hashlib.md5(FILENAME.encode()).hexdigest()

    def tearDown(self):
        if os.path.isfile(self.filepath):
            os.remove(self.filepath)

    def test_page_lists_the_folder(self):
        response = self.client.get(reverse("app_data:data_download"))

        self.assertEqual(response.status_code, 200)
        self.assertContains(response, FILENAME)

    def test_preview_shows_the_content(self):
        response = self.client.get(reverse("app_data:data_download"), {"view": self.md5})

        self.assertEqual(response.status_code, 200)
        self.assertContains(response, "This is a test export file")
        self.assertEqual(response.context["file_name"], FILENAME)

    def test_download_streams_the_file(self):
        response = self.client.get(reverse("app_data:data_download"), {"dl": self.md5})

        self.assertEqual(response.status_code, 200)
        self.assertIn("attachment;", response["Content-Disposition"])
        self.assertIn(FILENAME, response["Content-Disposition"])
        self.assertEqual(b"".join(response.streaming_content).decode(), CONTENT)

    def test_unknown_md5_reports_not_found(self):
        response = self.client.get(reverse("app_data:data_download"), {"dl": "deadbeef"})

        self.assertEqual(response.status_code, 200)
        self.assertContains(response, "not found")

    def test_traversal_name_is_refused(self):
        # callers match an md5 against the listing first, so this only exercises
        # the defense-in-depth guard inside exporter.send_file()
        from app_data.exporter import get_file_content, send_file

        self.assertIsNone(send_file("../../manage.py"))
        self.assertIsNone(get_file_content("../../manage.py"))

    def test_dotfile_is_refused(self):
        from app_data.exporter import get_file_content

        dotpath = os.path.join(self.folder, ".hidden")
        with open(dotpath, "w") as f:
            f.write("secret\n")
        try:
            self.assertIsNone(get_file_content(".hidden"))
        finally:
            os.remove(dotpath)


@override_settings(CAVALIBA_AUTH_MODE="unittest")
class ViewDownloadFolderPermissionTest(TestCase):
    def setUp(self):
        cache.clear()

    def test_without_p_data_export_viewer_redirected(self):
        helper.add_user_with_perm(login="unittest", perms=["p_data_export"])

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

        self.assertEqual(response.status_code, 302)

    def test_with_p_data_export_viewer_allowed(self):
        helper.add_user_with_perm(login="unittest", perms=["p_data_export_viewer"])

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

        self.assertEqual(response.status_code, 200)
