# (c) cavaliba.com - tests / views_importer - auto-detect CSV delimiter

"""
"Auto-detect" is the Delimiter selector's default. ImportForm resolves it while
validating, so an undetectable file comes back as an error on the field with the
form still filled in - never as an import of one wide column.
"""

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 app_data.forms import ImportForm
from app_data.models import DataTask
from tests import helper


@override_settings(CAVALIBA_AUTH_MODE="unittest", CELERY_TASK_ALWAYS_EAGER=True)
class ViewImporterAutoDelimiterTest(TestCase):
    def setUp(self):
        cache.clear()
        helper.add_admin_user(login="unittest")
        helper.add_schema(
            classname="autodel",
            field_definition={"mystring": {"dataformat": "string", "displayname": "MyString"}},
        )

    def _post(self, content, submit="import", filename="data.csv", extra=None):
        data = {
            "file": SimpleUploadedFile(filename, content.encode("utf-8"), content_type="text/csv"),
            "pipeline": "",
            "encoding": "utf-8",
            "separator": "",  # Auto-detect
            "split_multivalue": "on",
            "submit": submit,
        }
        if extra:
            data.update(extra)
        return self.client.post(reverse("app_data:data_import"), data)

    def _imported(self, keyname):
        return Instance.from_keyname(classname="autodel", keyname=keyname, expand=False)

    def test_auto_is_the_default_on_a_fresh_form(self):
        response = self.client.get(reverse("app_data:data_import"))

        self.assertEqual(ImportForm(pipelines=[], schemas=[])["separator"].value(), "")
        self.assertContains(response, "Auto-detect")

    def test_semicolon_file_imports_under_auto(self):
        response = self._post("classname;keyname;mystring\nautodel;row1;hello\n")

        self.assertEqual(response.status_code, 200)
        self.assertTrue(response.context["task_handle"])
        instance = self._imported("row1")
        self.assertIsNotNone(instance)
        self.assertEqual(instance.fields["mystring"].value, ["hello"])

    def test_pipe_file_imports_under_auto(self):
        self._post("classname|keyname|mystring\nautodel|row2|hello\n")

        self.assertIsNotNone(self._imported("row2"))

    def test_comma_file_imports_under_auto(self):
        self._post("classname,keyname,mystring\nautodel,row3,hello\n")

        self.assertIsNotNone(self._imported("row3"))

    def test_comma_inside_a_semicolon_file_is_not_mistaken_for_the_delimiter(self):
        """The whole point of the heuristic: a value holding a comma must not
        split the row."""

        self._post("classname;keyname;mystring\nautodel;row4;hello, world\n")

        instance = self._imported("row4")
        self.assertIsNotNone(instance)
        self.assertEqual(instance.fields["mystring"].value, ["hello, world"])

    def test_undetectable_file_is_refused_with_a_field_error(self):
        response = self._post("a,b\nc,d,e\nf\n")

        self.assertEqual(response.status_code, 200)
        self.assertTrue(response.context["form"].errors.get("separator"))
        self.assertIsNone(response.context["task_handle"])
        self.assertEqual(DataTask.objects.filter(name__startswith="Import").count(), 0)

    def test_undetectable_file_keeps_the_form_filled_in(self):
        """So the user only has to pick a delimiter and submit again."""

        response = self._post("a,b\nc,d,e\nf\n", extra={"pipeline": ""})

        self.assertEqual(response.context["form"]["encoding"].value(), "utf-8")
        self.assertEqual(response.context["form"]["split_multivalue"].value(), True)

    def test_an_explicit_delimiter_is_never_second_guessed(self):
        """A ,-file read with an explicit ";" stays one wide column - the user
        asked for it, and that is how they find out the file is not what they
        thought."""

        response = self._post(
            "classname,keyname,mystring\nautodel,row5,hello\n", extra={"separator": ";"}
        )

        self.assertFalse(response.context["form"].errors)
        self.assertIsNone(self._imported("row5"))

    def test_check_names_the_detected_delimiter(self):
        response = self._post("classname;keyname;mystring\nautodel;row6;hello\n", submit="verify")

        rendered = [str(m) for m in response.context["messages"]]
        self.assertTrue(any("1 rows" in m for m in rendered))
        self.assertTrue(any("delimiter detected: ;" in m for m in rendered))

    def test_yaml_upload_is_not_blocked_by_auto_detect(self):
        """The delimiter is a CSV-only option: an undetectable one must not
        stop a YAML or JSON import."""

        content = "- classname: autodel\n  keyname: row7\n  mystring: hello\n"
        response = self._post(content, filename="data.yaml")

        self.assertFalse(response.context["form"].errors)
        self.assertIsNotNone(self._imported("row7"))

    def test_single_column_file_imports_under_auto(self):
        """Nothing to separate, so no delimiter is wrong - this must not error."""

        response = self._post("keyname\nrow8\n", extra={"force_schema": "autodel"})

        self.assertFalse(response.context["form"].errors)
        self.assertIsNotNone(self._imported("row8"))
