# (c) cavaliba.com - tests / data / exporter field catalog

from django.test import TestCase, override_settings

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

ENUM_CONTENT = (
    '- value: "A"\n'
    '  widget: "green_circle"\n'
    "  enumstring: string AAA\n"
    '- value: "B"\n'
    '  widget: "yellow_circle"\n'
)


class ExporterCatalogTest(TestCase):
    def setUp(self):
        cache.clear()
        helper.add_admin_user(login="unittest")

        helper.add_instance(
            classname="_enumerate",
            keyname="cat_enum",
            fields={"content": ENUM_CONTENT},
        )

        helper.add_schema(
            classname="catref",
            field_definition={
                "refstring": {"dataformat": "string", "displayname": "RefString"},
                "refint": {"dataformat": "int", "displayname": "RefInt"},
            },
        )
        helper.add_instance(
            classname="catref",
            keyname="catref-01",
            fields={"refstring": "ref value", "refint": 7},
        )

        helper.add_schema(
            classname="catmain",
            field_definition={
                "mystring": {"dataformat": "string", "displayname": "MyString", "order": 1},
                "myref": {
                    "dataformat": "schema",
                    "displayname": "MyRef",
                    "dataformat_ext": "catref refstring refint",
                    "order": 2,
                },
                "myenum": {
                    "dataformat": "enumerate",
                    "displayname": "MyEnum",
                    "dataformat_ext": "cat_enum",
                    "order": 3,
                },
            },
        )
        helper.add_instance(
            classname="catmain",
            keyname="catmain-01",
            fields={"mystring": "hello", "myref": "catref-01", "myenum": "A"},
        )

        helper.add_schema(
            classname="catempty",
            field_definition={
                "mystring": {"dataformat": "string", "displayname": "MyString"},
            },
        )

    @override_settings(CAVALIBA_AUTH_MODE="unittest")
    def test_builtin_bucket_is_always_present(self):
        catalog = export_field_catalog("catmain")

        self.assertEqual(catalog["builtin"], list(EXPORT_BUILTIN_FIELDS))

    @override_settings(CAVALIBA_AUTH_MODE="unittest")
    def test_declared_schema_fields_listed_in_order(self):
        catalog = export_field_catalog("catmain")

        self.assertEqual(catalog["schema"], ["mystring", "myref", "myenum"])

    @override_settings(CAVALIBA_AUTH_MODE="unittest")
    def test_schema_reference_subfields_bucketed_as_injected(self):
        catalog = export_field_catalog("catmain")

        self.assertIn("myref__refstring", catalog["injected"])
        self.assertIn("myref__refint", catalog["injected"])

    @override_settings(CAVALIBA_AUTH_MODE="unittest")
    def test_enumerate_subfields_not_collected_at_all(self):
        # they vary per row, so they are never a selectable column - a YAML/JSON
        # export picks them up from their parent instead
        catalog = export_field_catalog("catmain")

        self.assertNotIn("enumerate", catalog)
        self.assertNotIn("myenum__widget", catalog["injected"])
        self.assertNotIn("myenum__widget", catalog["external"])

    @override_settings(CAVALIBA_AUTH_MODE="unittest")
    def test_unknown_schema_returns_empty_buckets(self):
        catalog = export_field_catalog("nosuchschema")

        self.assertEqual(catalog["schema"], [])
        self.assertEqual(catalog["injected"], [])
        self.assertEqual(catalog["external"], [])

    @override_settings(CAVALIBA_AUTH_MODE="unittest")
    def test_schema_without_instances_lists_declared_fields_only(self):
        # a resolved external only exists on a loaded instance, so with no sample
        # row the catalog can only report what the schema declares or derives
        catalog = export_field_catalog("catempty")

        self.assertEqual(catalog["schema"], ["mystring"])
        self.assertEqual(catalog["injected"], [])
        self.assertEqual(catalog["external"], [])

    @override_settings(CAVALIBA_AUTH_MODE="unittest")
    def test_injected_subfields_listed_without_any_sample_row(self):
        # derived from the schema, not from a row: a sample row whose reference is
        # empty (here: no row at all) must not hide the subfields, which would make
        # them unselectable in the Exporter's column selector
        spec = ExportSpec(schema="catmain", query="mystring:nothingmatches")
        catalog = export_field_catalog("catmain", spec=spec)

        self.assertEqual(catalog["schema"], ["mystring", "myref", "myenum"])
        self.assertEqual(catalog["injected"], ["myref__refstring", "myref__refint"])

    @override_settings(CAVALIBA_AUTH_MODE="unittest")
    def test_sample_row_does_not_duplicate_a_derived_injected_name(self):
        catalog = export_field_catalog("catmain")

        self.assertEqual(catalog["injected"].count("myref__refstring"), 1)
