# (c) cavaliba.com - tests / views_importer - CSV mode

from django.core.files.uploadedfile import SimpleUploadedFile
from django.test import TestCase, override_settings
from django.urls import reverse

import app_home.cache as cache
from app_data.data import Instance
from tests import helper


class ViewImportCsvTest(TestCase):
    def setUp(self):
        cache.clear()
        helper.add_admin_user(login="unittest")
        helper.add_schema(
            classname="csvtest",
            field_definition={
                "mystring": {"dataformat": "string", "displayname": "MyString"},
            },
        )

    def _post_csv(self, content, submit, extra=None, follow=False):
        data = {
            "file": SimpleUploadedFile(
                "data.csv", content.encode("utf-8"), content_type="text/csv"
            ),
            "force_schema": "csvtest",
            "pipeline": "",
            "encoding": "utf-8",
            "separator": ",",
            "split_multivalue": "on",
            "submit": submit,
        }
        if extra:
            data.update(extra)
        return self.client.post(reverse("app_data:data_import"), data, follow=follow)

    @override_settings(CAVALIBA_AUTH_MODE="unittest")
    def test_verify_reports_row_count(self):
        """ "verify" only reports the parsed row count - load_file_csv() never rejects
        a row itself (missing classname/keyname only fail once "import" reaches
        load_broker()), so there's nothing else to check at this stage."""

        response = self._post_csv("keyname,mystring\nrow1,hello\n", "verify")
        self.assertEqual(response.status_code, 200)
        rendered = [str(m) for m in response.context["messages"]]
        self.assertTrue(any("1 rows" in m for m in rendered))

    @override_settings(CAVALIBA_AUTH_MODE="unittest")
    def test_import_creates_instance(self):
        response = self._post_csv("keyname,mystring\nrow1,hello\n", "import")
        self.assertEqual(response.status_code, 302)
        instance = Instance.from_keyname(classname="csvtest", keyname="row1", expand=False)
        self.assertIsNotNone(instance)

    @override_settings(CAVALIBA_AUTH_MODE="unittest")
    def test_import_ok_ko_message(self):
        response = self._post_csv(
            "keyname,mystring\nrow1,hello\nrow2,world\n", "import", follow=True
        )
        rendered = [str(m) for m in response.context["messages"]]
        self.assertTrue(any("Import OK" in m and "(2)" in m for m in rendered))

    @override_settings(CAVALIBA_AUTH_MODE="unittest", CAVALIBA_MAX_IMPORT_ERROR=2)
    def test_import_aborts_past_failure_threshold(self):
        """Every row targets a non-existent schema, so load_broker fails on each one;
        once failures exceed CAVALIBA_MAX_IMPORT_ERROR, the loop stops early.

        The form's "force_schema" field must be left empty here: it's forced onto
        every row unconditionally (same "always wins" semantics as --schema on
        the CLI/API), so a non-empty value here would override each row's own
        "doesnotexist" and defeat the test."""

        rows = "\n".join(f"row{i},doesnotexist" for i in range(1, 8))
        content = "keyname,schema\n" + rows + "\n"
        response = self._post_csv(content, "import", extra={"force_schema": ""}, follow=True)

        rendered = [str(m) for m in response.context["messages"]]
        self.assertTrue(any("aborted" in m.lower() for m in rendered))

    @override_settings(CAVALIBA_AUTH_MODE="unittest", CAVALIBA_MAX_IMPORT_ERROR=100)
    def test_error_subset_capped_at_20(self):
        """load_file_csv() never rejects a row - only load_broker() does (here: every
        row has no "schema" column/value, so each is rejected for missing classname).
        _report_csv_import() caps the displayed error list at 20 even though every
        one of the 29 rows fails. The failure threshold is raised so all rows are
        attempted rather than aborting early."""

        rows = "\n".join(f"row{i},hello" for i in range(1, 30))
        content = "keyname,mystring\n" + rows + "\n"
        response = self._post_csv(content, "import", extra={"force_schema": ""}, follow=True)
        rendered = [str(m) for m in response.context["messages"]]
        error_lines = [m for m in rendered if "missing classname" in m]
        self.assertEqual(len(error_lines), 20)
