# (c) cavaliba.com - tests / data / exporter spec parsing

from django.http import QueryDict
from django.test import TestCase, override_settings

import app_home.cache as cache
from app_data.exporter import ExportSpec, spec_from_post
from tests import helper


def _post(**kwargs):
    qd = QueryDict(mutable=True)
    base = {"schema": "expspec", "format": "csv"}
    base.update(kwargs)
    for key, value in base.items():
        if value is not None:
            qd[key] = value
    return qd


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

    @override_settings(CAVALIBA_AUTH_MODE="unittest")
    def test_minimal_post_defaults(self):
        spec, err = spec_from_post(_post())

        self.assertIsNone(err)
        self.assertEqual(spec.schema, "expspec")
        self.assertEqual(spec.format, "csv")
        self.assertEqual(spec.columns, "*")
        self.assertEqual(spec.query, "")
        self.assertIsNone(spec.refs)
        self.assertIsNone(spec.rev)
        self.assertIsNone(spec.action)

    @override_settings(CAVALIBA_AUTH_MODE="unittest")
    def test_a_retired_option_in_the_post_is_ignored(self):
        # an old bookmarked form, or a caller still sending the retired options
        spec, err = spec_from_post(
            _post(with_schema_column="0", with_injected="0", with_enumerate_subfields="0")
        )

        self.assertIsNone(err)
        self.assertEqual(spec.schema, "expspec")

    @override_settings(CAVALIBA_AUTH_MODE="unittest")
    def test_missing_schema_rejected(self):
        spec, err = spec_from_post(_post(schema=""))

        self.assertIsNone(spec)
        self.assertTrue(err)

    @override_settings(CAVALIBA_AUTH_MODE="unittest")
    def test_bad_schema_characters_rejected(self):
        spec, err = spec_from_post(_post(schema="exp;drop"))

        self.assertIsNone(spec)
        self.assertTrue(err)

    @override_settings(CAVALIBA_AUTH_MODE="unittest")
    def test_bad_format_rejected(self):
        spec, err = spec_from_post(_post(format="xlsx"))

        self.assertIsNone(spec)
        self.assertTrue(err)

    @override_settings(CAVALIBA_AUTH_MODE="unittest")
    def test_bad_query_characters_rejected(self):
        spec, err = spec_from_post(_post(query="mystring:a;b"))

        self.assertIsNone(spec)
        self.assertTrue(err)

    @override_settings(CAVALIBA_AUTH_MODE="unittest")
    def test_bad_column_characters_rejected(self):
        spec, err = spec_from_post(_post(columns="a,b;c"))

        self.assertIsNone(spec)
        self.assertTrue(err)

    @override_settings(CAVALIBA_AUTH_MODE="unittest")
    def test_multichar_delimiter_rejected_for_csv(self):
        spec, err = spec_from_post(_post(delimiter=";;"))

        self.assertIsNone(spec)
        self.assertTrue(err)

    @override_settings(CAVALIBA_AUTH_MODE="unittest")
    def test_multichar_delimiter_ignored_for_yaml(self):
        spec, err = spec_from_post(_post(format="yaml", delimiter=";;"))

        self.assertIsNone(err)
        self.assertEqual(spec.format, "yaml")

    @override_settings(CAVALIBA_AUTH_MODE="unittest")
    def test_unknown_encoding_rejected(self):
        spec, err = spec_from_post(_post(encoding="rot13"))

        self.assertIsNone(spec)
        self.assertTrue(err)

    @override_settings(CAVALIBA_AUTH_MODE="unittest")
    def test_unknown_action_rejected(self):
        spec, err = spec_from_post(_post(action="explode"))

        self.assertIsNone(spec)
        self.assertTrue(err)

    @override_settings(CAVALIBA_AUTH_MODE="unittest")
    def test_known_action_accepted(self):
        spec, err = spec_from_post(_post(action="noop"))

        self.assertIsNone(err)
        self.assertEqual(spec.action, "noop")

    @override_settings(CAVALIBA_AUTH_MODE="unittest")
    def test_non_numeric_rev_rejected(self):
        spec, err = spec_from_post(_post(rev="many"))

        self.assertIsNone(spec)
        self.assertTrue(err)

    @override_settings(CAVALIBA_AUTH_MODE="unittest")
    def test_zero_rev_rejected(self):
        spec, err = spec_from_post(_post(rev="0"))

        self.assertIsNone(spec)
        self.assertTrue(err)

    @override_settings(CAVALIBA_AUTH_MODE="unittest")
    def test_refs_split_on_comma(self):
        spec, err = spec_from_post(_post(refs=" user , site "))

        self.assertIsNone(err)
        self.assertEqual(spec.refs, ["user", "site"])

    @override_settings(CAVALIBA_AUTH_MODE="unittest")
    def test_roundtrip_through_dict(self):
        spec, _err = spec_from_post(_post(columns="keyname,mystring", action="noop", rev="3"))
        rebuilt = ExportSpec.from_dict(spec.to_dict())

        self.assertEqual(rebuilt, spec)

    @override_settings(CAVALIBA_AUTH_MODE="unittest")
    def test_from_dict_ignores_a_retired_option(self):
        # a DataTask queued by a previous release still has to run after the upgrade
        stored = {
            "schema": "expspec",
            "with_schema_column": False,
            "with_injected": False,
            "with_enumerate_subfields": True,
        }

        spec = ExportSpec.from_dict(stored)

        self.assertEqual(spec.schema, "expspec")
        self.assertEqual(spec.columns, "*")
